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