#ifndef _ESEXTCGPUSHADER5PRECISEQUALIFIER_HPP #define _ESEXTCGPUSHADER5PRECISEQUALIFIER_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 esextcGPUShader5PreciseQualifier.hpp * \brief GPUShader5 Precise Float Test (Test Group 6) */ /*-------------------------------------------------------------------*/ #include "../esextcTestCaseBase.hpp" namespace glcts { /** Implementation of "Test 6" from CTS_EXT_gpu_shader5. Description follows: * * Test whether the qualifier 'precise' prevents implementations from * performing optimizations that produce slightly different results * than unoptimized code. The optimizations may lead to cracks in position * calculations during tessellation. * * Category: API, * Functional Test. * * The test simulates computing a position of a vertex inside a patch * using weighted sum of the patch vertices. To ensure that we have * crack-free position calculation during tessellation, we should get * with using 'precise' a bitwise accurate result regardless of the order * in which the patch edges are traversed. * * Create a vertex shader. Declare two input variables * * in vec4 positions; * in vec4 weights; * * and one output variable * * out vec4 weightedSum; * * Declare functions: * * void eval(in vec4 p, in vec4 w, precise out float result) * { * result = (p.x*w.x + p.y*w.y) + (p.z*w.z + p.w*w.w); * } * * float eval(in vec4 p, in vec4 w) * { * precise float result = (p.x*w.x + p.y*w.y) + (p.z*w.z + p.w*w.w); * return result; * } * * In the vertex shader main function compute: * * eval(positions, weights, weightedSum.x); * * weightedSum.y = eval(positions, weights); * * float result = 0; * precise result; * result = (positions.x* weights.x + positions.y* weights.y) + * (positions.z* weights.z + positions.w* weights.w); * weightedSum.z = result; * * weightedSum.w = (positions.x* weights.x + positions.y* weights.y) + * (positions.z* weights.z + positions.w* weights.w); * * Create a boilerplate fragment shader. * * Create a program from the above vertex shader and fragment shader * and use it. * * Configure transform feedback to capture the value of weightedSum. * * Configure two buffer objects as data sources for the positions * and weights attributes. * * The buffer object being a data source for the positions attribute * should be filled 4 random float values p1,p2,p3,p4 from range * [-100.0,100.0] generated using a consistent seed. * * The buffer object being a data source for the weights attribute * should be filled with 4 random float values w1,w2,w3,w4 from range [0,1] * generated using a consistent seed satisfying condition * (w1 + w2 + w3 + w4) == 1.0 * * Execute a draw call glDrawArrays(GL_POINTS, 0, 1); * * Copy the captured results from the buffer object bound to transform * feedback binding point to float weightedSumForward[4] array. * * Reverse the contents of the buffers that are fed into the shader. * * Execute a draw call glDrawArrays(GL_POINTS, 0, 1); * * Copy the captured results from the buffer object bound to transform * feedback binding point to float weightedSumBackward[4] array. * * The test is successful if values of * * weightedSumForward[0], weightedSumForward[1], weightedSumForward[2], * weightedSumBackward[0], weightedSumBackward[1], weightedSumBackward[2] * * are all bitwise accurate. * * On the other hand weightedSumForward[3] and weightedSumBackward[3] * are not necessary bitwise accurate with any of the above values or even * compared to each other. If precise is not used, it is likely that * compiler optimizations will result in MAD or fma operations that * are not exactly commutative and thus will not provide bitwise * accurate results. * * The test should be run in a loop at least 100 times, each time generating * different values for positions and weights. */ union WeightedSum { float floatv; unsigned int intv; }; class GPUShader5PreciseQualifier : public TestCaseBase { public: /* Public variables */ GPUShader5PreciseQualifier(Context& context, const ExtParameters& extParams, const char* name, const char* description); virtual ~GPUShader5PreciseQualifier() { } virtual void deinit(void); virtual IterateResult iterate(void); private: /* Private variables */ static const char* m_fragment_shader_code; static const char* m_vertex_shader_code; static const glw::GLuint m_n_components; static const glw::GLuint m_n_iterations; static const glw::GLint m_position_range; glw::GLuint m_fragment_shader_id; glw::GLuint m_program_id; glw::GLuint m_tf_buffer_id; glw::GLuint m_vao_id; glw::GLuint m_vertex_shader_id; glw::GLuint m_vertex_positions_buffer_id; glw::GLuint m_vertex_weights_buffer_id; /* Private functions */ void drawAndGetFeedbackResult(const glw::GLfloat* vertex_data_positions, const glw::GLfloat* vertex_data_weights, WeightedSum* feedback_result); void initTest(void); }; } // namespace glcts #endif // _ESEXTCGPUSHADER5PRECISEQUALIFIER_HPP