fuchsia / third_party / vulkan-cts / a8c8a8df7a6b04c70caed1beff6307dfec871386 / . / external / openglcts / modules / glesext / gpu_shader5 / esextcGPUShader5FmaAccuracy.hpp

#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 |