• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _ESEXTCGPUSHADER5FMAACCURACY_HPP
2 #define _ESEXTCGPUSHADER5FMAACCURACY_HPP
3 /*-------------------------------------------------------------------------
4  * OpenGL Conformance Test Suite
5  * -----------------------------
6  *
7  * Copyright (c) 2014-2016 The Khronos Group Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */ /*!
22  * \file
23  * \brief
24  */ /*-------------------------------------------------------------------*/
25 
26 /*!
27  * \file esextcGPUShader5FmaAccuracy.hpp
28  * \brief gpu_shader5 extenstion - fma accuracy test (Test 7)
29  */ /*-------------------------------------------------------------------*/
30 
31 #include "../esextcTestCaseBase.hpp"
32 
33 namespace glcts
34 {
35 /**  Implementation of "Test 7" from CTS_EXT_gpu_shader5. Test description follows:
36  *
37  *    Check the accuracy of the function fma() in comparison to a*b + c.
38  *    The fma() should be at least as accurate as a*b+c.
39  *
40  *    Category:   API,
41  *                Functional Test.
42  *
43  *    Write two vertex shaders that using Euler method compute the approximate
44  *    value of y(1) for a differential equation y'(t) = y(t) with
45  *    border case y(0) = 1. First shader should use the fma function and
46  *    the second one standard "a*b + c" expression in each iteration of
47  *    the Euler method. Both shaders should store the result in
48  *    out float Result variable.
49  *
50  *    Explanation:
51  *
52  *    For a differential equation y'(t) = y(t) with edge case y(0) = 1
53  *    the exact solution is y(t) = et . It means that for y(0) we get 1
54  *    and for y(1) we get e ~ 2.71828.
55  *
56  *    Sometimes we can't solve differential equation for exact solution
57  *    (get the actual y function), but we can still get an approximate value of
58  *    y(t) for a chosen t, by solving the equation numerically. The simplest
59  *    numerical method that can be applied to the problem is called Euler method.
60  *
61  *    This method start from the border case y(0) = 1 (t0 = 0, y0 = 1) and
62  *    in n sub steps converges slowly to the value of y(1) (tn = 1, yn = ?).
63  *    It does that by computing in a loop the equation
64  *    y(tx+1) = y(tx) + 1/n * y(tx) for x = 0..n-1.
65  *    After the last iteration the value of y(tn) is the approximate value of
66  *    y(1) and should be close to e ~ 2.71828. The Euler method not always
67  *    converges to the solution but for the differential equation y'(t) = y(t)
68  *    it should converge without any problems.
69  *
70  *    The equation y(tx+1) = y(tx) + 1/n * y(tx) is ideal to be implemented
71  *    using fma function in the following way:
72  *
73  *    y(tx+1) = fma(1/n, y(tx), y(tx)).
74  *
75  *    The shaders should be configurable by a uint uniform variable n
76  *    in the number of subintervals the interval [0,1] is divided into
77  *    while computing the value of y(1).
78  *
79  *    Write a boilerplate fragment shader.
80  *
81  *    Create a program from the first vertex shader and fragment shader and
82  *    a second program from the second vertex shader and fragment shader.
83  *
84  *    Use the first program.
85  *
86  *    Configure transform feedback to capture the value of Result.
87  *
88  *    Execute a draw call glDrawArrays(GL_POINTS, 0, 1) five times in a row.
89  *    Before each execution, double the value of n (n  should first be
90  *    set to 10).
91  *
92  *    Copy the captured results from the buffer object bound to transform
93  *    feedback binding point to resultsFmaArray.
94  *
95  *    Use the second program.
96  *
97  *    Configure transform feedback to capture the value of Result.
98  *
99  *    Execute a draw call glDrawArrays(GL_POINTS, 0, 1) 10 times in a row.
100  *    Before each execution double the value of n (n should first be set
101  *    to 10).
102  *
103  *    Copy the captured results from the buffer object bound to transform
104  *    feedback to resultsNotFmaArray.
105  *
106  *    For each of the values stored in the array resultsFmaArray compute
107  *    a relative error of the value with correspondence to a reference value
108  *    of y(1) which is e ~ 2.71828. Sum up those relative errors to a variable
109  *    precise float totalRelativeErrorFma.
110  *
111  *    Do the same for the array resultsNotFmaArray, this time storing the sum
112  *    in precise float totalRelativeErrorNotFma.
113  *
114  *    The test passes if the absolute value of the totalRelativeErrorFma
115  *    is smaller or equal to totalRelativeErrorNotFma.
116  **/
117 class GPUShader5FmaAccuracyTest : public TestCaseBase
118 {
119 public:
120 	/* Public methods */
121 	GPUShader5FmaAccuracyTest(Context& context, const ExtParameters& extParams, const char* name,
122 							  const char* description);
123 
~GPUShader5FmaAccuracyTest(void)124 	virtual ~GPUShader5FmaAccuracyTest(void)
125 	{
126 	}
127 
128 	virtual void		  deinit(void);
129 	virtual IterateResult iterate(void);
130 
131 private:
132 	/* Private methods */
133 	void calculateRelativeError(glw::GLfloat result, glw::GLfloat expected_result, glw::GLfloat& relative_error);
134 	void executePass(glw::GLuint program_object_id, glw::GLfloat* results);
135 	glw::GLuint getNumberOfStepsForIndex(glw::GLuint index);
136 	void initTest(void);
137 	void logArray(const char* description, glw::GLfloat* data, glw::GLuint length);
138 
139 	/* Private variables */
140 	/* Program and shader ids */
141 	glw::GLuint m_fragment_shader_id;
142 	glw::GLuint m_program_object_id_for_float_pass;
143 	glw::GLuint m_program_object_id_for_fma_pass;
144 	glw::GLuint m_vertex_shader_id_for_float_pass;
145 	glw::GLuint m_vertex_shader_id_for_fma_pass;
146 
147 	/* Buffer object used for transform feedback */
148 	glw::GLuint m_buffer_object_id;
149 
150 	/* Vertex array object */
151 	glw::GLuint m_vertex_array_object_id;
152 
153 	/* Size of buffer used for transform feedback */
154 	static const glw::GLuint m_buffer_size;
155 
156 	/* Expected solution */
157 	static const glw::GLfloat m_expected_result;
158 
159 	/* Number of draw call executions */
160 	static const glw::GLuint m_n_draw_call_executions;
161 
162 	/* Shaders' code */
163 	static const glw::GLchar* const m_fragment_shader_code;
164 	static const glw::GLchar* const m_vertex_shader_code_for_fma_pass;
165 	static const glw::GLchar* const m_vertex_shader_code_for_float_pass;
166 };
167 
168 } /* glcts */
169 
170 #endif // _ESEXTCGPUSHADER5FMAACCURACY_HPP
171