1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2014-2016 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ /*! 20 * \file 21 * \brief 22 */ /*-------------------------------------------------------------------*/ 23 24#include "esextcGPUShader5PreciseQualifier.hpp" 25#include "gluContextInfo.hpp" 26#include "gluDefs.hpp" 27#include "glwEnums.hpp" 28#include "glwFunctions.hpp" 29#include "tcuTestLog.hpp" 30#include <assert.h> 31#include <cstdlib> 32#include <cstring> 33#include <ctime> 34 35namespace glcts 36{ 37/* Fragment Shader code */ 38const char* GPUShader5PreciseQualifier::m_fragment_shader_code = "${VERSION}\n" 39 "\n" 40 "${GPU_SHADER5_REQUIRE}\n" 41 "\n" 42 "precision highp float;\n" 43 "\n" 44 "out vec4 color;\n" 45 "\n" 46 "void main()\n" 47 "{\n" 48 " color = vec4(1, 1, 1, 1);\n" 49 "}\n"; 50 51/* Vertex Shader code */ 52const char* GPUShader5PreciseQualifier::m_vertex_shader_code = 53 "${VERSION}\n" 54 "\n" 55 "${GPU_SHADER5_REQUIRE}\n" 56 "\n" 57 "precision highp float;\n" 58 "\n" 59 "layout(location = 0) in vec4 positions;\n" 60 "layout(location = 1) in vec4 weights;\n" 61 "out vec4 weightedSum;\n" 62 "\n" 63 "void eval(in vec4 p, in vec4 w, precise out float result)\n" 64 "{\n" 65 " result = (p.x*w.x + p.y*w.y) + (p.z*w.z + p.w*w.w);\n" 66 "}\n" 67 "\n" 68 "float eval(in vec4 p, in vec4 w)\n" 69 "{\n" 70 " precise float result = (p.x*w.x + p.y*w.y) + (p.z*w.z + p.w*w.w);\n" 71 "\n" 72 " return result;\n" 73 "}\n" 74 "void main()\n" 75 "{\n" 76 " eval(positions, weights, weightedSum.x);\n" 77 "\n" 78 " weightedSum.y = eval(positions, weights);\n" 79 "\n" 80 " precise float result = 0.0f;\n" 81 "\n" 82 " result = (positions.x * weights.x + positions.y * weights.y) +\n" 83 " (positions.z * weights.z + positions.w * weights.w);\n" 84 " weightedSum.z = result;\n" 85 " weightedSum.w = (positions.x * weights.x + positions.y * weights.y) + \n" 86 " (positions.z * weights.z + positions.w * weights.w);\n" 87 "}\n"; 88 89const glw::GLuint GPUShader5PreciseQualifier::m_n_components = 4; 90const glw::GLuint GPUShader5PreciseQualifier::m_n_iterations = 100; 91const glw::GLint GPUShader5PreciseQualifier::m_position_range = 1000; 92 93/** Constructor 94 * 95 * @param context Test context 96 * @param name Test case's name 97 * @param description Test case's description 98 **/ 99GPUShader5PreciseQualifier::GPUShader5PreciseQualifier(Context& context, const ExtParameters& extParams, 100 const char* name, const char* description) 101 : TestCaseBase(context, extParams, name, description) 102 , m_fragment_shader_id(0) 103 , m_program_id(0) 104 , m_tf_buffer_id(0) 105 , m_vao_id(0) 106 , m_vertex_shader_id(0) 107 , m_vertex_positions_buffer_id(0) 108 , m_vertex_weights_buffer_id(0) 109{ 110 /* Nothing to be done here */ 111} 112 113/** Initializes GLES objects used during the test. 114 * 115 */ 116void GPUShader5PreciseQualifier::initTest(void) 117{ 118 /* Check if gpu_shader5 extension is supported */ 119 if (!m_is_gpu_shader5_supported) 120 { 121 throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); 122 } 123 124 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 125 126 /* Create program object */ 127 m_program_id = gl.createProgram(); 128 129 /* Setup transform feedback varyings */ 130 const char* feedback_varyings[] = { "weightedSum" }; 131 132 gl.transformFeedbackVaryings(m_program_id, 1, feedback_varyings, GL_INTERLEAVED_ATTRIBS); 133 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set transform feedback varyings!"); 134 135 /* Create shaders */ 136 m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER); 137 m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER); 138 139 /* Build program */ 140 if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_vertex_shader_id, 1, 141 &m_vertex_shader_code)) 142 { 143 TCU_FAIL("Program could not have been created sucessfully from a valid vertex/geometry/fragment shader!"); 144 } 145 146 /* Generate & bind a VAO */ 147 gl.genVertexArrays(1, &m_vao_id); 148 gl.bindVertexArray(m_vao_id); 149 150 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a vertex array object!"); 151 152 /* Create transform feedback buffer object */ 153 gl.genBuffers(1, &m_tf_buffer_id); 154 gl.bindBuffer(GL_ARRAY_BUFFER, m_tf_buffer_id); 155 gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * m_n_components, DE_NULL, GL_STATIC_COPY); 156 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 157 158 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create buffer object!"); 159 160 /* Bind buffer object to transform feedback binding point */ 161 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_tf_buffer_id); 162 163 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object to transform feedback binding point!"); 164 165 /* Create positions buffer object */ 166 gl.genBuffers(1, &m_vertex_positions_buffer_id); 167 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_positions_buffer_id); 168 gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * m_n_components, DE_NULL, GL_STATIC_DRAW); 169 170 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create buffer object!"); 171 172 /* Create weights buffer object */ 173 gl.genBuffers(1, &m_vertex_weights_buffer_id); 174 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_weights_buffer_id); 175 gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * m_n_components, DE_NULL, GL_STATIC_DRAW); 176 177 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create buffer object!"); 178 179 gl.useProgram(m_program_id); 180 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use a program object!"); 181 182 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_positions_buffer_id); 183 gl.vertexAttribPointer(0 /* index */, 4 /* size */, GL_FLOAT, GL_FALSE, 0, 0); 184 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure vertex attribute array for positions attribute!"); 185 186 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_weights_buffer_id); 187 gl.vertexAttribPointer(1 /* index */, 4 /* size */, GL_FLOAT, GL_FALSE, 0, 0); 188 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure vertex attribute array for weights attribute!"); 189 190 gl.enableVertexAttribArray(0 /* index */); 191 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array for index 0!"); 192 gl.enableVertexAttribArray(1 /* index */); 193 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array for index 1!"); 194} 195 196/** Deinitializes GLES objects created during the test. 197 * 198 */ 199void GPUShader5PreciseQualifier::deinit(void) 200{ 201 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 202 203 /* Reset OpenGL ES state */ 204 gl.disableVertexAttribArray(0); 205 gl.disableVertexAttribArray(1); 206 gl.useProgram(0); 207 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 208 gl.bindVertexArray(0); 209 210 /* Delete program object and shaders */ 211 if (m_program_id != 0) 212 { 213 gl.deleteProgram(m_program_id); 214 215 m_program_id = 0; 216 } 217 218 if (m_vertex_shader_id != 0) 219 { 220 gl.deleteShader(m_vertex_shader_id); 221 222 m_vertex_shader_id = 0; 223 } 224 225 if (m_fragment_shader_id != 0) 226 { 227 gl.deleteShader(m_fragment_shader_id); 228 229 m_fragment_shader_id = 0; 230 } 231 232 /* Delete buffer objects */ 233 if (m_tf_buffer_id != 0) 234 { 235 gl.deleteBuffers(1, &m_tf_buffer_id); 236 237 m_tf_buffer_id = 0; 238 } 239 240 if (m_vertex_positions_buffer_id != 0) 241 { 242 gl.deleteBuffers(1, &m_vertex_positions_buffer_id); 243 244 m_vertex_positions_buffer_id = 0; 245 } 246 247 if (m_vertex_weights_buffer_id != 0) 248 { 249 gl.deleteBuffers(1, &m_vertex_weights_buffer_id); 250 251 m_vertex_weights_buffer_id = 0; 252 } 253 254 /* Delete vertex array object */ 255 if (m_vao_id != 0) 256 { 257 gl.deleteVertexArrays(1, &m_vao_id); 258 259 m_vao_id = 0; 260 } 261 262 /* Call base class' deinit() */ 263 TestCaseBase::deinit(); 264} 265 266/** Executes the test. 267 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. 268 * 269 * Note the function throws exception should an error occur! 270 * 271 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. 272 * 273 **/ 274tcu::TestNode::IterateResult GPUShader5PreciseQualifier::iterate(void) 275{ 276 initTest(); 277 278 /* Set the seed for the random generator */ 279 randomSeed(1); 280 281 glw::GLboolean test_failed = false; 282 283 for (glw::GLuint test_iter = 0; test_iter < m_n_iterations; ++test_iter) 284 { 285 /* Create the data for positions and weights attributes */ 286 glw::GLfloat vertex_data_positions[m_n_components]; 287 glw::GLfloat vertex_data_weights[m_n_components]; 288 glw::GLfloat weights_sum = 1.0f; 289 290 for (glw::GLuint component_nr = 0; component_nr < m_n_components; ++component_nr) 291 { 292 vertex_data_positions[component_nr] = static_cast<glw::GLfloat>( 293 static_cast<glw::GLint>(randomFormula(2 * m_position_range)) - m_position_range); 294 295 if (component_nr != (m_n_components - 1)) 296 { 297 glw::GLfloat random_value = static_cast<glw::GLfloat>(randomFormula(m_position_range)) / 298 static_cast<glw::GLfloat>(m_position_range); 299 300 vertex_data_weights[component_nr] = random_value; 301 weights_sum -= random_value; 302 } 303 else 304 { 305 vertex_data_weights[component_nr] = weights_sum; 306 } 307 } 308 309 /* Compute forward weighted sum */ 310 WeightedSum weighted_sum_forward[m_n_components]; 311 312 drawAndGetFeedbackResult(vertex_data_positions, vertex_data_weights, weighted_sum_forward); 313 314 /* Reverse the data for positions and weights attributes */ 315 glw::GLfloat temp_value = 0.0f; 316 317 for (glw::GLuint component_nr = 0; component_nr < (m_n_components / 2); ++component_nr) 318 { 319 temp_value = vertex_data_positions[component_nr]; 320 321 vertex_data_positions[component_nr] = vertex_data_positions[m_n_components - 1 - component_nr]; 322 vertex_data_positions[m_n_components - 1 - component_nr] = temp_value; 323 324 temp_value = vertex_data_weights[component_nr]; 325 326 vertex_data_weights[component_nr] = vertex_data_weights[m_n_components - 1 - component_nr]; 327 vertex_data_weights[m_n_components - 1 - component_nr] = temp_value; 328 } 329 330 /* Compute backward weighted sum */ 331 WeightedSum weighted_sum_backward[m_n_components]; 332 333 drawAndGetFeedbackResult(vertex_data_positions, vertex_data_weights, weighted_sum_backward); 334 335 /* Check if results are bitwise accurate */ 336 if (weighted_sum_backward[0].intv != weighted_sum_backward[1].intv || 337 weighted_sum_backward[0].intv != weighted_sum_backward[2].intv || 338 weighted_sum_backward[0].intv != weighted_sum_forward[0].intv || 339 weighted_sum_backward[0].intv != weighted_sum_forward[1].intv || 340 weighted_sum_backward[0].intv != weighted_sum_forward[2].intv) 341 { 342 test_failed = true; 343 break; 344 } 345 } 346 347 if (test_failed) 348 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 349 else 350 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 351 352 return STOP; 353} 354 355/** Draw and get feedback result 356 * 357 * @param vertex_data_positions data for positions attribute 358 * @param vertex_data_weights data for weights attribute 359 * @param feedback_result space to store result fetched via transform feedback 360 **/ 361void GPUShader5PreciseQualifier::drawAndGetFeedbackResult(const glw::GLfloat* vertex_data_positions, 362 const glw::GLfloat* vertex_data_weights, 363 WeightedSum* feedback_result) 364{ 365 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 366 367 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_positions_buffer_id); 368 gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * m_n_components, vertex_data_positions, GL_STATIC_DRAW); 369 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set buffer object's data!"); 370 371 gl.bindBuffer(GL_ARRAY_BUFFER, m_vertex_weights_buffer_id); 372 gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLfloat) * m_n_components, vertex_data_weights, GL_STATIC_DRAW); 373 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set buffer object's data!"); 374 375 gl.enable(GL_RASTERIZER_DISCARD); 376 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed"); 377 378 gl.beginTransformFeedback(GL_POINTS); 379 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) failed"); 380 381 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); 382 GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering Failed!"); 383 384 gl.endTransformFeedback(); 385 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed"); 386 387 /* Fetch the results via transform feedback */ 388 WeightedSum* result = (WeightedSum*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 389 sizeof(glw::GLfloat) * m_n_components, GL_MAP_READ_BIT); 390 391 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed"); 392 393 memcpy(feedback_result, result, sizeof(glw::GLfloat) * m_n_components); 394 395 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 396 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed"); 397 398 gl.disable(GL_RASTERIZER_DISCARD); 399 GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed"); 400} 401 402} // namespace glcts 403