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 {
139     float floatv;
140     unsigned int intv;
141 };
142 
143 class GPUShader5PreciseQualifier : public TestCaseBase
144 {
145 public:
146     /* Public variables */
147     GPUShader5PreciseQualifier(Context &context, const ExtParameters &extParams, const char *name,
148                                const char *description);
149 
~GPUShader5PreciseQualifier()150     virtual ~GPUShader5PreciseQualifier()
151     {
152     }
153 
154     virtual void deinit(void);
155     virtual IterateResult iterate(void);
156 
157 private:
158     /* Private variables */
159     static const char *m_fragment_shader_code;
160     static const char *m_vertex_shader_code;
161     static const glw::GLuint m_n_components;
162     static const glw::GLuint m_n_iterations;
163     static const glw::GLint m_position_range;
164 
165     glw::GLuint m_fragment_shader_id;
166     glw::GLuint m_program_id;
167     glw::GLuint m_tf_buffer_id;
168     glw::GLuint m_vao_id;
169     glw::GLuint m_vertex_shader_id;
170     glw::GLuint m_vertex_positions_buffer_id;
171     glw::GLuint m_vertex_weights_buffer_id;
172 
173     /* Private functions */
174     void drawAndGetFeedbackResult(const glw::GLfloat *vertex_data_positions, const glw::GLfloat *vertex_data_weights,
175                                   WeightedSum *feedback_result);
176     void initTest(void);
177 };
178 
179 } // namespace glcts
180 
181 #endif // _ESEXTCGPUSHADER5PRECISEQUALIFIER_HPP
182