blob: ac5a4f37c14c5ceaf0e0b9c0ab5edea9f09d4bba [file] [log] [blame]
#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