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 "esextcTessellationShaderProgramInterfaces.hpp" 25#include "gluContextInfo.hpp" 26#include "gluDefs.hpp" 27#include "glwEnums.hpp" 28#include "glwFunctions.hpp" 29#include "tcuTestLog.hpp" 30 31namespace glcts 32{ 33/** Constructor 34 * 35 * @param context Test context 36 * @param name Test case's name 37 * @param description Test case's desricption 38 **/ 39TessellationShaderProgramInterfaces::TessellationShaderProgramInterfaces(Context& context, 40 const ExtParameters& extParams) 41 : TestCaseBase(context, extParams, "ext_program_interface_query_dependency", 42 "Verifies EXT_program_interface_query works correctly for tessellation" 43 " control and tessellation evaluation shaders") 44 , m_fs_shader_id(0) 45 , m_po_id(0) 46 , m_tc_shader_id(0) 47 , m_te_shader_id(0) 48 , m_vs_shader_id(0) 49 , m_is_atomic_counters_supported(false) 50 , m_is_shader_storage_blocks_supported(false) 51{ 52 /* Left blank on purpose */ 53} 54 55/** Deinitializes all ES objects created for the test. */ 56void TessellationShaderProgramInterfaces::deinit() 57{ 58 /** Call base class' deinit() function */ 59 TestCaseBase::deinit(); 60 61 /* Release all objects we might've created */ 62 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 63 64 if (m_fs_shader_id != 0) 65 { 66 gl.deleteShader(m_fs_shader_id); 67 68 m_fs_shader_id = 0; 69 } 70 71 if (m_po_id != 0) 72 { 73 gl.deleteProgram(m_po_id); 74 75 m_po_id = 0; 76 } 77 78 if (m_tc_shader_id != 0) 79 { 80 gl.deleteShader(m_tc_shader_id); 81 82 m_tc_shader_id = 0; 83 } 84 85 if (m_te_shader_id != 0) 86 { 87 gl.deleteShader(m_te_shader_id); 88 89 m_te_shader_id = 0; 90 } 91 92 if (m_vs_shader_id != 0) 93 { 94 gl.deleteShader(m_vs_shader_id); 95 96 m_vs_shader_id = 0; 97 } 98} 99 100/** Initializes all ES objects that will be used for the test. */ 101void TessellationShaderProgramInterfaces::initTest() 102{ 103 /* The test requires EXT_tessellation_shader and EXT_program_interfaces_query extensions */ 104 if (!m_is_tessellation_shader_supported || !m_is_program_interface_query_supported) 105 { 106 return; 107 } 108 109 /* Generate a program object we will later configure */ 110 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 111 112 m_po_id = gl.createProgram(); 113 114 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed"); 115 116 /* Generate shader objects the test will use */ 117 m_fs_shader_id = gl.createShader(GL_FRAGMENT_SHADER); 118 m_tc_shader_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER); 119 m_te_shader_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER); 120 m_vs_shader_id = gl.createShader(GL_VERTEX_SHADER); 121 122 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed"); 123 124 glw::GLint gl_max_tess_control_shader_storage_blocks; 125 glw::GLint gl_max_tess_control_atomic_counter_buffers; 126 glw::GLint gl_max_tess_control_atomic_counters; 127 glw::GLint gl_max_tess_evaluation_shader_storage_blocks; 128 glw::GLint gl_max_tess_evaluation_atomic_counter_buffers; 129 glw::GLint gl_max_tess_evaluation_atomic_counters; 130 131 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, &gl_max_tess_control_atomic_counter_buffers); 132 GLU_EXPECT_NO_ERROR(gl.getError(), 133 "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT pname"); 134 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_ATOMIC_COUNTERS, &gl_max_tess_control_atomic_counters); 135 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT pname"); 136 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &gl_max_tess_control_shader_storage_blocks); 137 GLU_EXPECT_NO_ERROR(gl.getError(), 138 "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT pname"); 139 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, 140 &gl_max_tess_evaluation_atomic_counter_buffers); 141 GLU_EXPECT_NO_ERROR(gl.getError(), 142 "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT pname"); 143 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &gl_max_tess_evaluation_atomic_counters); 144 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT pname"); 145 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, 146 &gl_max_tess_evaluation_shader_storage_blocks); 147 GLU_EXPECT_NO_ERROR(gl.getError(), 148 "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT pname"); 149 150 m_is_atomic_counters_supported = 151 (gl_max_tess_control_atomic_counter_buffers > 1) && (gl_max_tess_evaluation_atomic_counter_buffers > 1) && 152 (gl_max_tess_control_atomic_counters > 0) && (gl_max_tess_evaluation_atomic_counters > 0); 153 154 m_is_shader_storage_blocks_supported = 155 (gl_max_tess_control_shader_storage_blocks > 0) && (gl_max_tess_evaluation_shader_storage_blocks > 0); 156 157 const char* atomic_counters_header = NULL; 158 if (m_is_atomic_counters_supported) 159 { 160 atomic_counters_header = "#define USE_ATOMIC_COUNTERS 1\n"; 161 } 162 else 163 { 164 atomic_counters_header = "\n"; 165 } 166 167 const char* shader_storage_blocks_header = NULL; 168 if (m_is_shader_storage_blocks_supported) 169 { 170 shader_storage_blocks_header = "#define USE_SHADER_STORAGE_BLOCKS\n"; 171 } 172 else 173 { 174 shader_storage_blocks_header = "\n"; 175 } 176 177 /* Build shader program */ 178 const char* fs_body = "${VERSION}\n" 179 "\n" 180 "precision highp float;\n" 181 "\n" 182 "out vec4 test_output;\n" 183 "\n" 184 "void main()\n" 185 "{\n" 186 " test_output = vec4(1, 0, 0, 0);\n" 187 "}\n"; 188 189 const char* tc_body = "\n" 190 "layout (vertices = 1) out;\n" 191 "\n" 192 /* Uniforms */ 193 "uniform vec2 tc_uniform1;\n" 194 "uniform mat4 tc_uniform2;\n" 195 "\n" 196 /* Uniform blocks */ 197 "uniform tc_uniform_block1\n" 198 "{\n" 199 " float tc_uniform_block1_1;\n" 200 "};\n" 201 /* Atomic counter buffers */ 202 "#ifdef USE_ATOMIC_COUNTERS\n" 203 "layout(binding = 1, offset = 0) uniform atomic_uint tc_atomic_counter1;\n" 204 "#endif\n" 205 /* Shader storage blocks & buffer variables */ 206 "#ifdef USE_SHADER_STORAGE_BLOCKS\n" 207 "layout(std140, binding = 0) buffer tc_shader_storage_block1\n" 208 "{\n" 209 " vec4 tc_shader_storage_buffer_object_1[];\n" 210 "};\n" 211 "#endif\n" 212 /* Body */ 213 "void main()\n" 214 "{\n" 215 " int test = 1;\n" 216 "\n" 217 /* Uniforms */ 218 " if (tc_uniform1.x == 0.0) test = 2;\n" 219 " if (tc_uniform2[0].y == 1.0) test = 3;\n" 220 /* Uniform blocks */ 221 " if (tc_uniform_block1_1 == 3.0) test = 4;\n" 222 /* Atomic counter buffers */ 223 "#ifdef USE_ATOMIC_COUNTERS\n" 224 " if (atomicCounter(tc_atomic_counter1) == 1u) test = 5;\n" 225 "#endif\n" 226 /* Shader storage blocks & buffer variables */ 227 "#ifdef USE_SHADER_STORAGE_BLOCKS\n" 228 " if (tc_shader_storage_buffer_object_1[0].x == 0.0) test = 6;\n" 229 "#endif\n" 230 "\n" 231 " gl_out [gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 232 " gl_TessLevelOuter[0] = 2.0 * float(test);\n" 233 " gl_TessLevelOuter[1] = 3.0;\n" 234 "}\n"; 235 236 const char* tc_code[] = { "${VERSION}\n", 237 /* Required EXT_tessellation_shader functionality */ 238 "${TESSELLATION_SHADER_REQUIRE}\n", atomic_counters_header, shader_storage_blocks_header, 239 tc_body }; 240 241 const char* te_body = "\n" 242 "layout (isolines, ccw, equal_spacing, point_mode) in;\n" 243 "\n" 244 /* Uniforms */ 245 "uniform vec2 te_uniform1;\n" 246 "uniform mat4 te_uniform2;\n" 247 "\n" 248 /* Uniform blocks */ 249 "uniform te_uniform_block1\n" 250 "{\n" 251 " float te_uniform_block1_1;\n" 252 "};\n" 253 /* Atomic counter buffers */ 254 "#ifdef USE_ATOMIC_COUNTERS\n" 255 "layout(binding = 2, offset = 0) uniform atomic_uint te_atomic_counter1;\n" 256 "#endif\n" 257 /* Shader storage blocks & buffer variables */ 258 "#ifdef USE_SHADER_STORAGE_BLOCKS\n" 259 "layout(std140, binding = 0) buffer te_shader_storage_block1\n" 260 "{\n" 261 " vec4 te_shader_storage_buffer_object_1[];\n" 262 "};\n" 263 "#endif\n" 264 "void main()\n" 265 "{\n" 266 " int test = 1;\n" 267 "\n" 268 /* Uniforms */ 269 " if (te_uniform1.x == 0.0) test = 2;\n" 270 " if (te_uniform2[0].y == 1.0) test = 3;\n" 271 /* Uniform blocks */ 272 " if (te_uniform_block1_1 == 3.0) test = 4;\n" 273 /* Atomic counter buffers */ 274 "#ifdef USE_ATOMIC_COUNTERS\n" 275 " if (atomicCounter(te_atomic_counter1) == 1u) test = 5;\n" 276 "#endif\n" 277 /* Shader storage blocks & buffer variables */ 278 "#ifdef USE_SHADER_STORAGE_BLOCKS\n" 279 " if (te_shader_storage_buffer_object_1[0].x == 0.0) test = 6;\n" 280 "#endif\n" 281 "\n" 282 " gl_Position = gl_in[0].gl_Position * float(test);\n" 283 "}\n"; 284 285 const char* te_code[] = { "${VERSION}\n", 286 /* Required EXT_tessellation_shader functionality */ 287 "${TESSELLATION_SHADER_REQUIRE}\n", atomic_counters_header, shader_storage_blocks_header, 288 te_body }; 289 290 const char* vs_body = "${VERSION}\n" 291 "\n" 292 "in vec4 test_input;\n" 293 "\n" 294 "void main()\n" 295 "{\n" 296 " gl_Position = vec4(gl_VertexID, test_input.y, 0, 1);\n" 297 "}\n"; 298 299 bool link_success = buildProgram(m_po_id, m_fs_shader_id, 1, &fs_body, m_tc_shader_id, 5, tc_code, m_te_shader_id, 300 5, te_code, m_vs_shader_id, 1, &vs_body); 301 302 if (!link_success) 303 { 304 TCU_FAIL("Program compilation and linking failed"); 305 } 306 307 /* We're good to execute the test! */ 308} 309 310/** Executes the test. 311 * 312 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. 313 * 314 * Note the function throws exception should an error occur! 315 * 316 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. 317 **/ 318tcu::TestNode::IterateResult TessellationShaderProgramInterfaces::iterate(void) 319{ 320 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 321 322 /* Do not execute if required extensions are not supported. */ 323 if (!m_is_tessellation_shader_supported) 324 { 325 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); 326 } 327 328 /* Initialize ES objects needed to run the test */ 329 initTest(); 330 331 /* Iterate through all interfaces */ 332 const glw::GLenum interfaces[] = { 333 GL_UNIFORM, GL_UNIFORM_BLOCK, GL_ATOMIC_COUNTER_BUFFER, GL_SHADER_STORAGE_BLOCK, 334 GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT 335 }; 336 const unsigned int n_interfaces = sizeof(interfaces) / sizeof(interfaces[0]); 337 338 for (unsigned int n_interface = 0; n_interface < n_interfaces; ++n_interface) 339 { 340 glw::GLenum interface = interfaces[n_interface]; 341 342 if ((interface == GL_SHADER_STORAGE_BLOCK || interface == GL_BUFFER_VARIABLE) && 343 !m_is_shader_storage_blocks_supported) 344 { 345 continue; 346 } 347 348 if (interface == GL_ATOMIC_COUNTER_BUFFER && !m_is_atomic_counters_supported) 349 { 350 continue; 351 } 352 353 /* For each interface, we want to check whether a specific resource 354 * is recognized by the implementation. If the name is unknown, 355 * the test should fail; if it's recognized, we should verify it's referenced 356 * by both TC and TE shaders 357 */ 358 const char* tc_resource_name = DE_NULL; 359 const char* te_resource_name = DE_NULL; 360 361 switch (interface) 362 { 363 case GL_UNIFORM: 364 { 365 tc_resource_name = "tc_uniform1"; 366 te_resource_name = "te_uniform1"; 367 368 break; 369 } 370 371 case GL_UNIFORM_BLOCK: 372 { 373 tc_resource_name = "tc_uniform_block1"; 374 te_resource_name = "te_uniform_block1"; 375 376 break; 377 } 378 379 case GL_ATOMIC_COUNTER_BUFFER: 380 { 381 /* Atomic counter buffers are tested in a separate codepath. */ 382 break; 383 } 384 385 case GL_SHADER_STORAGE_BLOCK: 386 { 387 tc_resource_name = "tc_shader_storage_block1"; 388 te_resource_name = "te_shader_storage_block1"; 389 390 break; 391 } 392 393 case GL_BUFFER_VARIABLE: 394 { 395 tc_resource_name = "tc_shader_storage_buffer_object_1"; 396 te_resource_name = "te_shader_storage_buffer_object_1"; 397 398 break; 399 } 400 401 case GL_PROGRAM_INPUT: 402 { 403 tc_resource_name = DE_NULL; 404 te_resource_name = DE_NULL; 405 406 break; 407 } 408 409 case GL_PROGRAM_OUTPUT: 410 { 411 tc_resource_name = DE_NULL; 412 te_resource_name = DE_NULL; 413 414 break; 415 } 416 417 default: 418 { 419 TCU_FAIL("Unrecognized interface type"); 420 } 421 } /* switch (interface) */ 422 423 /* Run in two iterations - first for TC, then for TE */ 424 for (int n_iteration = 0; n_iteration < 2; ++n_iteration) 425 { 426 glw::GLenum property = (n_iteration == 0) ? m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER : 427 m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER; 428 429 if (interface == GL_ATOMIC_COUNTER_BUFFER) 430 { 431 /* We only need a single iteration run for this interface */ 432 if (n_iteration == 1) 433 { 434 continue; 435 } 436 437 /* Atomic counter buffers are not assigned names, hence they need to be 438 * tested slightly differently. 439 * 440 * Exactly two atomic counter buffers should be defined. Make sure that's the case. 441 */ 442 glw::GLint n_active_resources = 0; 443 444 gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources); 445 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed."); 446 447 if (n_active_resources != 2) 448 { 449 TCU_FAIL("Invalid amount of atomic counter buffer binding points reported"); 450 } 451 452 /* Check both resources and make sure they report separate atomic counters */ 453 bool was_tc_atomic_counter_buffer_reported = false; 454 bool was_te_atomic_counter_buffer_reported = false; 455 456 for (int n_resource = 0; n_resource < n_active_resources; ++n_resource) 457 { 458 const glw::GLenum tc_property = m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER; 459 glw::GLint tc_property_value = 0; 460 const glw::GLenum te_property = m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER; 461 glw::GLint te_property_value = 0; 462 463 gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */ 464 &tc_property, 1, /* bufSize */ 465 NULL, /* length */ 466 &tc_property_value); 467 GLU_EXPECT_NO_ERROR( 468 gl.getError(), 469 "glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT property"); 470 471 gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */ 472 &te_property, 1, /* bufSize */ 473 NULL, /* length */ 474 &te_property_value); 475 GLU_EXPECT_NO_ERROR( 476 gl.getError(), 477 "glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT property"); 478 479 if (tc_property_value == GL_TRUE) 480 { 481 if (was_tc_atomic_counter_buffer_reported) 482 { 483 TCU_FAIL("Tessellation control-specific atomic counter buffer is reported twice"); 484 } 485 486 was_tc_atomic_counter_buffer_reported = true; 487 } 488 489 if (te_property_value == GL_TRUE) 490 { 491 if (was_te_atomic_counter_buffer_reported) 492 { 493 TCU_FAIL("Tessellation evaluation-specific atomic counter buffer is reported twice"); 494 } 495 496 was_te_atomic_counter_buffer_reported = true; 497 } 498 } /* for (all active resources) */ 499 500 if (!was_tc_atomic_counter_buffer_reported || !was_te_atomic_counter_buffer_reported) 501 { 502 TCU_FAIL("Either tessellation control or tessellation evaluation atomic counter buffer was not " 503 "reported"); 504 } 505 } 506 else 507 { 508 /* Retrieve resource index first, as long as the name is not NULL. 509 * If it's NULL, the property's value is assumed to be GL_FALSE for 510 * all reported active resources. 511 **/ 512 const char* resource_name = (n_iteration == 0) ? tc_resource_name : te_resource_name; 513 514 if (resource_name == DE_NULL) 515 { 516 /* Make sure the property has GL_FALSE value for any resources 517 * reported for this interface. */ 518 glw::GLint n_active_resources = 0; 519 520 gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources); 521 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed."); 522 523 for (glw::GLint n_resource = 0; n_resource < n_active_resources; ++n_resource) 524 { 525 verifyPropertyValue(interface, property, n_resource, GL_FALSE); 526 } /* for (all resource indices) */ 527 } 528 else 529 { 530 glw::GLuint resource_index = gl.getProgramResourceIndex(m_po_id, interface, resource_name); 531 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceIndex() failed"); 532 533 if (resource_index == GL_INVALID_INDEX) 534 { 535 m_testCtx.getLog() << tcu::TestLog::Message << "Resource [" << resource_name 536 << "] was not recognized." << tcu::TestLog::EndMessage; 537 538 TCU_FAIL("Resource not recognized."); 539 } 540 541 /* Now that we know the index, we can check the GL_REFERENCED_BY_... 542 * property value */ 543 verifyPropertyValue(interface, property, resource_index, GL_TRUE); 544 } 545 } /* (interface != GL_ATOMIC_COUNTER_BUFFER) */ 546 } /* for (both iterations) */ 547 } /* for (all interfaces) */ 548 549 /* All done */ 550 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 551 return STOP; 552} 553 554/** Checks if a property value reported for user-specified program object interface 555 * at given index is as expected. 556 * 557 * NOTE: This function throws TestError exception if retrieved value does not 558 * match @param expected_value. 559 * 560 * @param interface Program object interface to use for the query; 561 * @param property Interface property to check; 562 * @param index Property index to use for the test; 563 * @param expected_value Value that is expected to be reported by ES implementation. 564 **/ 565void TessellationShaderProgramInterfaces::verifyPropertyValue(glw::GLenum interface, glw::GLenum property, 566 glw::GLuint index, glw::GLint expected_value) 567{ 568 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 569 glw::GLint property_value = 0; 570 571 gl.getProgramResourceiv(m_po_id, interface, index, 1, /* propCount */ 572 &property, 1, /* bufSize */ 573 NULL, /* length */ 574 &property_value); 575 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv() failed"); 576 577 if (property_value != expected_value) 578 { 579 TCU_FAIL("Invalid GL_REFERENCED_BY_... property value reported"); 580 } 581} 582 583} /* namespace glcts */ 584