• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _ESEXTCGPUSHADER5PRECISEQUALIFIER_HPP
2 #define _ESEXTCGPUSHADER5PRECISEQUALIFIER_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 esextcGPUShader5PreciseQualifier.hpp
28  * \brief GPUShader5 Precise Float Test (Test Group 6)
29  */ /*-------------------------------------------------------------------*/
30 
31 #include "../esextcTestCaseBase.hpp"
32 
33 namespace glcts
34 {
35 /**  Implementation of "Test 6" from CTS_EXT_gpu_shader5. Description follows:
36  *
37  *    Test whether the qualifier 'precise' prevents implementations from
38  *    performing optimizations that produce slightly different results
39  *    than unoptimized code. The optimizations may lead to cracks in position
40  *    calculations during tessellation.
41  *
42  *            Category:   API,
43  *                        Functional Test.
44  *
45  *    The test simulates computing a position of a vertex inside a patch
46  *    using weighted sum of the patch vertices. To ensure that we have
47  *    crack-free position calculation during tessellation, we should get
48  *    with using 'precise' a bitwise accurate result regardless of the order
49  *    in which the patch edges are traversed.
50  *
51  *    Create a vertex shader. Declare two input variables
52  *
53  *    in vec4 positions;
54  *    in vec4 weights;
55  *
56  *    and one output variable
57  *
58  *    out vec4 weightedSum;
59  *
60  *    Declare functions:
61  *
62  *    void eval(in vec4 p, in vec4 w, precise out float result)
63  *    {
64  *         result = (p.x*w.x + p.y*w.y) + (p.z*w.z + p.w*w.w);
65  *    }
66  *
67  *    float eval(in vec4 p, in vec4 w)
68  *    {
69  *         precise float result = (p.x*w.x + p.y*w.y) + (p.z*w.z + p.w*w.w);
70  *         return result;
71  *    }
72  *
73  *    In the vertex shader main function compute:
74  *
75  *    eval(positions, weights, weightedSum.x);
76  *
77  *    weightedSum.y = eval(positions, weights);
78  *
79  *    float result = 0;
80  *    precise result;
81  *    result =    (positions.x* weights.x + positions.y* weights.y) +
82  *                (positions.z* weights.z + positions.w* weights.w);
83  *    weightedSum.z = result;
84  *
85  *    weightedSum.w = (positions.x* weights.x + positions.y* weights.y) +
86  *                    (positions.z* weights.z + positions.w* weights.w);
87  *
88  *    Create a boilerplate fragment shader.
89  *
90  *    Create a program from the above vertex shader and fragment shader
91  *    and use it.
92  *
93  *    Configure transform feedback to capture the value of weightedSum.
94  *
95  *    Configure two buffer objects as data sources for the positions
96  *    and weights attributes.
97  *
98  *    The buffer object being a data source for the positions attribute
99  *    should be filled 4 random float values p1,p2,p3,p4 from range
100  *    [-100.0,100.0] generated using a consistent seed.
101  *
102  *    The buffer object being a data source for the weights attribute
103  *    should be filled with 4 random float values w1,w2,w3,w4 from range [0,1]
104  *    generated using a consistent seed satisfying condition
105  *    (w1 + w2 + w3 + w4) == 1.0
106  *
107  *    Execute a draw call glDrawArrays(GL_POINTS, 0, 1);
108  *
109  *    Copy the captured results from the buffer object bound to transform
110  *    feedback binding point to float weightedSumForward[4] array.
111  *
112  *    Reverse the contents of the buffers that are fed into the shader.
113  *
114  *    Execute a draw call glDrawArrays(GL_POINTS, 0, 1);
115  *
116  *    Copy the captured results from the buffer object bound to transform
117  *    feedback binding point to float weightedSumBackward[4] array.
118  *
119  *    The test is successful if values of
120  *
121  *    weightedSumForward[0], weightedSumForward[1], weightedSumForward[2],
122  *    weightedSumBackward[0], weightedSumBackward[1], weightedSumBackward[2]
123  *
124  *    are all bitwise accurate.
125  *
126  *    On the other hand weightedSumForward[3] and weightedSumBackward[3]
127  *    are not necessary bitwise accurate with any of the above values or even
128  *    compared to each other. If precise is not used, it is likely that
129  *    compiler optimizations will result in MAD or fma operations that
130  *    are not exactly commutative and thus will not provide bitwise
131  *    accurate results.
132  *
133  *    The test should be run in a loop at least 100 times, each time generating
134  *    different values for positions and weights.
135  */
136 
137 union WeightedSum {
138 	float		 floatv;
139 	unsigned int intv;
140 };
141 
142 class GPUShader5PreciseQualifier : public TestCaseBase
143 {
144 public:
145 	/* Public variables */
146 	GPUShader5PreciseQualifier(Context& context, const ExtParameters& extParams, const char* name,
147 							   const char* description);
148 
~GPUShader5PreciseQualifier()149 	virtual ~GPUShader5PreciseQualifier()
150 	{
151 	}
152 
153 	virtual void		  deinit(void);
154 	virtual IterateResult iterate(void);
155 
156 private:
157 	/* Private variables */
158 	static const char*		 m_fragment_shader_code;
159 	static const char*		 m_vertex_shader_code;
160 	static const glw::GLuint m_n_components;
161 	static const glw::GLuint m_n_iterations;
162 	static const glw::GLint  m_position_range;
163 
164 	glw::GLuint m_fragment_shader_id;
165 	glw::GLuint m_program_id;
166 	glw::GLuint m_tf_buffer_id;
167 	glw::GLuint m_vao_id;
168 	glw::GLuint m_vertex_shader_id;
169 	glw::GLuint m_vertex_positions_buffer_id;
170 	glw::GLuint m_vertex_weights_buffer_id;
171 
172 	/* Private functions */
173 	void drawAndGetFeedbackResult(const glw::GLfloat* vertex_data_positions, const glw::GLfloat* vertex_data_weights,
174 								  WeightedSum* feedback_result);
175 	void initTest(void);
176 };
177 
178 } // namespace glcts
179 
180 #endif // _ESEXTCGPUSHADER5PRECISEQUALIFIER_HPP
181