| #ifndef _ESEXTCGPUSHADER5FMAACCURACY_HPP |
| #define _ESEXTCGPUSHADER5FMAACCURACY_HPP |
| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2014-2016 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ /*! |
| * \file |
| * \brief |
| */ /*-------------------------------------------------------------------*/ |
| |
| /*! |
| * \file esextcGPUShader5FmaAccuracy.hpp |
| * \brief gpu_shader5 extenstion - fma accuracy test (Test 7) |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "../esextcTestCaseBase.hpp" |
| |
| namespace glcts |
| { |
| /** Implementation of "Test 7" from CTS_EXT_gpu_shader5. Test description follows: |
| * |
| * Check the accuracy of the function fma() in comparison to a*b + c. |
| * The fma() should be at least as accurate as a*b+c. |
| * |
| * Category: API, |
| * Functional Test. |
| * |
| * Write two vertex shaders that using Euler method compute the approximate |
| * value of y(1) for a differential equation y'(t) = y(t) with |
| * border case y(0) = 1. First shader should use the fma function and |
| * the second one standard "a*b + c" expression in each iteration of |
| * the Euler method. Both shaders should store the result in |
| * out float Result variable. |
| * |
| * Explanation: |
| * |
| * For a differential equation y'(t) = y(t) with edge case y(0) = 1 |
| * the exact solution is y(t) = et . It means that for y(0) we get 1 |
| * and for y(1) we get e ~ 2.71828. |
| * |
| * Sometimes we can't solve differential equation for exact solution |
| * (get the actual y function), but we can still get an approximate value of |
| * y(t) for a chosen t, by solving the equation numerically. The simplest |
| * numerical method that can be applied to the problem is called Euler method. |
| * |
| * This method start from the border case y(0) = 1 (t0 = 0, y0 = 1) and |
| * in n sub steps converges slowly to the value of y(1) (tn = 1, yn = ?). |
| * It does that by computing in a loop the equation |
| * y(tx+1) = y(tx) + 1/n * y(tx) for x = 0..n-1. |
| * After the last iteration the value of y(tn) is the approximate value of |
| * y(1) and should be close to e ~ 2.71828. The Euler method not always |
| * converges to the solution but for the differential equation y'(t) = y(t) |
| * it should converge without any problems. |
| * |
| * The equation y(tx+1) = y(tx) + 1/n * y(tx) is ideal to be implemented |
| * using fma function in the following way: |
| * |
| * y(tx+1) = fma(1/n, y(tx), y(tx)). |
| * |
| * The shaders should be configurable by a uint uniform variable n |
| * in the number of subintervals the interval [0,1] is divided into |
| * while computing the value of y(1). |
| * |
| * Write a boilerplate fragment shader. |
| * |
| * Create a program from the first vertex shader and fragment shader and |
| * a second program from the second vertex shader and fragment shader. |
| * |
| * Use the first program. |
| * |
| * Configure transform feedback to capture the value of Result. |
| * |
| * Execute a draw call glDrawArrays(GL_POINTS, 0, 1) five times in a row. |
| * Before each execution, double the value of n (n should first be |
| * set to 10). |
| * |
| * Copy the captured results from the buffer object bound to transform |
| * feedback binding point to resultsFmaArray. |
| * |
| * Use the second program. |
| * |
| * Configure transform feedback to capture the value of Result. |
| * |
| * Execute a draw call glDrawArrays(GL_POINTS, 0, 1) 10 times in a row. |
| * Before each execution double the value of n (n should first be set |
| * to 10). |
| * |
| * Copy the captured results from the buffer object bound to transform |
| * feedback to resultsNotFmaArray. |
| * |
| * For each of the values stored in the array resultsFmaArray compute |
| * a relative error of the value with correspondence to a reference value |
| * of y(1) which is e ~ 2.71828. Sum up those relative errors to a variable |
| * precise float totalRelativeErrorFma. |
| * |
| * Do the same for the array resultsNotFmaArray, this time storing the sum |
| * in precise float totalRelativeErrorNotFma. |
| * |
| * The test passes if the absolute value of the totalRelativeErrorFma |
| * is smaller or equal to totalRelativeErrorNotFma. |
| **/ |
| class GPUShader5FmaAccuracyTest : public TestCaseBase |
| { |
| public: |
| /* Public methods */ |
| GPUShader5FmaAccuracyTest(Context& context, const ExtParameters& extParams, const char* name, |
| const char* description); |
| |
| virtual ~GPUShader5FmaAccuracyTest(void) |
| { |
| } |
| |
| virtual void deinit(void); |
| virtual IterateResult iterate(void); |
| |
| private: |
| /* Private methods */ |
| void calculateRelativeError(glw::GLfloat result, glw::GLfloat expected_result, glw::GLfloat& relative_error); |
| void executePass(glw::GLuint program_object_id, glw::GLfloat* results); |
| glw::GLuint getNumberOfStepsForIndex(glw::GLuint index); |
| void initTest(void); |
| void logArray(const char* description, glw::GLfloat* data, glw::GLuint length); |
| |
| /* Private variables */ |
| /* Program and shader ids */ |
| glw::GLuint m_fragment_shader_id; |
| glw::GLuint m_program_object_id_for_float_pass; |
| glw::GLuint m_program_object_id_for_fma_pass; |
| glw::GLuint m_vertex_shader_id_for_float_pass; |
| glw::GLuint m_vertex_shader_id_for_fma_pass; |
| |
| /* Buffer object used for transform feedback */ |
| glw::GLuint m_buffer_object_id; |
| |
| /* Vertex array object */ |
| glw::GLuint m_vertex_array_object_id; |
| |
| /* Size of buffer used for transform feedback */ |
| static const glw::GLuint m_buffer_size; |
| |
| /* Expected solution */ |
| static const glw::GLfloat m_expected_result; |
| |
| /* Number of draw call executions */ |
| static const glw::GLuint m_n_draw_call_executions; |
| |
| /* Shaders' code */ |
| static const glw::GLchar* const m_fragment_shader_code; |
| static const glw::GLchar* const m_vertex_shader_code_for_fma_pass; |
| static const glw::GLchar* const m_vertex_shader_code_for_float_pass; |
| }; |
| |
| } /* glcts */ |
| |
| #endif // _ESEXTCGPUSHADER5FMAACCURACY_HPP |