1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2015-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 /** 25 */ /*! 26 * \file gl3cCullDistanceTests.cpp 27 * \brief Cull Distance Test Suite Implementation 28 */ /*-------------------------------------------------------------------*/ 29 30 #include "gl3cCullDistanceTests.hpp" 31 #include "gluContextInfo.hpp" 32 #include "gluDefs.hpp" 33 #include "gluStrUtil.hpp" 34 #include "glwEnums.hpp" 35 #include "glwFunctions.hpp" 36 #include "tcuRenderTarget.hpp" 37 #include "tcuTestLog.hpp" 38 39 #include <cmath> 40 #include <sstream> 41 #include <string> 42 #include <vector> 43 44 #ifndef GL_MAX_CULL_DISTANCES 45 #define GL_MAX_CULL_DISTANCES (0x82F9) 46 #endif 47 #ifndef GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 48 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES (0x82FA) 49 #endif 50 51 namespace glcts 52 { 53 /** @brief Build OpenGL program 54 * 55 * @param [in] gl OpenGL function bindings 56 * @param [in] testCtx Context 57 * @param [in] cs_body Compute shader source code 58 * @param [in] fs_body Fragment shader source code 59 * @param [in] gs_body Geometric shader source code 60 * @param [in] tc_body Tessellation control shader source code 61 * @param [in] te_body Tessellation evaluation shader source code 62 * @param [in] vs_body Vertex shader source code 63 * @param [in] n_tf_varyings Number of transform feedback varyings 64 * @param [in] tf_varyings Transform feedback varyings names 65 * 66 * @param [out] out_program If succeeded output program GL handle, 0 otherwise. 67 */ 68 void CullDistance::Utilities::buildProgram(const glw::Functions& gl, tcu::TestContext& testCtx, 69 const glw::GLchar* cs_body, const glw::GLchar* fs_body, 70 const glw::GLchar* gs_body, const glw::GLchar* tc_body, 71 const glw::GLchar* te_body, const glw::GLchar* vs_body, 72 const glw::GLuint& n_tf_varyings, const glw::GLchar** tf_varyings, 73 glw::GLuint* out_program) 74 { 75 glw::GLuint po_id = 0; 76 77 struct _shaders_configuration 78 { 79 glw::GLenum type; 80 const glw::GLchar* body; 81 glw::GLuint id; 82 } shaders_configuration[] = { { GL_COMPUTE_SHADER, cs_body, 0 }, { GL_FRAGMENT_SHADER, fs_body, 0 }, 83 { GL_GEOMETRY_SHADER, gs_body, 0 }, { GL_TESS_CONTROL_SHADER, tc_body, 0 }, 84 { GL_TESS_EVALUATION_SHADER, te_body, 0 }, { GL_VERTEX_SHADER, vs_body, 0 } }; 85 86 const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]); 87 88 /* Guard allocated OpenGL resources */ 89 try 90 { 91 /* Create needed programs */ 92 po_id = gl.createProgram(); 93 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed."); 94 95 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++) 96 { 97 if (shaders_configuration[n_shader_index].body != DE_NULL) 98 { 99 /* Generate shader object */ 100 shaders_configuration[n_shader_index].id = gl.createShader(shaders_configuration[n_shader_index].type); 101 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed"); 102 103 glw::GLint compile_status = GL_FALSE; 104 const glw::GLuint so_id = shaders_configuration[n_shader_index].id; 105 106 /* Assign shader source code */ 107 gl.shaderSource(shaders_configuration[n_shader_index].id, 1, /* count */ 108 &shaders_configuration[n_shader_index].body, DE_NULL); /* length */ 109 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed"); 110 111 gl.compileShader(so_id); 112 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); 113 114 gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status); 115 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); 116 117 if (compile_status == GL_FALSE) 118 { 119 std::vector<glw::GLchar> log_array(1); 120 glw::GLint log_length = 0; 121 std::string log_string("Failed to retrieve log"); 122 123 /* Retrive compilation log length */ 124 gl.getShaderiv(so_id, GL_INFO_LOG_LENGTH, &log_length); 125 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); 126 127 log_array.resize(log_length + 1, 0); 128 129 gl.getShaderInfoLog(so_id, log_length, DE_NULL, &log_array[0]); 130 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed."); 131 132 log_string = std::string(&log_array[0]); 133 134 testCtx.getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n" 135 << "Shader type: " << shaders_configuration[n_shader_index].type << "\n" 136 << "Shader compilation error log:\n" 137 << log_string << "\n" 138 << "Shader source code:\n" 139 << shaders_configuration[n_shader_index].body << "\n" 140 << tcu::TestLog::EndMessage; 141 142 TCU_FAIL("Shader compilation has failed."); 143 } 144 145 /* Also attach the shader to the corresponding program object */ 146 gl.attachShader(po_id, so_id); 147 148 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed"); 149 } /* if (shaders_configuration[n_shader_index].body != DE_NULL) */ 150 } /* for (all shader object IDs) */ 151 152 /* Set transform feedback if requested */ 153 if (n_tf_varyings > 0) 154 { 155 gl.transformFeedbackVaryings(po_id, n_tf_varyings, tf_varyings, GL_INTERLEAVED_ATTRIBS); 156 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed"); 157 } 158 159 /* Try to link the program objects */ 160 if (po_id != 0) 161 { 162 glw::GLint link_status = GL_FALSE; 163 164 gl.linkProgram(po_id); 165 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed"); 166 167 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status); 168 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed"); 169 170 if (link_status == GL_FALSE) 171 { 172 std::vector<glw::GLchar> log_array(1); 173 glw::GLsizei log_length = 0; 174 std::string log_string; 175 176 /* Retreive compilation log length */ 177 gl.getProgramiv(po_id, GL_INFO_LOG_LENGTH, &log_length); 178 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); 179 180 log_array.resize(log_length + 1, 0); 181 182 /* Retreive compilation log */ 183 gl.getProgramInfoLog(po_id, log_length, DE_NULL, &log_array[0]); 184 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed."); 185 186 log_string = std::string(&log_array[0]); 187 188 /* Log linking error message */ 189 testCtx.getLog() << tcu::TestLog::Message << "Program linking has failed.\n" 190 << "Linking error log:\n" 191 << log_string << "\n" 192 << tcu::TestLog::EndMessage; 193 194 /* Log shader source code of shaders involved */ 195 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++) 196 { 197 if (shaders_configuration[n_shader_index].body != DE_NULL) 198 { 199 testCtx.getLog() << tcu::TestLog::Message << "Shader source code of type " 200 << shaders_configuration[n_shader_index].type << " follows:\n" 201 << shaders_configuration[n_shader_index].body << "\n" 202 << tcu::TestLog::EndMessage; 203 } 204 } 205 206 TCU_FAIL("Program linking failed"); 207 } 208 } /* if (po_id != 0) */ 209 210 /* Delete all shaders we've created */ 211 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++) 212 { 213 const glw::GLuint so_id = shaders_configuration[n_shader_index].id; 214 215 if (so_id != 0) 216 { 217 gl.deleteShader(so_id); 218 219 shaders_configuration[n_shader_index].id = 0; 220 221 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed."); 222 } 223 } 224 225 /* Store the result progrtam IDs */ 226 *out_program = po_id; 227 } 228 catch (...) 229 { 230 /* Delete all shaders we've created */ 231 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++) 232 { 233 const glw::GLuint so_id = shaders_configuration[n_shader_index].id; 234 235 if (so_id != 0) 236 { 237 gl.deleteShader(so_id); 238 239 shaders_configuration[n_shader_index].id = 0; 240 } 241 } 242 243 /* Delete the program object */ 244 if (po_id != 0) 245 { 246 gl.deleteProgram(po_id); 247 248 po_id = 0; 249 } 250 251 /* Rethrow */ 252 throw; 253 } 254 } 255 256 /** @brief Replace all occurences of a substring in a string by a substring 257 * 258 * @param [in,out] str string to be edited 259 * @param [in] from substring to be replaced 260 * @param [out] to new substring 261 */ 262 void CullDistance::Utilities::replaceAll(std::string& str, const std::string& from, const std::string& to) 263 { 264 for (size_t start_pos = str.find(from, 0); start_pos != std::string::npos; start_pos = str.find(from, start_pos)) 265 { 266 str.replace(start_pos, from.length(), to); 267 268 start_pos += to.length(); 269 } 270 271 return; 272 } 273 274 /** @brief Convert integer to string representation 275 * 276 * @param [in] integer input integer to be converted 277 * 278 * @return String representation of integer 279 */ 280 std::string CullDistance::Utilities::intToString(glw::GLint integer) 281 { 282 std::stringstream temp_sstream; 283 284 temp_sstream << integer; 285 286 return temp_sstream.str(); 287 } 288 289 /** Constructor. 290 * 291 * @param context Rendering context handle. 292 **/ 293 CullDistance::APICoverageTest::APICoverageTest(deqp::Context& context) 294 : TestCase(context, "coverage", "Cull Distance API Coverage Test") 295 , m_bo_id(0) 296 , m_cs_id(0) 297 , m_cs_to_id(0) 298 , m_fbo_draw_id(0) 299 , m_fbo_draw_to_id(0) 300 , m_fbo_read_id(0) 301 , m_fs_id(0) 302 , m_gs_id(0) 303 , m_po_id(0) 304 , m_tc_id(0) 305 , m_te_id(0) 306 , m_vao_id(0) 307 , m_vs_id(0) 308 { 309 /* Left blank on purpose */ 310 } 311 312 /** @brief Cull Distance API Coverage Test deinitialization */ 313 void CullDistance::APICoverageTest::deinit() 314 { 315 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 316 317 if (m_bo_id != 0) 318 { 319 gl.deleteBuffers(1, &m_bo_id); 320 321 m_bo_id = 0; 322 } 323 324 if (m_cs_id != 0) 325 { 326 gl.deleteShader(m_cs_id); 327 328 m_cs_id = 0; 329 } 330 331 if (m_cs_to_id != 0) 332 { 333 gl.deleteTextures(1, &m_cs_to_id); 334 335 m_cs_to_id = 0; 336 } 337 338 if (m_fbo_draw_id != 0) 339 { 340 gl.deleteFramebuffers(1, &m_fbo_draw_id); 341 342 m_fbo_draw_id = 0; 343 } 344 345 if (m_fbo_draw_to_id != 0) 346 { 347 gl.deleteTextures(1, &m_fbo_draw_to_id); 348 349 m_fbo_draw_to_id = 0; 350 } 351 352 if (m_fbo_read_id != 0) 353 { 354 gl.deleteFramebuffers(1, &m_fbo_read_id); 355 356 m_fbo_read_id = 0; 357 } 358 359 if (m_fs_id != 0) 360 { 361 gl.deleteShader(m_fs_id); 362 363 m_fs_id = 0; 364 } 365 366 if (m_gs_id != 0) 367 { 368 gl.deleteShader(m_gs_id); 369 370 m_gs_id = 0; 371 } 372 373 if (m_po_id != 0) 374 { 375 gl.deleteProgram(m_po_id); 376 377 m_po_id = 0; 378 } 379 380 if (m_tc_id != 0) 381 { 382 gl.deleteShader(m_tc_id); 383 384 m_tc_id = 0; 385 } 386 387 if (m_te_id != 0) 388 { 389 gl.deleteShader(m_te_id); 390 391 m_te_id = 0; 392 } 393 394 if (m_vao_id != 0) 395 { 396 gl.deleteVertexArrays(1, &m_vao_id); 397 398 m_vao_id = 0; 399 } 400 401 if (m_vs_id != 0) 402 { 403 gl.deleteShader(m_vs_id); 404 405 m_vs_id = 0; 406 } 407 408 /* Restore default pack alignment value */ 409 gl.pixelStorei(GL_PACK_ALIGNMENT, 4); 410 } 411 412 /** Executes test iteration. 413 * 414 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. 415 */ 416 tcu::TestNode::IterateResult CullDistance::APICoverageTest::iterate() 417 { 418 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 419 420 /* This test should only be executed if ARB_cull_distance is supported, or if 421 * we're running a GL4.5 context 422 */ 423 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") && 424 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))) 425 { 426 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported"); 427 } 428 429 /* Check that calling GetIntegerv with MAX_CULL_DISTANCES doesn't generate 430 * any errors and returns a value at least 8. 431 * 432 * Check that calling GetIntegerv with MAX_COMBINED_CLIP_AND_CULL_DISTANCES 433 * doesn't generate any errors and returns a value at least 8. 434 * 435 */ 436 glw::GLint error_code = GL_NO_ERROR; 437 glw::GLint gl_max_cull_distances_value = 0; 438 glw::GLint gl_max_combined_clip_and_cull_distances_value = 0; 439 440 gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value); 441 442 error_code = gl.getError(); 443 if (error_code != GL_NO_ERROR) 444 { 445 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code " 446 << "[" << glu::getErrorStr(error_code) << "] for GL_MAX_CULL_DISTANCES" 447 " query instead of GL_NO_ERROR" 448 << tcu::TestLog::EndMessage; 449 450 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 451 452 return STOP; 453 } 454 455 gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value); 456 457 error_code = gl.getError(); 458 if (error_code != GL_NO_ERROR) 459 { 460 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv() returned error code " 461 << "[" << glu::getErrorStr(error_code) << "] for " 462 "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES query " 463 "instead of GL_NO_ERROR" 464 << tcu::TestLog::EndMessage; 465 466 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 467 468 return STOP; 469 } 470 471 /* Before we proceed with the two other tests, initialize a buffer & a texture 472 * object we will need to capture data from the programs */ 473 static const glw::GLuint bo_size = sizeof(int) * 4 /* components */ * 4 /* result points */; 474 475 gl.genBuffers(1, &m_bo_id); 476 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); 477 478 gl.genFramebuffers(1, &m_fbo_draw_id); 479 gl.genFramebuffers(1, &m_fbo_read_id); 480 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call(s) failed."); 481 482 gl.genTextures(1, &m_cs_to_id); 483 gl.genTextures(1, &m_fbo_draw_to_id); 484 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); 485 486 gl.genVertexArrays(1, &m_vao_id); 487 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); 488 489 gl.bindVertexArray(m_vao_id); 490 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); 491 492 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); 493 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */ 494 m_bo_id); 495 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() or glBindBufferBase() call(s) failed."); 496 497 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW); 498 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); 499 500 for (glw::GLuint n_to_id = 0; n_to_id < 2; /* CS, FBO */ ++n_to_id) 501 { 502 gl.bindTexture(GL_TEXTURE_2D, (n_to_id == 0) ? m_cs_to_id : m_fbo_draw_to_id); 503 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); 504 505 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ 506 GL_R32I, 1, /* width */ 507 1); /* height */ 508 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); 509 } 510 511 gl.bindImageTexture(0, /* unit */ 512 m_cs_to_id, 0, /* level */ 513 GL_FALSE, /* layered */ 514 0, /* layer */ 515 GL_WRITE_ONLY, GL_R32I); 516 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindImageTexture() call failed."); 517 518 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_draw_id); 519 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); 520 521 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fbo_draw_to_id, 0); /* level */ 522 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); 523 524 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read_id); 525 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); 526 527 gl.viewport(0, /* x */ 528 0, /* y */ 529 1, /* width */ 530 1); /* height */ 531 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed."); 532 533 gl.pixelStorei(GL_PACK_ALIGNMENT, 1); 534 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed."); 535 536 /* There are two new GL constants, where value we need to verify */ 537 struct _run 538 { 539 const glw::GLchar* essl_token_value; 540 glw::GLenum gl_enum; 541 glw::GLint gl_value; 542 glw::GLint min_value; 543 const glw::GLchar* name; 544 } runs[] = { { "gl_MaxCullDistances", GL_MAX_CULL_DISTANCES, gl_max_cull_distances_value, 8 /*minimum required */, 545 "GL_MAX_CULL_DISTANCES" }, 546 { "gl_MaxCombinedClipAndCullDistances", GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, 547 gl_max_combined_clip_and_cull_distances_value, 8 /*minimum required */, 548 "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES" } }; 549 550 static const glw::GLuint n_runs = sizeof(runs) / sizeof(runs[0]); 551 552 for (glw::GLuint n_run = 0; n_run < n_runs; ++n_run) 553 { 554 _run& current_run = runs[n_run]; 555 556 static const struct _stage 557 { 558 bool use_cs; 559 bool use_fs; 560 bool use_gs; 561 bool use_tc; 562 bool use_te; 563 bool use_vs; 564 565 const glw::GLchar* fs_input; 566 const glw::GLchar* gs_input; 567 const glw::GLchar* tc_input; 568 const glw::GLchar* te_input; 569 570 const glw::GLchar* tf_output_name; 571 const glw::GLenum tf_mode; 572 573 glw::GLenum draw_call_mode; 574 glw::GLuint n_draw_call_vertices; 575 } stages[] = { /* CS only test */ 576 { 577 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */ 578 true, false, false, false, false, false, 579 580 NULL, /* fs_input */ 581 NULL, /* gs_input */ 582 NULL, /* tc_input */ 583 NULL, /* te_input */ 584 NULL, /* tf_output_name */ 585 GL_NONE, /* tf_mode */ 586 GL_NONE, /* draw_call_mode */ 587 0, /* n_draw_call_vertices */ 588 }, 589 /* VS+GS+TC+TE+FS test */ 590 { 591 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */ 592 false, true, true, true, true, true, 593 594 "out_gs", /* fs_input */ 595 "out_te", /* gs_input */ 596 "out_vs", /* tc_input */ 597 "out_tc", /* te_input */ 598 "out_gs", /* tf_output_name */ 599 GL_TRIANGLES, /* tf_mode */ 600 GL_PATCHES, /* draw_call_mode */ 601 3, /* n_draw_call_vertices */ 602 }, 603 /* VS+GS+FS test */ 604 { 605 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */ 606 false, true, true, false, false, true, 607 608 "out_gs", /* fs_input */ 609 "out_vs", /* gs_input */ 610 NULL, /* tc_input */ 611 NULL, /* te_input */ 612 "out_gs", /* tf_output_name */ 613 GL_TRIANGLES, /* tf_mode */ 614 GL_POINTS, /* draw_call_mode */ 615 1, /* n_draw_call_vertices */ 616 }, 617 /* VS+TC+TE+FS test */ 618 { 619 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */ 620 false, true, false, true, true, true, 621 622 "out_te", /* fs_input */ 623 NULL, /* gs_input */ 624 "out_vs", /* tc_input */ 625 "out_tc", /* te_input */ 626 "out_te", /* tf_output_name */ 627 GL_POINTS, /* tf_mode */ 628 GL_PATCHES, /* draw_call_mode */ 629 3 /* n_draw_call_vertices */ 630 }, 631 /* VS test */ 632 { 633 /* use_cs|use_fs|use_gs|use_tc|use_te|use_vs */ 634 false, false, false, false, false, true, 635 636 "out_vs", /* fs_input */ 637 NULL, /* gs_input */ 638 NULL, /* tc_input */ 639 NULL, /* te_input */ 640 "out_vs", /* tf_output_name */ 641 GL_POINTS, /* tf_mode */ 642 GL_POINTS, /* draw_call_mode */ 643 1 /* n_draw_call_vertices */ 644 } 645 }; 646 const glw::GLuint n_stages = sizeof(stages) / sizeof(stages[0]); 647 648 /* Run through all test stages */ 649 for (glw::GLuint n_stage = 0; n_stage < n_stages; ++n_stage) 650 { 651 /* Check for OpenGL feature support */ 652 if (stages[n_stage].use_cs) 653 { 654 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 3)) && 655 !m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader")) 656 { 657 continue; // no compute shader support 658 } 659 } 660 if (stages[n_stage].use_tc || stages[n_stage].use_te) 661 { 662 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) && 663 !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader")) 664 { 665 continue; // no tessellation shader support 666 } 667 } 668 669 /* Check that use of the GLSL built-in constant gl_MaxCullDistance in any 670 * shader stage (including compute shader) does not affect the shader 671 * compilation & program linking process. 672 */ 673 static const glw::GLchar* cs_body_template = 674 "#version 150\n" 675 "\n" 676 "#extension GL_ARB_compute_shader : require\n" 677 "#extension GL_ARB_cull_distance : require\n" 678 "#extension GL_ARB_shader_image_load_store : require\n" 679 "\n" 680 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 681 "\n" 682 "layout(r32i) uniform writeonly iimage2D result;\n" 683 "\n" 684 "void main()\n" 685 "{\n" 686 " imageStore(result, ivec2(0),ivec4(TOKEN) );\n" 687 "}\n"; 688 std::string cs_body = cs_body_template; 689 690 static const glw::GLchar* fs_body_template = "#version 150\n" 691 "\n" 692 "#extension GL_ARB_cull_distance : require\n" 693 "\n" 694 "flat in int INPUT_FS_NAME;\n" 695 "out int out_fs;\n" 696 "\n" 697 "void main()\n" 698 "{\n" 699 " if (INPUT_FS_NAME == TOKEN)\n" 700 " {\n" 701 " out_fs = TOKEN;\n" 702 " }\n" 703 " else\n" 704 " {\n" 705 " out_fs = -1;\n" 706 " }\n" 707 "}\n"; 708 std::string fs_body = fs_body_template; 709 710 static const glw::GLchar* gs_body_template = 711 "#version 150\n" 712 "\n" 713 "#extension GL_ARB_cull_distance : require\n" 714 "\n" 715 "flat in int INPUT_GS_NAME[];\n" 716 "flat out int out_gs;\n" 717 "\n" 718 "layout(points) in;\n" 719 "layout(triangle_strip, max_vertices = 4) out;\n" 720 "\n" 721 "void main()\n" 722 "{\n" 723 " int result_value = (INPUT_GS_NAME[0] == TOKEN) ? TOKEN : -1;\n" 724 "\n" 725 /* Draw a full-screen quad */ 726 " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" 727 " out_gs = result_value;\n" 728 " EmitVertex();\n" 729 "\n" 730 " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" 731 " out_gs = result_value;\n" 732 " EmitVertex();\n" 733 "\n" 734 " gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n" 735 " out_gs = result_value;\n" 736 " EmitVertex();\n" 737 "\n" 738 " gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n" 739 " out_gs = result_value;\n" 740 " EmitVertex();\n" 741 " EndPrimitive();\n" 742 "}\n"; 743 std::string gs_body = gs_body_template; 744 745 static const glw::GLchar* tc_body_template = 746 "#version 400\n" 747 "\n" 748 "#extension GL_ARB_cull_distance : require\n" 749 "\n" 750 "layout(vertices = 1) out;\n" 751 "\n" 752 "flat in int INPUT_TC_NAME[];\n" 753 "flat out int out_tc [];\n" 754 "\n" 755 "void main()\n" 756 "{\n" 757 " int result_value = (INPUT_TC_NAME[0] == TOKEN) ? TOKEN : -1;\n" 758 "\n" 759 " out_tc[gl_InvocationID] = result_value;\n" 760 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 761 " gl_TessLevelInner[0] = 1.0;\n" 762 " gl_TessLevelInner[1] = 1.0;\n" 763 " gl_TessLevelOuter[0] = 1.0;\n" 764 " gl_TessLevelOuter[1] = 1.0;\n" 765 " gl_TessLevelOuter[2] = 1.0;\n" 766 " gl_TessLevelOuter[3] = 1.0;\n" 767 "}\n"; 768 std::string tc_body = tc_body_template; 769 770 static const glw::GLchar* te_body_template = 771 "#version 400\n" 772 "\n" 773 "#extension GL_ARB_cull_distance : require\n" 774 "\n" 775 "flat in int INPUT_TE_NAME[];\n" 776 "flat out int out_te;\n" 777 "\n" 778 "layout(isolines, point_mode) in;\n" 779 "\n" 780 "void main()\n" 781 "{\n" 782 " int result_value = (INPUT_TE_NAME[0] == TOKEN) ? TOKEN : 0;\n" 783 "\n" 784 " out_te = result_value;\n" 785 "\n" 786 " gl_Position = vec4(0.0, 0.0, 0.0, 1.);\n" 787 "}\n"; 788 std::string te_body = te_body_template; 789 790 static const glw::GLchar* vs_body_template = "#version 150\n" 791 "\n" 792 "#extension GL_ARB_cull_distance : require\n" 793 "\n" 794 "flat out int out_vs;\n" 795 "\n" 796 "void main()\n" 797 "{\n" 798 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 799 " out_vs = TOKEN;\n" 800 "}\n"; 801 std::string vs_body = vs_body_template; 802 803 const _stage& current_stage = stages[n_stage]; 804 805 /* Build shader bodies */ 806 struct _shader_body 807 { 808 std::string* body_ptr; 809 glw::GLenum gl_type; 810 } shader_bodies[] = { { &cs_body, GL_COMPUTE_SHADER }, { &fs_body, GL_FRAGMENT_SHADER }, 811 { &gs_body, GL_GEOMETRY_SHADER }, { &tc_body, GL_TESS_CONTROL_SHADER }, 812 { &te_body, GL_TESS_EVALUATION_SHADER }, { &vs_body, GL_VERTEX_SHADER } }; 813 static const glw::GLchar* input_fs_token_string = "INPUT_FS_NAME"; 814 static const glw::GLchar* input_gs_token_string = "INPUT_GS_NAME"; 815 static const glw::GLchar* input_te_token_string = "INPUT_TE_NAME"; 816 static const glw::GLchar* input_tc_token_string = "INPUT_TC_NAME"; 817 static const glw::GLuint n_shader_bodies = sizeof(shader_bodies) / sizeof(shader_bodies[0]); 818 819 std::size_t token_position = std::string::npos; 820 static const glw::GLchar* token_string = "TOKEN"; 821 822 for (glw::GLuint n_shader_body = 0; n_shader_body < n_shader_bodies; ++n_shader_body) 823 { 824 _shader_body& current_body = shader_bodies[n_shader_body]; 825 826 /* Is this stage actually used? */ 827 if (((current_body.gl_type == GL_COMPUTE_SHADER) && (!current_stage.use_cs)) || 828 ((current_body.gl_type == GL_FRAGMENT_SHADER) && (!current_stage.use_fs)) || 829 ((current_body.gl_type == GL_TESS_CONTROL_SHADER) && (!current_stage.use_tc)) || 830 ((current_body.gl_type == GL_TESS_EVALUATION_SHADER) && (!current_stage.use_te)) || 831 ((current_body.gl_type == GL_VERTEX_SHADER) && (!current_stage.use_vs))) 832 { 833 /* Skip the iteration. */ 834 continue; 835 } 836 837 /* Iterate over all token and replace them with stage-specific values */ 838 struct _token_value_pair 839 { 840 const glw::GLchar* token; 841 const glw::GLchar* value; 842 } token_value_pairs[] = { 843 /* NOTE: The last entry is filled by the switch() block below */ 844 { token_string, current_run.essl_token_value }, 845 { NULL, NULL }, 846 }; 847 848 const size_t n_token_value_pairs = sizeof(token_value_pairs) / sizeof(token_value_pairs[0]); 849 850 switch (current_body.gl_type) 851 { 852 case GL_COMPUTE_SHADER: 853 case GL_VERTEX_SHADER: 854 break; 855 856 case GL_FRAGMENT_SHADER: 857 { 858 token_value_pairs[1].token = input_fs_token_string; 859 token_value_pairs[1].value = current_stage.fs_input; 860 861 break; 862 } 863 864 case GL_GEOMETRY_SHADER: 865 { 866 token_value_pairs[1].token = input_gs_token_string; 867 token_value_pairs[1].value = current_stage.gs_input; 868 869 break; 870 } 871 872 case GL_TESS_CONTROL_SHADER: 873 { 874 token_value_pairs[1].token = input_tc_token_string; 875 token_value_pairs[1].value = current_stage.tc_input; 876 877 break; 878 } 879 880 case GL_TESS_EVALUATION_SHADER: 881 { 882 token_value_pairs[1].token = input_te_token_string; 883 token_value_pairs[1].value = current_stage.te_input; 884 885 break; 886 } 887 888 default: 889 TCU_FAIL("Unrecognized shader body type"); 890 } 891 892 for (glw::GLuint n_pair = 0; n_pair < n_token_value_pairs; ++n_pair) 893 { 894 const _token_value_pair& current_pair = token_value_pairs[n_pair]; 895 896 if (current_pair.token == NULL || current_pair.value == NULL) 897 { 898 continue; 899 } 900 901 while ((token_position = current_body.body_ptr->find(current_pair.token)) != std::string::npos) 902 { 903 current_body.body_ptr->replace(token_position, strlen(current_pair.token), current_pair.value); 904 } 905 } /* for (all token+value pairs) */ 906 } /* for (all sader bodies) */ 907 908 /* Build the test program */ 909 CullDistance::Utilities::buildProgram( 910 gl, m_testCtx, current_stage.use_cs ? cs_body.c_str() : DE_NULL, 911 current_stage.use_fs ? fs_body.c_str() : DE_NULL, current_stage.use_gs ? gs_body.c_str() : DE_NULL, 912 current_stage.use_tc ? tc_body.c_str() : DE_NULL, current_stage.use_te ? te_body.c_str() : DE_NULL, 913 current_stage.use_vs ? vs_body.c_str() : DE_NULL, (current_stage.tf_output_name != NULL) ? 1 : 0, 914 (const glw::GLchar**)¤t_stage.tf_output_name, &m_po_id); 915 916 /* Bind the test program */ 917 DE_ASSERT(m_po_id != 0); 918 919 gl.useProgram(m_po_id); 920 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); 921 922 /* Execute the draw call. Transform Feed-back should be enabled for all iterations 923 * par the CS one, since we use a different tool to capture the result data in the 924 * latter case. 925 */ 926 if (!current_stage.use_cs) 927 { 928 gl.beginTransformFeedback(current_stage.tf_mode); 929 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed."); 930 931 gl.drawArrays(current_stage.draw_call_mode, 0, /* first */ 932 current_stage.n_draw_call_vertices); /* count */ 933 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed."); 934 935 gl.endTransformFeedback(); 936 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed."); 937 } /* if (uses_tf) */ 938 else 939 { 940 gl.dispatchCompute(1, /* num_groups_x */ 941 1, /* num_groups_y */ 942 1); /* num_groups_z */ 943 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() call failed."); 944 } 945 946 /* Verify the result values */ 947 if (!current_stage.use_cs) 948 { 949 glw::GLint* result_data_ptr = DE_NULL; 950 951 /* Retrieve the data captured by Transform Feedback */ 952 result_data_ptr = (glw::GLint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ 953 sizeof(unsigned int) * 1, GL_MAP_READ_BIT); 954 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed."); 955 956 if (*result_data_ptr != current_run.gl_value) 957 { 958 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value " 959 "[" 960 << *result_data_ptr << "]" 961 " does not match the one reported by glGetIntegerv() " 962 "[" 963 << current_run.gl_value << "]" << tcu::TestLog::EndMessage; 964 965 TCU_FAIL("GL constant value does not match the ES SL equivalent"); 966 } 967 968 if (*result_data_ptr < current_run.min_value) 969 { 970 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name << " value " 971 "[" 972 << *result_data_ptr << "]" 973 " does not meet the minimum specification requirements " 974 "[" 975 << current_run.min_value << "]" << tcu::TestLog::EndMessage; 976 977 TCU_FAIL("GL constant value does not meet minimum specification requirements"); 978 } 979 980 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 981 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed."); 982 } 983 984 for (glw::GLuint n_stage_internal = 0; n_stage_internal < 2; /* CS, FS write to separate textures */ 985 ++n_stage_internal) 986 { 987 glw::GLuint to_id = (n_stage_internal == 0) ? m_cs_to_id : m_fbo_draw_to_id; 988 989 if (((n_stage_internal == 0) && (!current_stage.use_cs)) || 990 ((n_stage_internal == 1) && (!current_stage.use_fs))) 991 { 992 /* Skip the iteration */ 993 continue; 994 } 995 996 /* Check the image data the test CS / FS should have written */ 997 glw::GLint result_value = 0; 998 999 gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_id, 0); /* level */ 1000 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); 1001 1002 /* NOTE: We're using our custom read framebuffer here, so we'll be reading 1003 * from the texture, that the writes have been issued to earlier. */ 1004 gl.finish(); 1005 GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() call failed."); 1006 1007 gl.readPixels(0, /* x */ 1008 0, /* y */ 1009 1, /* width */ 1010 1, /* height */ 1011 GL_RED_INTEGER, GL_INT, &result_value); 1012 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed."); 1013 1014 if (result_value != current_run.gl_value) 1015 { 1016 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name 1017 << " value accessible to the compute / fragment shader " 1018 "[" 1019 << result_value << "]" 1020 " does not match the one reported by glGetIntegerv() " 1021 "[" 1022 << current_run.gl_value << "]" << tcu::TestLog::EndMessage; 1023 1024 TCU_FAIL("GL constant value does not match the ES SL equivalent"); 1025 } 1026 1027 if (result_value < current_run.min_value) 1028 { 1029 m_testCtx.getLog() << tcu::TestLog::Message << current_run.name 1030 << " value accessible to the compute / fragment shader " 1031 "[" 1032 << result_value << "]" 1033 " does not meet the minimum specification requirements " 1034 "[" 1035 << current_run.min_value << "]" << tcu::TestLog::EndMessage; 1036 1037 TCU_FAIL("GL constant value does not meet minimum specification requirements"); 1038 } 1039 } 1040 1041 /* Clear the data buffer before we continue */ 1042 static const glw::GLubyte bo_clear_data[bo_size] = { 0 }; 1043 1044 gl.bufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ 1045 bo_size, bo_clear_data); 1046 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed."); 1047 1048 /* Clear the texture mip-map before we continue */ 1049 glw::GLint clear_values[4] = { 0, 0, 0, 0 }; 1050 1051 gl.clearBufferiv(GL_COLOR, 0, /* drawbuffer */ 1052 clear_values); 1053 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed."); 1054 1055 /* Release program before we move on to the next iteration */ 1056 if (m_po_id != 0) 1057 { 1058 gl.deleteProgram(m_po_id); 1059 1060 m_po_id = 0; 1061 } 1062 } /* for (all stages) */ 1063 } /* for (both runs) */ 1064 1065 /* All done */ 1066 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1067 1068 return STOP; 1069 } 1070 1071 /** Constructor. 1072 * 1073 * @param context Rendering context handle. 1074 **/ 1075 CullDistance::FunctionalTest::FunctionalTest(deqp::Context& context) 1076 : TestCase(context, "functional", "Cull Distance Functional Test") 1077 , m_bo_data() 1078 , m_bo_id(0) 1079 , m_fbo_id(0) 1080 , m_po_id(0) 1081 , m_render_primitives(0) 1082 , m_render_vertices(0) 1083 , m_sub_grid_cell_size(0) 1084 , m_to_id(0) 1085 , m_vao_id(0) 1086 , m_to_height(512) 1087 , m_to_width(512) 1088 , m_to_pixel_data_cache() 1089 { 1090 /* Left blank on purpose */ 1091 } 1092 1093 /** @brief Build OpenGL program for functional tests 1094 * 1095 * @param [in] clipdistances_array_size use size of gl_ClipDistance array 1096 * @param [in] culldistances_array_size use size of gl_CullDistance array 1097 * @param [in] dynamic_index_writes use dunamic indexing for setting the gl_ClipDistance and gl_CullDistance arrays 1098 * @param [in] primitive_mode primitive_mode will be used for rendering 1099 * @param [in] redeclare_clipdistances redeclare gl_ClipDistance 1100 * @param [in] redeclare_culldistances redeclare gl_CullDistance 1101 * @param [in] use_core_functionality use core OpenGL functionality 1102 * @param [in] use_gs use geometry shader 1103 * @param [in] use_ts use tessellation shader 1104 * @param [in] fetch_culldistance_from_fs fetch check sum of gl_ClipDistance and gl_CullDistance from fragment shader 1105 */ 1106 void CullDistance::FunctionalTest::buildPO(glw::GLuint clipdistances_array_size, glw::GLuint culldistances_array_size, 1107 bool dynamic_index_writes, _primitive_mode primitive_mode, 1108 bool redeclare_clipdistances, bool redeclare_culldistances, 1109 bool use_core_functionality, bool use_gs, bool use_ts, 1110 bool fetch_culldistance_from_fs) 1111 { 1112 deinitPO(); 1113 1114 /* Form the vertex shader */ 1115 glw::GLuint clipdistances_input_size = 1116 clipdistances_array_size > 0 ? clipdistances_array_size : 1; /* Avoid zero-sized array compilation error */ 1117 glw::GLuint culldistances_input_size = 1118 culldistances_array_size > 0 ? culldistances_array_size : 1; /* Avoid zero-sized array compilation error */ 1119 static const glw::GLchar* dynamic_array_setters = 1120 "\n" 1121 "#if TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES\n" 1122 " for (int n_clipdistance_entry = 0;\n" 1123 " n_clipdistance_entry < TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES;\n" 1124 " ++n_clipdistance_entry)\n" 1125 " {\n" 1126 " ASSIGN_CLIP_DISTANCE(n_clipdistance_entry);\n" 1127 " }\n" 1128 "#endif" 1129 "\n" 1130 "#if TEMPLATE_N_GL_CULLDISTANCE_ENTRIES \n" 1131 " for (int n_culldistance_entry = 0;\n" 1132 " n_culldistance_entry < TEMPLATE_N_GL_CULLDISTANCE_ENTRIES;\n" 1133 " ++n_culldistance_entry)\n" 1134 " {\n" 1135 " ASSIGN_CULL_DISTANCE(n_culldistance_entry);\n" 1136 " }\n" 1137 "#endif\n"; 1138 1139 static const glw::GLchar* core_functionality = "#version 450\n"; 1140 1141 static const glw::GLchar* extention_functionality = "#version 440\n" 1142 "\n" 1143 "#extension GL_ARB_cull_distance : require\n" 1144 "\n" 1145 "#ifndef GL_ARB_cull_distance\n" 1146 " #error GL_ARB_cull_distance is undefined\n" 1147 "#endif\n"; 1148 1149 static const glw::GLchar* fetch_function = "highp float fetch()\n" 1150 "{\n" 1151 " highp float sum = 0.0;\n" 1152 "\n" 1153 "TEMPLATE_SUM_SETTER" 1154 "\n" 1155 " return sum / TEMPLATE_SUM_DIVIDER;\n" 1156 "}\n" 1157 "\n" 1158 "#define ASSIGN_RETURN_VALUE fetch()"; 1159 1160 static const glw::GLchar* fs_template = "TEMPLATE_HEADER_DECLARATION\n" 1161 "\n" 1162 "TEMPLATE_REDECLARE_CLIPDISTANCE\n" 1163 "TEMPLATE_REDECLARE_CULLDISTANCE\n" 1164 "\n" 1165 "TEMPLATE_ASSIGN_RETURN_VALUE\n" 1166 "\n" 1167 "out vec4 out_fs;\n" 1168 "\n" 1169 "/* Fragment shader main function */\n" 1170 "void main()\n" 1171 "{\n" 1172 " out_fs = vec4(ASSIGN_RETURN_VALUE, 1.0, 1.0, 1.0);\n" 1173 "}\n"; 1174 1175 static const glw::GLchar* gs_template = "TEMPLATE_HEADER_DECLARATION\n" 1176 "\n" 1177 "TEMPLATE_LAYOUT_IN\n" 1178 "TEMPLATE_LAYOUT_OUT\n" 1179 "\n" 1180 "TEMPLATE_REDECLARE_CLIPDISTANCE\n" 1181 "TEMPLATE_REDECLARE_CULLDISTANCE\n" 1182 "\n" 1183 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n" 1184 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n" 1185 "\n" 1186 "/* Geometry shader (passthrough) main function */\n" 1187 "void main()\n" 1188 "{\n" 1189 " for (int n_vertex_index = 0;\n" 1190 " n_vertex_index < gl_in.length();\n" 1191 " n_vertex_index ++)\n" 1192 " {\n" 1193 " gl_Position = gl_in[n_vertex_index].gl_Position;\n" 1194 "\n" 1195 " TEMPLATE_ARRAY_SETTERS\n" 1196 "\n" 1197 " EmitVertex();\n" 1198 " }\n" 1199 "\n" 1200 " EndPrimitive();\n" 1201 "}\n"; 1202 1203 static const glw::GLchar* tc_template = 1204 "TEMPLATE_HEADER_DECLARATION\n" 1205 "\n" 1206 "TEMPLATE_LAYOUT_OUT\n" 1207 "\n" 1208 "out gl_PerVertex {\n" 1209 "TEMPLATE_REDECLARE_CLIPDISTANCE\n" 1210 "TEMPLATE_REDECLARE_CULLDISTANCE\n" 1211 "vec4 gl_Position;\n" 1212 "} gl_out[];\n" 1213 "\n" 1214 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n" 1215 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n" 1216 "\n" 1217 "/* Tesselation control shader main function */\n" 1218 "void main()\n" 1219 "{\n" 1220 " gl_TessLevelInner[0] = 1.0;\n" 1221 " gl_TessLevelInner[1] = 1.0;\n" 1222 " gl_TessLevelOuter[0] = 1.0;\n" 1223 " gl_TessLevelOuter[1] = 1.0;\n" 1224 " gl_TessLevelOuter[2] = 1.0;\n" 1225 " gl_TessLevelOuter[3] = 1.0;\n" 1226 " /* Clipdistance and culldistance array setters */\n" 1227 " {\n" 1228 " TEMPLATE_ARRAY_SETTERS\n" 1229 " }\n" 1230 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 1231 "}\n"; 1232 1233 static const glw::GLchar* te_template = "TEMPLATE_HEADER_DECLARATION\n" 1234 "\n" 1235 "TEMPLATE_LAYOUT_IN\n" 1236 "\n" 1237 "in gl_PerVertex {\n" 1238 "TEMPLATE_REDECLARE_IN_CLIPDISTANCE\n" 1239 "TEMPLATE_REDECLARE_IN_CULLDISTANCE\n" 1240 "vec4 gl_Position;\n" 1241 "} gl_in[];\n" 1242 "\n" 1243 "TEMPLATE_REDECLARE_CLIPDISTANCE\n" 1244 "TEMPLATE_REDECLARE_CULLDISTANCE\n" 1245 "\n" 1246 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n" 1247 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n" 1248 "\n" 1249 "/* Tesselation evaluation shader main function */\n" 1250 "void main()\n" 1251 "{\n" 1252 " /* Clipdistance and culldistance array setters */\n" 1253 " {\n" 1254 " TEMPLATE_ARRAY_SETTERS\n" 1255 " }\n" 1256 " gl_Position = TEMPLATE_OUT_FORMULA;\n" 1257 "}\n"; 1258 1259 static const glw::GLchar* vs_template = 1260 "TEMPLATE_HEADER_DECLARATION\n" 1261 "\n" 1262 "in float clipdistance_data[TEMPLATE_CLIPDISTANCE_INPUT_SIZE];\n" 1263 "in float culldistance_data[TEMPLATE_CULLDISTANCE_INPUT_SIZE];\n" 1264 "in vec2 position;\n" 1265 "\n" 1266 "TEMPLATE_REDECLARE_CLIPDISTANCE\n" 1267 "TEMPLATE_REDECLARE_CULLDISTANCE\n" 1268 "\n" 1269 "#define ASSIGN_CLIP_DISTANCE(IDX) TEMPLATE_ASSIGN_CLIP_DISTANCE\n" 1270 "#define ASSIGN_CULL_DISTANCE(IDX) TEMPLATE_ASSIGN_CULL_DISTANCE\n" 1271 "\n" 1272 "/* Vertex shader main function */\n" 1273 "void main()\n" 1274 "{\n" 1275 " /* Clipdistance and culldistance array setters */\n" 1276 " {\n" 1277 " TEMPLATE_ARRAY_SETTERS\n" 1278 " }\n" 1279 " gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, 0.0, 1.0);\n" 1280 "}\n"; 1281 1282 std::string* shader_body_string_fs = DE_NULL; 1283 std::string* shader_body_string_gs = DE_NULL; 1284 std::string* shader_body_string_tc = DE_NULL; 1285 std::string* shader_body_string_te = DE_NULL; 1286 std::string* shader_body_string_vs = DE_NULL; 1287 std::string shader_header_declaration = use_core_functionality ? core_functionality : extention_functionality; 1288 1289 struct _shaders_configuration 1290 { 1291 glw::GLenum type; 1292 const glw::GLchar* shader_template; 1293 std::string body; 1294 const bool use; 1295 } shaders_configuration[] = { { 1296 GL_FRAGMENT_SHADER, fs_template, std::string(), true, 1297 }, 1298 { 1299 GL_GEOMETRY_SHADER, gs_template, std::string(), use_gs, 1300 }, 1301 { 1302 GL_TESS_CONTROL_SHADER, tc_template, std::string(), use_ts, 1303 }, 1304 { 1305 GL_TESS_EVALUATION_SHADER, te_template, std::string(), use_ts, 1306 }, 1307 { 1308 GL_VERTEX_SHADER, vs_template, std::string(), true, 1309 } }; 1310 1311 const glw::GLuint n_shaders_configuration = sizeof(shaders_configuration) / sizeof(shaders_configuration[0]); 1312 1313 /* Construct shader bodies out of templates */ 1314 for (glw::GLuint n_shader_index = 0; n_shader_index < n_shaders_configuration; n_shader_index++) 1315 { 1316 if (shaders_configuration[n_shader_index].use) 1317 { 1318 std::string array_setters; 1319 std::string clipdistance_array_declaration; 1320 std::string culldistance_array_declaration; 1321 std::string clipdistance_in_array_declaration; 1322 std::string culldistance_in_array_declaration; 1323 std::string& shader_source = shaders_configuration[n_shader_index].body; 1324 1325 /* Copy template into shader body source */ 1326 shader_source = shaders_configuration[n_shader_index].shader_template; 1327 1328 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_HEADER_DECLARATION"), 1329 shader_header_declaration); 1330 1331 /* Shader-specific actions */ 1332 switch (shaders_configuration[n_shader_index].type) 1333 { 1334 case GL_FRAGMENT_SHADER: 1335 { 1336 shader_body_string_fs = &shaders_configuration[n_shader_index].body; 1337 1338 if (fetch_culldistance_from_fs) 1339 { 1340 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"), 1341 std::string(fetch_function)); 1342 1343 std::string fetch_sum_setters = ""; 1344 for (glw::GLuint i = 0; i < clipdistances_array_size; ++i) 1345 { 1346 fetch_sum_setters.append(" sum += abs(gl_ClipDistance["); 1347 fetch_sum_setters.append(CullDistance::Utilities::intToString(i)); 1348 fetch_sum_setters.append("]) * "); 1349 fetch_sum_setters.append(CullDistance::Utilities::intToString(i + 1)); 1350 fetch_sum_setters.append(".0;\n"); 1351 } 1352 1353 fetch_sum_setters.append("\n"); 1354 1355 for (glw::GLuint i = 0; i < culldistances_array_size; ++i) 1356 { 1357 fetch_sum_setters.append(" sum += abs(gl_CullDistance["); 1358 fetch_sum_setters.append(CullDistance::Utilities::intToString(i)); 1359 fetch_sum_setters.append("]) * "); 1360 fetch_sum_setters.append( 1361 CullDistance::Utilities::intToString(i + 1 + clipdistances_array_size)); 1362 fetch_sum_setters.append(".0;\n"); 1363 } 1364 1365 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_SUM_SETTER"), 1366 std::string(fetch_sum_setters)); 1367 CullDistance::Utilities::replaceAll( 1368 shader_source, std::string("TEMPLATE_SUM_DIVIDER"), 1369 std::string(CullDistance::Utilities::intToString( 1370 (clipdistances_array_size + culldistances_array_size) * 1371 ((clipdistances_array_size + culldistances_array_size + 1)))) 1372 .append(".0")); 1373 } 1374 else 1375 { 1376 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_RETURN_VALUE"), 1377 std::string("#define ASSIGN_RETURN_VALUE 1.0")); 1378 } 1379 1380 break; 1381 } 1382 1383 case GL_GEOMETRY_SHADER: 1384 { 1385 shader_body_string_gs = &shaders_configuration[n_shader_index].body; 1386 1387 CullDistance::Utilities::replaceAll( 1388 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"), 1389 std::string("gl_ClipDistance[IDX] = gl_in[n_vertex_index].gl_ClipDistance[IDX]")); 1390 CullDistance::Utilities::replaceAll( 1391 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"), 1392 std::string("gl_CullDistance[IDX] = gl_in[n_vertex_index].gl_CullDistance[IDX]")); 1393 1394 switch (primitive_mode) 1395 { 1396 case PRIMITIVE_MODE_LINES: 1397 { 1398 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"), 1399 std::string("layout(lines) in;")); 1400 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"), 1401 std::string("layout(line_strip, max_vertices = 2) out;")); 1402 1403 break; 1404 } 1405 case PRIMITIVE_MODE_POINTS: 1406 { 1407 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"), 1408 std::string("layout(points) in;")); 1409 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"), 1410 std::string("layout(points, max_vertices = 1) out;")); 1411 1412 break; 1413 } 1414 case PRIMITIVE_MODE_TRIANGLES: 1415 { 1416 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"), 1417 std::string("layout(triangles) in;")); 1418 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"), 1419 std::string("layout(triangle_strip, max_vertices = 3) out;")); 1420 1421 break; 1422 } 1423 default: 1424 TCU_FAIL("Unknown primitive mode"); 1425 } 1426 1427 break; 1428 } 1429 1430 case GL_TESS_CONTROL_SHADER: 1431 { 1432 shader_body_string_tc = &shaders_configuration[n_shader_index].body; 1433 1434 CullDistance::Utilities::replaceAll( 1435 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"), 1436 std::string( 1437 "gl_out[gl_InvocationID].gl_ClipDistance[IDX] = gl_in[gl_InvocationID].gl_ClipDistance[IDX]")); 1438 CullDistance::Utilities::replaceAll( 1439 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"), 1440 std::string( 1441 "gl_out[gl_InvocationID].gl_CullDistance[IDX] = gl_in[gl_InvocationID].gl_CullDistance[IDX]")); 1442 1443 switch (primitive_mode) 1444 { 1445 case PRIMITIVE_MODE_LINES: 1446 { 1447 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"), 1448 std::string("layout(vertices = 2) out;")); 1449 1450 break; 1451 } 1452 case PRIMITIVE_MODE_POINTS: 1453 { 1454 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"), 1455 std::string("layout(vertices = 1) out;")); 1456 1457 break; 1458 } 1459 case PRIMITIVE_MODE_TRIANGLES: 1460 { 1461 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_OUT"), 1462 std::string("layout(vertices = 3) out;")); 1463 1464 break; 1465 } 1466 default: 1467 TCU_FAIL("Unknown primitive mode"); 1468 } 1469 1470 break; 1471 } 1472 1473 case GL_TESS_EVALUATION_SHADER: 1474 { 1475 shader_body_string_te = &shaders_configuration[n_shader_index].body; 1476 1477 switch (primitive_mode) 1478 { 1479 case PRIMITIVE_MODE_LINES: 1480 { 1481 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"), 1482 std::string("layout(isolines) in;")); 1483 CullDistance::Utilities::replaceAll( 1484 shader_source, std::string("TEMPLATE_OUT_FORMULA"), 1485 std::string("mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x)")); 1486 CullDistance::Utilities::replaceAll( 1487 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"), 1488 std::string("gl_ClipDistance[IDX] = mix(gl_in[0].gl_ClipDistance[IDX], " 1489 "gl_in[1].gl_ClipDistance[IDX], gl_TessCoord.x)")); 1490 CullDistance::Utilities::replaceAll( 1491 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"), 1492 std::string("gl_CullDistance[IDX] = mix(gl_in[0].gl_CullDistance[IDX], " 1493 "gl_in[1].gl_CullDistance[IDX], gl_TessCoord.x)")); 1494 1495 break; 1496 } 1497 case PRIMITIVE_MODE_POINTS: 1498 { 1499 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"), 1500 std::string("layout(isolines, point_mode) in;")); 1501 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_OUT_FORMULA"), 1502 std::string("gl_in[0].gl_Position")); 1503 CullDistance::Utilities::replaceAll( 1504 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"), 1505 std::string("gl_ClipDistance[IDX] = gl_in[0].gl_ClipDistance[IDX]")); 1506 CullDistance::Utilities::replaceAll( 1507 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"), 1508 std::string("gl_CullDistance[IDX] = gl_in[0].gl_CullDistance[IDX]")); 1509 1510 break; 1511 } 1512 case PRIMITIVE_MODE_TRIANGLES: 1513 { 1514 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_LAYOUT_IN"), 1515 std::string("layout(triangles) in;")); 1516 CullDistance::Utilities::replaceAll( 1517 shader_source, std::string("TEMPLATE_OUT_FORMULA"), 1518 std::string("vec4(mat3(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, " 1519 "gl_in[2].gl_Position.xyz) * gl_TessCoord, 1.0)")); 1520 CullDistance::Utilities::replaceAll( 1521 shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"), 1522 std::string("gl_ClipDistance[IDX] = dot(vec3(gl_in[0].gl_ClipDistance[IDX], " 1523 "gl_in[1].gl_ClipDistance[IDX], gl_in[2].gl_ClipDistance[IDX]), gl_TessCoord)")); 1524 CullDistance::Utilities::replaceAll( 1525 shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"), 1526 std::string("gl_CullDistance[IDX] = dot(vec3(gl_in[0].gl_CullDistance[IDX], " 1527 "gl_in[1].gl_CullDistance[IDX], gl_in[2].gl_CullDistance[IDX]), gl_TessCoord)")); 1528 1529 break; 1530 } 1531 default: 1532 TCU_FAIL("Unknown primitive mode"); 1533 } 1534 1535 break; 1536 } 1537 1538 case GL_VERTEX_SHADER: 1539 { 1540 shader_body_string_vs = &shaders_configuration[n_shader_index].body; 1541 1542 /* Specify input data size for clipdistances data */ 1543 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CLIPDISTANCE_INPUT_SIZE"), 1544 CullDistance::Utilities::intToString(clipdistances_input_size)); 1545 1546 /* Specify input data size for culldistances data */ 1547 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_CULLDISTANCE_INPUT_SIZE"), 1548 CullDistance::Utilities::intToString(culldistances_input_size)); 1549 1550 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CLIP_DISTANCE"), 1551 std::string("gl_ClipDistance[IDX] = clipdistance_data[IDX]")); 1552 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ASSIGN_CULL_DISTANCE"), 1553 std::string("gl_CullDistance[IDX] = culldistance_data[IDX]")); 1554 1555 break; 1556 } 1557 1558 default: 1559 TCU_FAIL("Unknown shader type"); 1560 } 1561 1562 /* Adjust clipdistances declaration */ 1563 if (redeclare_clipdistances && clipdistances_array_size > 0) 1564 { 1565 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER) 1566 { 1567 if (fetch_culldistance_from_fs) 1568 { 1569 clipdistance_array_declaration = 1570 std::string("in float gl_ClipDistance[") + 1571 CullDistance::Utilities::intToString(clipdistances_array_size) + std::string("];"); 1572 } 1573 } 1574 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER) 1575 { 1576 clipdistance_array_declaration = std::string("float gl_ClipDistance[") + 1577 CullDistance::Utilities::intToString(clipdistances_array_size) + 1578 std::string("];"); 1579 } 1580 else 1581 { 1582 clipdistance_array_declaration = std::string("out float gl_ClipDistance[") + 1583 CullDistance::Utilities::intToString(clipdistances_array_size) + 1584 std::string("];"); 1585 clipdistance_in_array_declaration = std::string("in float gl_ClipDistance[") + 1586 CullDistance::Utilities::intToString(clipdistances_array_size) + 1587 std::string("];"); 1588 } 1589 } 1590 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CLIPDISTANCE"), 1591 clipdistance_array_declaration); 1592 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CLIPDISTANCE"), 1593 clipdistance_in_array_declaration); 1594 1595 /* Adjust culldistances declaration */ 1596 if (redeclare_culldistances && culldistances_array_size > 0) 1597 { 1598 if (shaders_configuration[n_shader_index].type == GL_FRAGMENT_SHADER) 1599 { 1600 if (fetch_culldistance_from_fs) 1601 { 1602 culldistance_array_declaration = 1603 std::string("in float gl_CullDistance[") + 1604 CullDistance::Utilities::intToString(culldistances_array_size) + std::string("];"); 1605 } 1606 } 1607 else if (shaders_configuration[n_shader_index].type == GL_TESS_CONTROL_SHADER) 1608 { 1609 culldistance_array_declaration = std::string("float gl_CullDistance[") + 1610 CullDistance::Utilities::intToString(culldistances_array_size) + 1611 std::string("];"); 1612 } 1613 else 1614 { 1615 culldistance_array_declaration = std::string("out float gl_CullDistance[") + 1616 CullDistance::Utilities::intToString(culldistances_array_size) + 1617 std::string("];"); 1618 culldistance_in_array_declaration = std::string("in float gl_CullDistance[") + 1619 CullDistance::Utilities::intToString(culldistances_array_size) + 1620 std::string("];"); 1621 } 1622 } 1623 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_CULLDISTANCE"), 1624 culldistance_array_declaration); 1625 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_REDECLARE_IN_CULLDISTANCE"), 1626 culldistance_in_array_declaration); 1627 1628 /* Adjust clip/cull distances setters */ 1629 if (dynamic_index_writes) 1630 { 1631 array_setters = dynamic_array_setters; 1632 1633 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CLIPDISTANCE_ENTRIES"), 1634 CullDistance::Utilities::intToString(clipdistances_array_size)); 1635 CullDistance::Utilities::replaceAll(array_setters, std::string("TEMPLATE_N_GL_CULLDISTANCE_ENTRIES"), 1636 CullDistance::Utilities::intToString(culldistances_array_size)); 1637 } 1638 else 1639 { 1640 std::stringstream static_array_setters_sstream; 1641 1642 static_array_setters_sstream << "\n"; 1643 1644 for (glw::GLuint clipdistances_array_entry = 0; clipdistances_array_entry < clipdistances_array_size; 1645 ++clipdistances_array_entry) 1646 { 1647 static_array_setters_sstream << " ASSIGN_CLIP_DISTANCE(" << clipdistances_array_entry 1648 << ");\n"; 1649 } 1650 1651 static_array_setters_sstream << "\n"; 1652 1653 for (glw::GLuint culldistances_array_entry = 0; culldistances_array_entry < culldistances_array_size; 1654 ++culldistances_array_entry) 1655 { 1656 static_array_setters_sstream << " ASSIGN_CULL_DISTANCE(" << culldistances_array_entry 1657 << ");\n"; 1658 } 1659 1660 array_setters = static_array_setters_sstream.str(); 1661 } 1662 1663 CullDistance::Utilities::replaceAll(shader_source, std::string("TEMPLATE_ARRAY_SETTERS"), array_setters); 1664 } 1665 } 1666 1667 /* Build the geometry shader */ 1668 CullDistance::Utilities::buildProgram( 1669 m_context.getRenderContext().getFunctions(), m_testCtx, DE_NULL, /* Compute shader */ 1670 shader_body_string_fs != DE_NULL ? shader_body_string_fs->c_str() : 1671 DE_NULL, /* Fragment shader */ 1672 shader_body_string_gs != DE_NULL ? shader_body_string_gs->c_str() : 1673 DE_NULL, /* Geometry shader */ 1674 shader_body_string_tc != DE_NULL ? shader_body_string_tc->c_str() : 1675 DE_NULL, /* Tesselation control shader */ 1676 shader_body_string_te != DE_NULL ? shader_body_string_te->c_str() : 1677 DE_NULL, /* Tesselation evaluation shader */ 1678 shader_body_string_vs != DE_NULL ? shader_body_string_vs->c_str() : 1679 DE_NULL, /* Vertex shader */ 1680 0, /* Transform feedback varyings count */ 1681 DE_NULL, /* Transform feedback varyings */ 1682 &m_po_id /* Program object id */ 1683 ); 1684 } 1685 1686 /** Generates primitive data required to test a case with specified 1687 * gl_ClipDistance and glCullDistance array sizes for specified 1688 * primitive mode. Generated primitive data is stored in m_bo_data 1689 * as well uploaded into buffer specified in m_bo_id buffer. 1690 * Also the procedure binds vertex attribute locations to 1691 * program object m_po_id. 1692 * 1693 * @param clipdistances_array_size gl_ClipDistance array size. Can be 0. 1694 * @param culldistances_array_size gl_CullDistance array size. Can be 0. 1695 * @param _primitive_mode Primitives to be generated. Can be: 1696 * PRIMITIVE_MODE_POINTS, 1697 * PRIMITIVE_MODE_LINES, 1698 * PRIMITIVE_MODE_TRIANGLES. 1699 */ 1700 void CullDistance::FunctionalTest::configureVAO(glw::GLuint clipdistances_array_size, 1701 glw::GLuint culldistances_array_size, _primitive_mode primitive_mode) 1702 { 1703 /* Detailed test description. 1704 * 1705 * configureVAO() generates primitives layouted in grid. Primitve 1706 * consists of up to 3 vertices and each vertex is accompanied by: 1707 * - array of clipdistances (clipdistances_array_size floats); 1708 * - array of culldistances (culldistances_array_size floats); 1709 * - rendering position coordinates (x and y); 1710 * - check position coordinates (x and y). 1711 * 1712 * The grid has following layout: 1713 * 1714 * Grid | gl_CullDistance[x] | 1715 * | 0 .. culldistances_array_size - 1 | 1716 * | 0th | 1st | 2nd | .......... | 1717 * ---------------------------+-------+-------+-------+------------+ 1718 * 0th gl_ClipDistance |Subgrid|Subgrid|Subgrid| .......... | 1719 * 1st gl_ClipDistance |Subgrid|Subgrid|Subgrid| .......... | 1720 * ... | ... | ... | ... | .......... | 1721 * y-th gl_ClipDistance |Subgrid|Subgrid|Subgrid| .......... | 1722 * ... | ... | ... | ... | .......... | 1723 * clipdistances_array_size-1 |Subgrid|Subgrid|Subgrid| .......... | 1724 * 1725 * Each grid cell contains subgrid of 3*3 items in size with following 1726 * structure: 1727 * 1728 * Subgrid | x-th gl_CullDistance test | 1729 * | | 1730 * y-th | all vertices | 0th vertex | all vertices | 1731 * gl_ClipDistance| in primitive | in primitive | in primitive | 1732 * tests | dist[x] > 0 | dist[x] < 0 | dist[x] < 0 | 1733 * ---------------+--------------+--------------+--------------+ 1734 * all vertices| primitive #0 | primitive #1 | primitive #2 | 1735 * in primitive| | | | 1736 * dist[y] > 0 | visible | visible | culled | 1737 * ---------------+--------------+--------------+--------------+ 1738 * 0th vertex | primitive #3 | primitive #4 | primitive #5 | 1739 * in primitive| 0th vertex | 0th vertex | | 1740 * dist[y] < 0 | clipped | clipped | culled | 1741 * ---------------+--------------+--------------+--------------+ 1742 * all vertices| primitive #6 | primitive #7 | primitive #8 | 1743 * in primitive| | | | 1744 * dist[y] < 0 | clipped | clipped | culled | 1745 * ---------------+--------------+--------------+--------------+ 1746 * 1747 * Expected rendering result is specified in cell bottom. 1748 * It can be one of the following: 1749 * - "visible" means the primitive is not affected neither by gl_CullDistance 1750 * nor by gl_ClipDistance and rendered as a whole; 1751 * - "clipped" for the vertex means the vertex is not rendered, while other 1752 * primitive vertices and some filling fragments are rendered; 1753 * - "clipped" for primitive means none of primitive vertices and fragments 1754 * are rendered and thus primitive is not rendered and is invisible; 1755 * - "culled" means, that neither primitive vertices, nor primitive filling 1756 * fragments are rendered (primitive is invisible). 1757 * 1758 * All subgrid items contain same primitive rendered. Depending on 1759 * test case running it would be either triangle, or line, or point: 1760 * 1761 * triangle line point 1762 * 8x8 box 8x8 box 3x3 box 1763 * ........ ........ ... 1764 * .0----2. .0...... .0. 1765 * ..\@@@|. ..\..... ... 1766 * ...\@@|. ...\.... 1767 * ....\@|. ....\... 1768 * .....\|. .....\.. 1769 * ......1. ......1. 1770 * ........ ........ 1771 * 1772 * where 0 - is a 0th vertex primitive 1773 * 1 - is a 1st vertex primitive 1774 * 2 - is a 2nd vertex primitive 1775 * 1776 * The culldistances_array_size can be 0. In that case, grid height 1777 * is assumed equal to 1, but 0 glCullDistances is specified. 1778 * Similar handled clipdistances_array_size. 1779 * 1780 * The data generated is used and checked in executeRenderTest(). 1781 * After rendering each primitive vertex is tested: 1782 * - if it is rendered, if it have to be rendered (according distance); 1783 * - if it is not rendered, if it have to be not rendered (according distance). 1784 * Due to "top-left" rasterization rule check position is 1785 * different from rendering vertex position. 1786 * 1787 * Also one pixel width guarding box is checked to be clear. 1788 */ 1789 1790 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1791 const glw::GLuint n_sub_grid_cells = 3; /* Tested distance is positive for all vertices in the primitive; 1792 * Tested distance is negative for 0th vertex in the primitive; 1793 * Tested distance is negative for all vertices in the primitive; 1794 */ 1795 const glw::GLuint sub_grid_cell_size = 1796 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 8 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 3 : 8); 1797 1798 const glw::GLuint grid_cell_size = n_sub_grid_cells * sub_grid_cell_size; 1799 const glw::GLuint n_primitive_vertices = 1800 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3); 1801 1802 const glw::GLuint n_grid_cells_x = culldistances_array_size != 0 ? culldistances_array_size : 1; 1803 const glw::GLuint n_grid_cells_y = clipdistances_array_size != 0 ? clipdistances_array_size : 1; 1804 const glw::GLuint n_pervertex_float_attributes = clipdistances_array_size + culldistances_array_size + 1805 2 /* vertex' draw x, y */ + 2 /* vertex' checkpoint x, y */; 1806 const glw::GLuint n_primitives_total = n_grid_cells_x * n_sub_grid_cells * n_grid_cells_y * n_sub_grid_cells; 1807 const glw::GLuint n_vertices_total = n_primitives_total * n_primitive_vertices; 1808 const glw::GLuint offsets_line_draw_x[2] = { 1809 1, sub_grid_cell_size - 1 1810 }; /* vertex x offsets to subgrid cell origin for line primitive */ 1811 const glw::GLuint offsets_line_draw_y[2] = { 1812 1, sub_grid_cell_size - 1 1813 }; /* vertex y offsets to subgrid cell origin for line primitive */ 1814 const glw::GLuint offsets_line_checkpoint_x[2] = { 1815 1, sub_grid_cell_size - 2 1816 }; /* pixel x offsets to subgrid cell origin for line primitive */ 1817 const glw::GLuint offsets_line_checkpoint_y[2] = { 1818 1, sub_grid_cell_size - 2 1819 }; /* pixel y offsets to subgrid cell origin for line primitive */ 1820 const glw::GLuint offsets_point_draw_x[1] = { 1821 1 1822 }; /* vertex x offsets to subgrid cell origin for point primitive */ 1823 const glw::GLuint offsets_point_draw_y[1] = { 1824 1 1825 }; /* vertex y offsets to subgrid cell origin for point primitive */ 1826 const glw::GLuint offsets_point_checkpoint_x[1] = { 1827 1 1828 }; /* pixel x offsets to subgrid cell origin for point primitive */ 1829 const glw::GLuint offsets_point_checkpoint_y[1] = { 1830 1 1831 }; /* pixel y offsets to subgrid cell origin for point primitive */ 1832 const glw::GLuint offsets_triangle_draw_x[3] = { 1833 1, sub_grid_cell_size - 1, sub_grid_cell_size - 1 1834 }; /* vertex x offsets to subgrid cell origin for triangle primitive */ 1835 const glw::GLuint offsets_triangle_draw_y[3] = { 1836 1, sub_grid_cell_size - 1, 1 1837 }; /* vertex y offsets to subgrid cell origin for triangle primitive */ 1838 const glw::GLuint offsets_triangle_checkpoint_x[3] = { 1839 1, sub_grid_cell_size - 2, sub_grid_cell_size - 2 1840 }; /* pixel x offsets to subgrid cell origin for triangle primitive */ 1841 const glw::GLuint offsets_triangle_checkpoint_y[3] = { 1842 1, sub_grid_cell_size - 2, 1 1843 }; /* pixel y offsets to subgrid cell origin for triangle primitive */ 1844 const glw::GLfloat offsets_pixel_center_x = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0; 1845 const glw::GLfloat offsets_pixel_center_y = (primitive_mode == PRIMITIVE_MODE_POINTS) ? 0.5f : 0; 1846 /* Clear data left from previous tests. */ 1847 m_bo_data.clear(); 1848 1849 /* No data to render */ 1850 m_render_primitives = 0; 1851 m_render_vertices = 0; 1852 1853 /* Preallocate space for bo_points_count */ 1854 m_bo_data.reserve(n_vertices_total * n_pervertex_float_attributes); 1855 1856 /* Generate test data for cell_y-th clip distance */ 1857 for (glw::GLuint cell_y = 0; cell_y < n_grid_cells_y; cell_y++) 1858 { 1859 /* Generate test data for cell_x-th cull distance */ 1860 for (glw::GLuint cell_x = 0; cell_x < n_grid_cells_x; cell_x++) 1861 { 1862 /* Check clip distance sub cases: 1863 * 0. Tested distance is positive for all vertices in the primitive; 1864 * 1. Tested distance is negative for 0th vertex in the primitive; 1865 * 2. Tested distance is negative for all vertices in the primitive; 1866 */ 1867 for (glw::GLuint n_sub_cell_y = 0; n_sub_cell_y < n_sub_grid_cells; n_sub_cell_y++) 1868 { 1869 /* Check cull distance sub cases: 1870 * 0. Tested distance is positive for all vertices in the primitive; 1871 * 1. Tested distance is negative for 0th vertex in the primitive; 1872 * 2. Tested distance is negative for all vertices in the primitive; 1873 */ 1874 for (glw::GLuint n_sub_cell_x = 0; n_sub_cell_x < n_sub_grid_cells; n_sub_cell_x++) 1875 { 1876 /* Generate vertices in primitive */ 1877 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < n_primitive_vertices; 1878 n_primitive_vertex++) 1879 { 1880 /* Fill in clipdistance array for the n_primitive_vertex vertex in primitive */ 1881 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; 1882 n_clipdistance_entry++) 1883 { 1884 glw::GLfloat distance_value = 0.0f; 1885 bool negative = true; 1886 1887 /* Special approach to tested clipdistance entry. */ 1888 if (n_clipdistance_entry == cell_y) 1889 { 1890 /* The primitive vertex should be affected by the clip distance */ 1891 switch (n_sub_cell_y) 1892 { 1893 case 0: 1894 { 1895 /* subgrid row 0: all primitive vertices have tested distance value positive */ 1896 negative = false; 1897 1898 break; 1899 } 1900 case 1: 1901 { 1902 /* subgrid row 1: tested distance value for 0th primitive vertex is negative, 1903 all other primitive vertices have tested distance value positive */ 1904 negative = (n_primitive_vertex == 0) ? true : false; 1905 1906 break; 1907 } 1908 case 2: 1909 { 1910 /* subgrid row 2: tested distance value is negative for all primitive vertices */ 1911 negative = true; 1912 1913 break; 1914 } 1915 default: 1916 TCU_FAIL("Invalid subgrid cell index"); 1917 } 1918 1919 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_clipdistance_entry + 1); 1920 } 1921 else 1922 { 1923 /* For clip distances other than tested: assign positive value to avoid its influence. */ 1924 distance_value = glw::GLfloat(clipdistances_array_size + n_clipdistance_entry + 1); 1925 } 1926 1927 m_bo_data.push_back(distance_value / glw::GLfloat(clipdistances_array_size)); 1928 } /* for (all gl_ClipDistance[] array values) */ 1929 1930 /* Fill in culldistance array for the n_primitive_vertex vertex in primitive */ 1931 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; 1932 n_culldistance_entry++) 1933 { 1934 glw::GLfloat distance_value = 0.0f; 1935 bool negative = true; 1936 1937 /* Special approach to tested culldistance entry. */ 1938 if (n_culldistance_entry == cell_x) 1939 { 1940 /* The primitive vertex should be affected by the cull distance */ 1941 switch (n_sub_cell_x) 1942 { 1943 case 0: 1944 { 1945 /* subgrid column 0: all primitive vertices have tested distance value positive */ 1946 negative = false; 1947 1948 break; 1949 } 1950 case 1: 1951 { 1952 /* subgrid column 1: tested distance value for 0th primitive vertex is negative, 1953 all other primitive vertices have tested distance value positive */ 1954 negative = (n_primitive_vertex == 0) ? true : false; 1955 1956 break; 1957 } 1958 case 2: 1959 { 1960 /* subgrid column 2: tested distance value is negative for all primitive vertices */ 1961 negative = true; 1962 1963 break; 1964 } 1965 default: 1966 TCU_FAIL("Invalid subgrid cell index"); 1967 } 1968 1969 distance_value = (negative ? -1.0f : 1.0f) * glw::GLfloat(n_culldistance_entry + 1); 1970 } 1971 else 1972 { 1973 /* For cull distances other than tested: assign 0th vertex negative value, 1974 to check absence of between-distances influence. */ 1975 if (n_primitive_vertices > 1 && n_primitive_vertex == 0) 1976 { 1977 distance_value = -glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1); 1978 } 1979 else 1980 { 1981 /* This culldistance is out of interest: assign positive value. */ 1982 distance_value = glw::GLfloat(culldistances_array_size + n_culldistance_entry + 1); 1983 } 1984 } 1985 1986 m_bo_data.push_back(distance_value / glw::GLfloat(culldistances_array_size)); 1987 } /* for (all gl_CullDistance[] array values) */ 1988 1989 /* Generate primitve vertex draw and checkpoint coordinates */ 1990 glw::GLint vertex_draw_pixel_offset_x = 0; 1991 glw::GLint vertex_draw_pixel_offset_y = 0; 1992 glw::GLint vertex_checkpoint_pixel_offset_x = 0; 1993 glw::GLint vertex_checkpoint_pixel_offset_y = 0; 1994 1995 switch (primitive_mode) 1996 { 1997 case PRIMITIVE_MODE_LINES: 1998 { 1999 vertex_draw_pixel_offset_x = offsets_line_draw_x[n_primitive_vertex]; 2000 vertex_draw_pixel_offset_y = offsets_line_draw_y[n_primitive_vertex]; 2001 vertex_checkpoint_pixel_offset_x = offsets_line_checkpoint_x[n_primitive_vertex]; 2002 vertex_checkpoint_pixel_offset_y = offsets_line_checkpoint_y[n_primitive_vertex]; 2003 2004 break; 2005 } 2006 2007 case PRIMITIVE_MODE_POINTS: 2008 { 2009 vertex_draw_pixel_offset_x = offsets_point_draw_x[n_primitive_vertex]; 2010 vertex_draw_pixel_offset_y = offsets_point_draw_y[n_primitive_vertex]; 2011 vertex_checkpoint_pixel_offset_x = offsets_point_checkpoint_x[n_primitive_vertex]; 2012 vertex_checkpoint_pixel_offset_y = offsets_point_checkpoint_y[n_primitive_vertex]; 2013 2014 break; 2015 } 2016 2017 case PRIMITIVE_MODE_TRIANGLES: 2018 { 2019 vertex_draw_pixel_offset_x = offsets_triangle_draw_x[n_primitive_vertex]; 2020 vertex_draw_pixel_offset_y = offsets_triangle_draw_y[n_primitive_vertex]; 2021 vertex_checkpoint_pixel_offset_x = offsets_triangle_checkpoint_x[n_primitive_vertex]; 2022 vertex_checkpoint_pixel_offset_y = offsets_triangle_checkpoint_y[n_primitive_vertex]; 2023 2024 break; 2025 } 2026 2027 default: 2028 TCU_FAIL("Unknown primitive mode"); 2029 } 2030 2031 /* Origin of sub_cell */ 2032 glw::GLint sub_cell_origin_x = cell_x * grid_cell_size + n_sub_cell_x * sub_grid_cell_size; 2033 glw::GLint sub_cell_origin_y = cell_y * grid_cell_size + n_sub_cell_y * sub_grid_cell_size; 2034 /* Normalized texture coordinates of vertex draw position. */ 2035 glw::GLfloat x = 2036 (glw::GLfloat(sub_cell_origin_x + vertex_draw_pixel_offset_x) + offsets_pixel_center_x) / 2037 glw::GLfloat(m_to_width); 2038 glw::GLfloat y = 2039 (glw::GLfloat(sub_cell_origin_y + vertex_draw_pixel_offset_y) + offsets_pixel_center_y) / 2040 glw::GLfloat(m_to_height); 2041 /* Normalized texture coordinates of vertex checkpoint position. */ 2042 glw::GLfloat checkpoint_x = glw::GLfloat(sub_cell_origin_x + vertex_checkpoint_pixel_offset_x) / 2043 glw::GLfloat(m_to_width); 2044 glw::GLfloat checkpoint_y = glw::GLfloat(sub_cell_origin_y + vertex_checkpoint_pixel_offset_y) / 2045 glw::GLfloat(m_to_height); 2046 2047 /* Add vertex draw coordinates into buffer. */ 2048 m_bo_data.push_back(x); 2049 m_bo_data.push_back(y); 2050 2051 /* Add vertex checkpoint coordinates into buffer. */ 2052 m_bo_data.push_back(checkpoint_x); 2053 m_bo_data.push_back(checkpoint_y); 2054 } /* for (all vertices in primitive) */ 2055 } /* for (all horizontal sub cells) */ 2056 } /* for (all vertical sub cells) */ 2057 } /* for (all horizontal cells) */ 2058 } /* for (all vertical cells) */ 2059 2060 /* Sanity check: make sure we pushed required amount of data */ 2061 DE_ASSERT(m_bo_data.size() == n_vertices_total * n_pervertex_float_attributes); 2062 2063 /* Save number of primitives to render */ 2064 m_render_primitives = n_primitives_total; 2065 m_render_vertices = n_vertices_total; 2066 m_sub_grid_cell_size = sub_grid_cell_size; 2067 2068 /* Copy the data to the buffer object */ 2069 gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id); 2070 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed."); 2071 2072 gl.bufferData(GL_ARRAY_BUFFER, m_bo_data.size() * sizeof(glw::GLfloat), &m_bo_data[0], GL_STATIC_DRAW); 2073 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed."); 2074 2075 DE_ASSERT(m_po_id != 0); 2076 2077 /* Bind VAO data to program */ 2078 glw::GLint po_clipdistance_array_location = -1; 2079 glw::GLint po_culldistance_array_location = -1; 2080 glw::GLint po_position_location = -1; 2081 2082 /* Retrieve clipdistance and culldistance attribute locations */ 2083 gl.bindVertexArray(m_vao_id); 2084 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); 2085 2086 po_clipdistance_array_location = gl.getAttribLocation(m_po_id, "clipdistance_data[0]"); 2087 po_culldistance_array_location = gl.getAttribLocation(m_po_id, "culldistance_data[0]"); 2088 po_position_location = gl.getAttribLocation(m_po_id, "position"); 2089 2090 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation() call(s) failed."); 2091 2092 if (clipdistances_array_size > 0) 2093 { 2094 DE_ASSERT(po_clipdistance_array_location != -1); 2095 } 2096 2097 if (culldistances_array_size > 0) 2098 { 2099 DE_ASSERT(po_culldistance_array_location != -1); 2100 } 2101 2102 DE_ASSERT(po_position_location != -1); 2103 2104 glw::GLintptr current_offset = 0; 2105 const glw::GLint stride = static_cast<glw::GLint>(n_pervertex_float_attributes * sizeof(glw::GLfloat)); 2106 2107 gl.bindVertexArray(m_vao_id); 2108 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed."); 2109 2110 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; ++n_clipdistance_entry) 2111 { 2112 gl.vertexAttribPointer(po_clipdistance_array_location + n_clipdistance_entry, 1, /* size */ 2113 GL_FLOAT, GL_FALSE, /* normalized */ 2114 stride, (const glw::GLvoid*)current_offset); 2115 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed."); 2116 2117 gl.enableVertexAttribArray(po_clipdistance_array_location + n_clipdistance_entry); 2118 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed."); 2119 2120 current_offset += sizeof(glw::GLfloat); 2121 } /* for (all clip distance array value attributes) */ 2122 2123 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; ++n_culldistance_entry) 2124 { 2125 gl.vertexAttribPointer(po_culldistance_array_location + n_culldistance_entry, 1, /* size */ 2126 GL_FLOAT, GL_FALSE, /* normalized */ 2127 stride, (const glw::GLvoid*)current_offset); 2128 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed."); 2129 2130 gl.enableVertexAttribArray(po_culldistance_array_location + n_culldistance_entry); 2131 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed."); 2132 2133 current_offset += sizeof(glw::GLfloat); 2134 } /* for (all cull distance array value attributes) */ 2135 2136 gl.vertexAttribPointer(po_position_location, 2, /* size */ 2137 GL_FLOAT, GL_FALSE, /* normalized */ 2138 stride, (const glw::GLvoid*)current_offset); 2139 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed"); 2140 2141 gl.enableVertexAttribArray(po_position_location); 2142 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed"); 2143 } 2144 2145 /** @brief Cull Distance Functional Test deinitialization */ 2146 void CullDistance::FunctionalTest::deinit() 2147 { 2148 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2149 2150 if (m_fbo_id != 0) 2151 { 2152 gl.deleteFramebuffers(1, &m_fbo_id); 2153 2154 m_fbo_id = 0; 2155 } 2156 2157 if (m_to_id != 0) 2158 { 2159 gl.deleteTextures(1, &m_to_id); 2160 2161 m_to_id = 0; 2162 } 2163 2164 if (m_vao_id != 0) 2165 { 2166 gl.deleteVertexArrays(1, &m_vao_id); 2167 2168 m_vao_id = 0; 2169 } 2170 2171 deinitPO(); 2172 } 2173 2174 /** @brief Cull Distance Functional Test deinitialization of OpenGL programs */ 2175 void CullDistance::FunctionalTest::deinitPO() 2176 { 2177 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2178 2179 if (m_po_id != 0) 2180 { 2181 gl.deleteProgram(m_po_id); 2182 2183 m_po_id = 0; 2184 } 2185 } 2186 2187 /** @brief Executes single render test case 2188 * 2189 * @param [in] clipdistances_array_size Size of gl_ClipDistance[] array 2190 * @param [in] culldistances_array_size Size of gl_CullDistance[] array 2191 * @param [in] primitive_mode Type of primitives to be rendered (see enum _primitive_mode) 2192 * @param [in] use_tesselation Indicate whether to use tessellation shader 2193 * @param [in] fetch_culldistance_from_fs Indicate whether to fetch gl_CullDistance and gl_ClipDistance values from the fragment shader 2194 */ 2195 void CullDistance::FunctionalTest::executeRenderTest(glw::GLuint clipdistances_array_size, 2196 glw::GLuint culldistances_array_size, 2197 _primitive_mode primitive_mode, bool use_tesselation, 2198 bool fetch_culldistance_from_fs) 2199 { 2200 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2201 glw::GLenum mode = GL_NONE; 2202 glw::GLuint n_clipped_vertices_real = 0; 2203 glw::GLuint n_culled_primitives_real = 0; 2204 glw::GLuint n_not_clipped_vertices_real = 0; 2205 const glw::GLuint primitive_vertices_count = 2206 ((primitive_mode == PRIMITIVE_MODE_LINES) ? 2 : (primitive_mode == PRIMITIVE_MODE_POINTS) ? 1 : 3); 2207 const glw::GLuint stride_in_floats = 2208 clipdistances_array_size + culldistances_array_size + 2 /* position's x, y*/ + 2 /* checkpoint x,y */; 2209 2210 switch (primitive_mode) 2211 { 2212 case PRIMITIVE_MODE_LINES: 2213 { 2214 mode = GL_LINES; 2215 2216 break; 2217 } 2218 case PRIMITIVE_MODE_POINTS: 2219 { 2220 mode = GL_POINTS; 2221 2222 break; 2223 } 2224 case PRIMITIVE_MODE_TRIANGLES: 2225 { 2226 mode = GL_TRIANGLES; 2227 2228 break; 2229 } 2230 default: 2231 TCU_FAIL("Unknown primitive mode"); 2232 } 2233 2234 if (use_tesselation) 2235 { 2236 mode = GL_PATCHES; 2237 2238 gl.patchParameteri(GL_PATCH_VERTICES, primitive_vertices_count); 2239 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed."); 2240 } 2241 2242 gl.clear(GL_COLOR_BUFFER_BIT); 2243 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed."); 2244 2245 gl.useProgram(m_po_id); 2246 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); 2247 2248 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++) 2249 { 2250 gl.enable(GL_CLIP_DISTANCE0 + n_clipdistance_entry); 2251 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.enable(GL_CLIP_DISTANCE)() call failed."); 2252 } /* for (all clip distance array value attributes) */ 2253 2254 gl.drawArrays(mode, 0, m_render_vertices); 2255 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray() call(s) failed."); 2256 2257 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; n_clipdistance_entry++) 2258 { 2259 gl.disable(GL_CLIP_DISTANCE0 + n_clipdistance_entry); 2260 GLU_EXPECT_NO_ERROR(gl.getError(), "gl.disable(GL_CLIP_DISTANCE)() call failed."); 2261 } /* for (all clip distance array value attributes) */ 2262 2263 gl.useProgram(0); 2264 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); 2265 2266 /* Read generated texture into m_to_pixel_data_cache */ 2267 readTexturePixels(); 2268 2269 for (glw::GLint n_primitive_index = 0; n_primitive_index < m_render_primitives; n_primitive_index++) 2270 { 2271 glw::GLuint base_index_of_primitive = n_primitive_index * primitive_vertices_count * stride_in_floats; 2272 bool primitive_culled = false; 2273 glw::GLint primitive_culled_by_distance = -1; 2274 2275 /* Check the bounding box is clear */ 2276 glw::GLuint base_index_of_vertex = base_index_of_primitive; 2277 glw::GLuint checkpoint_position_index = base_index_of_vertex + clipdistances_array_size + 2278 culldistances_array_size + 2 /* ignore vertex coordinates */; 2279 glw::GLint checkpoint_x = glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index]); 2280 glw::GLint checkpoint_y = glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index + 1]); 2281 glw::GLint origin_x = checkpoint_x - 1; 2282 glw::GLint origin_y = checkpoint_y - 1; 2283 for (glw::GLint pixel_offset = 0; pixel_offset < m_sub_grid_cell_size; pixel_offset++) 2284 { 2285 if (readRedPixelValue(origin_x + pixel_offset, origin_y) != 0) 2286 { 2287 TCU_FAIL("Top edge of bounding box is overwritten"); 2288 } 2289 2290 if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1, origin_y + pixel_offset) != 0) 2291 { 2292 TCU_FAIL("Right edge of bounding box is overwritten"); 2293 } 2294 2295 if (readRedPixelValue(origin_x + m_sub_grid_cell_size - 1 - pixel_offset, 2296 origin_y + m_sub_grid_cell_size - 1) != 0) 2297 { 2298 TCU_FAIL("Bottom edge of bounding box is overwritten"); 2299 } 2300 2301 if (readRedPixelValue(origin_x, origin_y + m_sub_grid_cell_size - 1 - pixel_offset) != 0) 2302 { 2303 TCU_FAIL("Left edge of bounding box is overwritten"); 2304 } 2305 } 2306 2307 /* Determine if primitive has been culled */ 2308 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; 2309 n_culldistance_entry++) 2310 { 2311 bool distance_negative_in_all_primitive_vertices = true; 2312 2313 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; 2314 n_primitive_vertex++) 2315 { 2316 glw::GLint base_index_of_vertex_internal = 2317 base_index_of_primitive + n_primitive_vertex * stride_in_floats; 2318 glw::GLint culldistance_array_offset = base_index_of_vertex_internal + clipdistances_array_size; 2319 glw::GLfloat* vertex_culldistance_array = &m_bo_data[culldistance_array_offset]; 2320 2321 if (vertex_culldistance_array[n_culldistance_entry] >= 0) 2322 { 2323 /* Primitive is not culled, due to one of its distances is not negative */ 2324 distance_negative_in_all_primitive_vertices = false; 2325 2326 /* Skip left vertices for this distance */ 2327 break; 2328 } 2329 } 2330 2331 /* The distance is negative in all primitive vertices, so this distance culls the primitive */ 2332 if (distance_negative_in_all_primitive_vertices) 2333 { 2334 primitive_culled = true; 2335 primitive_culled_by_distance = n_culldistance_entry; 2336 2337 n_culled_primitives_real++; 2338 2339 /* Skip left distances from check */ 2340 break; 2341 } 2342 } 2343 2344 /* Validate culling */ 2345 if (primitive_culled) 2346 { 2347 /* Check whether primitive was culled and all its vertices are invisible */ 2348 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; 2349 n_primitive_vertex++) 2350 { 2351 glw::GLint base_index_of_vertex_internal = 2352 base_index_of_primitive + n_primitive_vertex * stride_in_floats; 2353 glw::GLint checkpoint_position_index_internal = base_index_of_vertex_internal + 2354 clipdistances_array_size + culldistances_array_size + 2355 2 /* ignore vertex coordinates */; 2356 glw::GLint checkpoint_x_internal = 2357 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]); 2358 glw::GLint checkpoint_y_internal = 2359 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]); 2360 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal); 2361 2362 /* Make sure vertex is invisible */ 2363 if (vertex_color_red_value != 0) 2364 { 2365 m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] " 2366 << "should be culled by distance [" << primitive_culled_by_distance << "]" 2367 << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y 2368 << ") is visible." << tcu::TestLog::EndMessage; 2369 2370 TCU_FAIL("Primitive is expected to be culled, but one of its vertices is visible."); 2371 } 2372 } 2373 2374 /* Primitive is culled, no reason to check clipping */ 2375 continue; 2376 } 2377 2378 bool all_vertices_are_clipped = true; 2379 2380 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; n_primitive_vertex++) 2381 { 2382 glw::GLuint base_index_of_vertex_internal = base_index_of_primitive + n_primitive_vertex * stride_in_floats; 2383 glw::GLuint clipdistance_array_index = base_index_of_vertex_internal; 2384 glw::GLuint checkpoint_position_index_internal = base_index_of_vertex_internal + clipdistances_array_size + 2385 culldistances_array_size + 2386 2 /* ignore vertex coordinates */; 2387 glw::GLint checkpoint_x_internal = 2388 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]); 2389 glw::GLint checkpoint_y_internal = 2390 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]); 2391 glw::GLfloat* vertex_clipdistance_array = &m_bo_data[clipdistance_array_index]; 2392 bool vertex_clipped = false; 2393 glw::GLint vertex_clipped_by_distance = 0; 2394 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal); 2395 2396 /* Check whether pixel should be clipped */ 2397 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; 2398 n_clipdistance_entry++) 2399 { 2400 if (vertex_clipdistance_array[n_clipdistance_entry] < 0) 2401 { 2402 vertex_clipped = true; 2403 vertex_clipped_by_distance = n_clipdistance_entry; 2404 2405 break; 2406 } 2407 } 2408 2409 all_vertices_are_clipped &= vertex_clipped; 2410 2411 /* Validate whether real data same as expected */ 2412 if (vertex_clipped) 2413 { 2414 if (vertex_color_red_value != 0) 2415 { 2416 m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] " 2417 << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") " 2418 << "should be clipped by distance [" << vertex_clipped_by_distance << "] " 2419 << "(distance value [" << vertex_clipdistance_array[vertex_clipped_by_distance] 2420 << "])" << tcu::TestLog::EndMessage; 2421 2422 TCU_FAIL("Vertex is expected to be clipped and invisible, while it is visible."); 2423 } 2424 else 2425 { 2426 n_clipped_vertices_real++; 2427 } 2428 } 2429 else 2430 { 2431 if (vertex_color_red_value == 0) 2432 { 2433 m_testCtx.getLog() << tcu::TestLog::Message << "In primitive number [" << n_primitive_index << "] " 2434 << "vertex at (" << checkpoint_x << "," << checkpoint_y << ") " 2435 << "should not be clipped." << tcu::TestLog::EndMessage; 2436 2437 TCU_FAIL("Vertex is unexpectedly clipped or invisible"); 2438 } 2439 else 2440 { 2441 n_not_clipped_vertices_real++; 2442 } 2443 } 2444 } 2445 2446 if (!all_vertices_are_clipped) 2447 { 2448 /* Check fetched values from the shader (Point 2 of Basic Outline : "Use program that...") */ 2449 if (fetch_culldistance_from_fs) 2450 { 2451 for (glw::GLuint n_primitive_vertex = 0; n_primitive_vertex < primitive_vertices_count; 2452 n_primitive_vertex++) 2453 { 2454 /* Get shader output value */ 2455 glw::GLuint base_index_of_vertex_internal = 2456 base_index_of_primitive + n_primitive_vertex * stride_in_floats; 2457 glw::GLuint checkpoint_position_index_internal = 2458 base_index_of_vertex_internal + clipdistances_array_size + culldistances_array_size + 2459 2 /* ignore vertex coordinates */; 2460 glw::GLuint culldistances_index = base_index_of_vertex_internal + clipdistances_array_size; 2461 glw::GLint checkpoint_x_internal = 2462 glw::GLint(glw::GLfloat(m_to_width) * m_bo_data[checkpoint_position_index_internal]); 2463 glw::GLint checkpoint_y_internal = 2464 glw::GLint(glw::GLfloat(m_to_height) * m_bo_data[checkpoint_position_index_internal + 1]); 2465 glw::GLint vertex_color_red_value = readRedPixelValue(checkpoint_x_internal, checkpoint_y_internal); 2466 2467 /* Calculate culldistances check sum hash */ 2468 float sum = 0.f; 2469 2470 for (glw::GLuint n_clipdistance_entry = 0; n_clipdistance_entry < clipdistances_array_size; 2471 ++n_clipdistance_entry) 2472 { 2473 sum += de::abs(m_bo_data[base_index_of_vertex_internal + n_clipdistance_entry]) * 2474 float(n_clipdistance_entry + 1); 2475 } 2476 2477 for (glw::GLuint n_culldistance_entry = 0; n_culldistance_entry < culldistances_array_size; 2478 ++n_culldistance_entry) 2479 { 2480 sum += de::abs(m_bo_data[culldistances_index + n_culldistance_entry]) * 2481 float(n_culldistance_entry + 1 + clipdistances_array_size); 2482 } 2483 2484 /* limit sum and return */ 2485 glw::GLint sum_hash = 2486 glw::GLint(sum / glw::GLfloat((clipdistances_array_size + culldistances_array_size) * 2487 (clipdistances_array_size + culldistances_array_size + 1)) * 2488 65535.f /* normalizing to short */); 2489 sum_hash = (sum_hash < 65536) ? sum_hash : 65535; /* clamping to short */ 2490 2491 /* Compare against setup value */ 2492 if (std::abs(vertex_color_red_value - sum_hash) > 4 /* precision 4/65536 */) 2493 { 2494 m_testCtx.getLog() << tcu::TestLog::Message << "Primitive number [" << n_primitive_index << "] " 2495 << "should have culldistance hash sum " << sum_hash 2496 << "but primitive vertex at (" << checkpoint_x << "," << checkpoint_y 2497 << ") has sum hash equal to " << vertex_color_red_value 2498 << tcu::TestLog::EndMessage; 2499 2500 TCU_FAIL("Culled distances returned from fragment shader dose not match expected values."); 2501 } 2502 } 2503 } 2504 } 2505 } 2506 2507 /* sub_grid cell size is 3*3 */ 2508 DE_ASSERT(m_render_primitives % 9 == 0); 2509 2510 /* Sanity check */ 2511 switch (primitive_mode) 2512 { 2513 case PRIMITIVE_MODE_LINES: 2514 case PRIMITIVE_MODE_TRIANGLES: 2515 { 2516 /* Validate culled primitives */ 2517 if (culldistances_array_size == 0) 2518 { 2519 DE_ASSERT(n_culled_primitives_real == 0); 2520 } 2521 else 2522 { 2523 /* Each 3rd line or triangle should be culled by test design */ 2524 DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives / 3); 2525 } 2526 2527 /* Validate clipped vertices */ 2528 if (clipdistances_array_size == 0) 2529 { 2530 DE_ASSERT(n_clipped_vertices_real == 0); 2531 } 2532 else 2533 { 2534 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD) 2535 glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3; 2536 glw::GLint n_clipped_vertices_expected = /* One third of primitives has 0th vertex clipped */ 2537 one_third_of_rendered_primitives + 2538 /* One third of primitives clipped completely */ 2539 one_third_of_rendered_primitives * primitive_vertices_count; 2540 2541 DE_ASSERT(glw::GLint(n_clipped_vertices_real) == n_clipped_vertices_expected); 2542 #endif 2543 } 2544 break; 2545 } 2546 2547 case PRIMITIVE_MODE_POINTS: 2548 { 2549 /* Validate culled primitives */ 2550 if (culldistances_array_size == 0) 2551 { 2552 DE_ASSERT(n_culled_primitives_real == 0); 2553 } 2554 else 2555 { 2556 /* 2/3 points should be culled by test design */ 2557 DE_ASSERT(glw::GLsizei(n_culled_primitives_real) == m_render_primitives * 2 / 3); 2558 } 2559 2560 /* Validate clipped vertices */ 2561 if (clipdistances_array_size == 0) 2562 { 2563 DE_ASSERT(n_clipped_vertices_real == 0); 2564 } 2565 else 2566 { 2567 #if defined(DE_DEBUG) && !defined(DE_COVERAGE_BUILD) 2568 glw::GLint one_third_of_rendered_primitives = (m_render_primitives - n_culled_primitives_real) / 3; 2569 2570 /* 2/3 of rendered points should be clipped by test design */ 2571 DE_ASSERT(glw::GLint(n_clipped_vertices_real) == 2 * one_third_of_rendered_primitives); 2572 #endif 2573 } 2574 2575 break; 2576 } 2577 default: 2578 TCU_FAIL("Unknown primitive mode"); 2579 } 2580 } 2581 2582 /** Executes test iteration. 2583 * 2584 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. 2585 */ 2586 tcu::TestNode::IterateResult CullDistance::FunctionalTest::iterate() 2587 { 2588 /* This test should only be executed if ARB_cull_distance is supported, or if 2589 * we're running a GL4.5 context 2590 */ 2591 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") && 2592 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))) 2593 { 2594 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported"); 2595 } 2596 2597 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2598 bool has_succeeded = true; 2599 bool is_core = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)); 2600 2601 /* Retrieve important GL constant values */ 2602 glw::GLint gl_max_clip_distances_value = 0; 2603 glw::GLint gl_max_combined_clip_and_cull_distances_value = 0; 2604 glw::GLint gl_max_cull_distances_value = 0; 2605 2606 gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value); 2607 gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value); 2608 gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value); 2609 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed."); 2610 2611 gl.genTextures(1, &m_to_id); 2612 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed."); 2613 2614 gl.bindTexture(GL_TEXTURE_2D, m_to_id); 2615 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); 2616 2617 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */ 2618 GL_R32F, m_to_width, m_to_height); 2619 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed."); 2620 2621 /* Set up the draw/read FBO */ 2622 gl.genFramebuffers(1, &m_fbo_id); 2623 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed."); 2624 2625 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id); 2626 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); 2627 2628 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); /* level */ 2629 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed."); 2630 2631 /* Prepare a buffer object */ 2632 gl.genBuffers(1, &m_bo_id); 2633 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed."); 2634 2635 /* Prepare a VAO. We will configure separately for each iteration. */ 2636 gl.genVertexArrays(1, &m_vao_id); 2637 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed."); 2638 2639 /* Iterate over all functional tests */ 2640 struct _test_item 2641 { 2642 bool redeclare_clipdistances_array; 2643 bool redeclare_culldistances_array; 2644 bool dynamic_index_writes; 2645 bool use_passthrough_gs; 2646 bool use_passthrough_ts; 2647 bool use_core_functionality; 2648 bool fetch_culldistances; 2649 } test_items[] = { /* Use the basic outline to test the basic functionality of cull distances. */ 2650 { 2651 true, /* redeclare_clipdistances_array */ 2652 true, /* redeclare_culldistances_array */ 2653 false, /* dynamic_index_writes */ 2654 false, /* use_passthrough_gs */ 2655 false, /* use_passthrough_ts */ 2656 is_core, /* use_core_functionality */ 2657 false /* fetch_culldistances */ 2658 }, 2659 /* Use the basic outline but don't redeclare gl_ClipDistance with a size. */ 2660 { 2661 false, /* redeclare_clipdistances_array */ 2662 true, /* redeclare_culldistances_array */ 2663 false, /* dynamic_index_writes */ 2664 false, /* use_passthrough_gs */ 2665 false, /* use_passthrough_ts */ 2666 is_core, /* use_core_functionality */ 2667 false /* fetch_culldistances */ 2668 }, 2669 /* Use the basic outline but don't redeclare gl_CullDistance with a size. */ 2670 { 2671 true, /* redeclare_clipdistances_array */ 2672 false, /* redeclare_culldistances_array */ 2673 false, /* dynamic_index_writes */ 2674 false, /* use_passthrough_gs */ 2675 false, /* use_passthrough_ts */ 2676 is_core, /* use_core_functionality */ 2677 false /* fetch_culldistances */ 2678 }, 2679 /* Use the basic outline but don't redeclare either gl_ClipDistance or 2680 * gl_CullDistance with a size. 2681 */ 2682 { 2683 false, /* redeclare_clipdistances_array */ 2684 false, /* redeclare_culldistances_array */ 2685 false, /* dynamic_index_writes */ 2686 false, /* use_passthrough_gs */ 2687 false, /* use_passthrough_ts */ 2688 is_core, /* use_core_functionality */ 2689 false /* fetch_culldistances */ 2690 }, 2691 /* Use the basic outline but use dynamic indexing when writing the elements 2692 * of the gl_ClipDistance and gl_CullDistance arrays. 2693 */ 2694 { 2695 true, /* redeclare_clipdistances_array */ 2696 true, /* redeclare_culldistances_array */ 2697 true, /* dynamic_index_writes */ 2698 false, /* use_passthrough_gs */ 2699 false, /* use_passthrough_ts */ 2700 is_core, /* use_core_functionality */ 2701 false /* fetch_culldistances */ 2702 }, 2703 /* Use the basic outline but add a geometry shader to the program that 2704 * simply passes through all written clip and cull distances. 2705 */ 2706 { 2707 true, /* redeclare_clipdistances_array */ 2708 true, /* redeclare_culldistances_array */ 2709 false, /* dynamic_index_writes */ 2710 true, /* use_passthrough_gs */ 2711 false, /* use_passthrough_ts */ 2712 is_core, /* use_core_functionality */ 2713 false /* fetch_culldistances */ 2714 }, 2715 /* Use the basic outline but add a tessellation control and tessellation 2716 * evaluation shader to the program which simply pass through all written 2717 * clip and cull distances. 2718 */ 2719 { 2720 true, /* redeclare_clipdistances_array */ 2721 true, /* redeclare_culldistances_array */ 2722 false, /* dynamic_index_writes */ 2723 false, /* use_passthrough_gs */ 2724 true, /* use_passthrough_ts */ 2725 is_core, /* use_core_functionality */ 2726 false /* fetch_culldistances */ 2727 }, 2728 /* Test that using #extension with GL_ARB_cull_distance allows using the 2729 * feature even with an earlier version of GLSL. Also test that the 2730 * extension name is available as preprocessor #define. 2731 */ 2732 { 2733 true, /* redeclare_clipdistances_array */ 2734 true, /* redeclare_culldistances_array */ 2735 false, /* dynamic_index_writes */ 2736 false, /* use_passthrough_gs */ 2737 false, /* use_passthrough_ts */ 2738 false, /* use_core_functionality */ 2739 false /* fetch_culldistances */ 2740 }, 2741 /* Use a program that has only a vertex shader and a fragment shader. 2742 * The vertex shader should redeclare gl_ClipDistance with a size that 2743 * fits all enabled cull distances. Also redeclare gl_CullDistance with a 2744 * size. The sum of the two sizes should not be more than MAX_COMBINED_- 2745 * CLIP_AND_CULL_DISTANCES. The fragment shader should output the cull 2746 * distances written by the vertex shader by reading them from the built-in 2747 * array gl_CullDistance. 2748 */ 2749 { 2750 true, /* redeclare_clipdistances_array */ 2751 true, /* redeclare_culldistances_array */ 2752 false, /* dynamic_index_writes */ 2753 false, /* use_passthrough_gs */ 2754 false, /* use_passthrough_ts */ 2755 false, /* use_core_functionality */ 2756 true /* fetch_culldistances */ 2757 } 2758 }; 2759 const glw::GLuint n_test_items = sizeof(test_items) / sizeof(test_items[0]); 2760 2761 gl.viewport(0, 0, m_to_width, m_to_height); 2762 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed."); 2763 2764 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 2765 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed."); 2766 2767 for (glw::GLuint n_test_item = 0; n_test_item < n_test_items; ++n_test_item) 2768 { 2769 /* Check for OpenGL feature support */ 2770 if (test_items[n_test_item].use_passthrough_ts) 2771 { 2772 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)) && 2773 !m_context.getContextInfo().isExtensionSupported("GL_ARB_tessellation_shader")) 2774 { 2775 continue; // no tessellation shader support 2776 } 2777 } 2778 2779 const _test_item& current_test_item = test_items[n_test_item]; 2780 const _primitive_mode primitive_modes[PRIMITIVE_MODE_COUNT] = { PRIMITIVE_MODE_LINES, PRIMITIVE_MODE_POINTS, 2781 PRIMITIVE_MODE_TRIANGLES }; 2782 2783 for (glw::GLuint primitive_mode_index = 0; primitive_mode_index < PRIMITIVE_MODE_COUNT; ++primitive_mode_index) 2784 { 2785 _primitive_mode primitive_mode = primitive_modes[primitive_mode_index]; 2786 2787 /* Iterate over a set of gl_ClipDistances[] and gl_CullDistances[] array sizes */ 2788 for (glw::GLint n_iteration = 0; n_iteration <= gl_max_combined_clip_and_cull_distances_value; 2789 ++n_iteration) 2790 { 2791 glw::GLuint clipdistances_array_size = 0; 2792 glw::GLuint culldistances_array_size = 0; 2793 2794 if (n_iteration != 0 && n_iteration <= gl_max_clip_distances_value) 2795 { 2796 clipdistances_array_size = n_iteration; 2797 } 2798 2799 if ((gl_max_combined_clip_and_cull_distances_value - n_iteration) < gl_max_cull_distances_value) 2800 { 2801 culldistances_array_size = gl_max_combined_clip_and_cull_distances_value - n_iteration; 2802 } 2803 else 2804 { 2805 culldistances_array_size = gl_max_cull_distances_value; 2806 } 2807 2808 if (clipdistances_array_size == 0 && culldistances_array_size == 0) 2809 { 2810 /* Skip the dummy iteration */ 2811 continue; 2812 } 2813 2814 if (current_test_item.fetch_culldistances && (primitive_mode != PRIMITIVE_MODE_POINTS)) 2815 { 2816 continue; 2817 } 2818 2819 /* Create a program to run */ 2820 buildPO(clipdistances_array_size, culldistances_array_size, current_test_item.dynamic_index_writes, 2821 primitive_mode, current_test_item.redeclare_clipdistances_array, 2822 current_test_item.redeclare_culldistances_array, current_test_item.use_core_functionality, 2823 current_test_item.use_passthrough_gs, current_test_item.use_passthrough_ts, 2824 current_test_item.fetch_culldistances); 2825 2826 /* Initialize VAO data */ 2827 configureVAO(clipdistances_array_size, culldistances_array_size, primitive_mode); 2828 2829 /* Run GLSL program and check results */ 2830 executeRenderTest(clipdistances_array_size, culldistances_array_size, primitive_mode, 2831 current_test_item.use_passthrough_ts, current_test_item.fetch_culldistances); 2832 2833 } /* for (all iterations) */ 2834 } /* for (all test modes) */ 2835 } /* for (all test items) */ 2836 2837 /* All done */ 2838 if (has_succeeded) 2839 { 2840 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2841 } 2842 else 2843 { 2844 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 2845 } 2846 2847 return STOP; 2848 } 2849 2850 /** Returns pixel red component read from texture at position x, y. 2851 * 2852 * @param x x-coordinate to read pixel color component from 2853 * @param y y-coordinate to read pixel color component from 2854 **/ 2855 glw::GLint CullDistance::FunctionalTest::readRedPixelValue(glw::GLint x, glw::GLint y) 2856 { 2857 glw::GLint result = -1; 2858 2859 DE_ASSERT(x >= 0 && (glw::GLuint)x < m_to_width); 2860 DE_ASSERT(y >= 0 && (glw::GLuint)y < m_to_height); 2861 2862 result = m_to_pixel_data_cache[(m_to_width * y + x) * m_to_pixel_data_cache_color_components]; 2863 2864 return result; 2865 } 2866 2867 /** Reads texture into m_to_pixel_data_cache. 2868 * Texture size determined by fields m_to_width, m_to_height 2869 **/ 2870 void CullDistance::FunctionalTest::readTexturePixels() 2871 { 2872 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2873 2874 m_to_pixel_data_cache.clear(); 2875 2876 m_to_pixel_data_cache.resize(m_to_width * m_to_height * m_to_pixel_data_cache_color_components); 2877 2878 /* Read vertex from texture */ 2879 gl.readPixels(0, /* x */ 2880 0, /* y */ 2881 m_to_width, /* width */ 2882 m_to_height, /* height */ 2883 GL_RGBA, GL_UNSIGNED_SHORT, &m_to_pixel_data_cache[0]); 2884 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed."); 2885 } 2886 2887 /** Constructor. 2888 * 2889 * @param context Rendering context handle. 2890 **/ 2891 CullDistance::NegativeTest::NegativeTest(deqp::Context& context) 2892 : TestCase(context, "negative", "Cull Distance Negative Test") 2893 , m_fs_id(0) 2894 , m_po_id(0) 2895 , m_temp_buffer(DE_NULL) 2896 , m_vs_id(0) 2897 { 2898 /* Left blank on purpose */ 2899 } 2900 2901 /** @brief Cull Distance Negative Test deinitialization */ 2902 void CullDistance::NegativeTest::deinit() 2903 { 2904 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2905 2906 if (m_fs_id != 0) 2907 { 2908 gl.deleteShader(m_fs_id); 2909 2910 m_fs_id = 0; 2911 } 2912 2913 if (m_po_id != 0) 2914 { 2915 gl.deleteProgram(m_po_id); 2916 2917 m_po_id = 0; 2918 } 2919 2920 if (m_vs_id != 0) 2921 { 2922 gl.deleteShader(m_vs_id); 2923 2924 m_vs_id = 0; 2925 } 2926 2927 if (m_temp_buffer != DE_NULL) 2928 { 2929 delete[] m_temp_buffer; 2930 2931 m_temp_buffer = DE_NULL; 2932 } 2933 } 2934 2935 /** @brief Get string description of test with given parameters 2936 * 2937 * @param [in] n_test_iteration Test iteration number 2938 * @param [in] should_redeclare_output_variables Indicate whether test redeclared gl_ClipDistance and gl_CullDistance 2939 * @param [in] use_dynamic_index_based_writes Indicate whether test used dynamic index-based setters 2940 * 2941 * @return String containing description. 2942 */ 2943 std::string CullDistance::NegativeTest::getTestDescription(int n_test_iteration, bool should_redeclare_output_variables, 2944 bool use_dynamic_index_based_writes) 2945 { 2946 std::stringstream stream; 2947 2948 stream << "Test iteration [" << n_test_iteration << "] which uses a vertex shader that:\n\n" 2949 << ((should_redeclare_output_variables) ? 2950 "* redeclares gl_ClipDistance and gl_CullDistance arrays\n" : 2951 "* does not redeclare gl_ClipDistance and gl_CullDistance arrays\n") 2952 << ((use_dynamic_index_based_writes) ? "* uses dynamic index-based writes\n" : "* uses static writes\n"); 2953 2954 return stream.str(); 2955 } 2956 2957 /** Executes test iteration. 2958 * 2959 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. 2960 */ 2961 tcu::TestNode::IterateResult CullDistance::NegativeTest::iterate() 2962 { 2963 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 2964 2965 /* Build the test shaders. */ 2966 const glw::GLchar* token_dynamic_index_based_writes = "DYNAMIC_INDEX_BASED_WRITES"; 2967 const glw::GLchar* token_insert_static_writes = "INSERT_STATIC_WRITES"; 2968 const glw::GLchar* token_n_gl_clipdistance_entries = "N_GL_CLIPDISTANCE_ENTRIES"; 2969 const glw::GLchar* token_n_gl_culldistance_entries = "N_GL_CULLDISTANCE_ENTRIES"; 2970 const glw::GLchar* token_redeclare_output_variables = "REDECLARE_OUTPUT_VARIABLES"; 2971 2972 const glw::GLchar* fs_body = "#version 130\n" 2973 "\n" 2974 "void main()\n" 2975 "{\n" 2976 "}\n"; 2977 2978 const glw::GLchar* vs_body_preamble = "#version 130\n" 2979 "\n" 2980 " #extension GL_ARB_cull_distance : require\n" 2981 "\n"; 2982 2983 const glw::GLchar* vs_body_main = "#ifdef REDECLARE_OUTPUT_VARIABLES\n" 2984 " out float gl_ClipDistance[N_GL_CLIPDISTANCE_ENTRIES];\n" 2985 " out float gl_CullDistance[N_GL_CULLDISTANCE_ENTRIES];\n" 2986 "#endif\n" 2987 "\n" 2988 "void main()\n" 2989 "{\n" 2990 "#ifdef DYNAMIC_INDEX_BASED_WRITES\n" 2991 " for (int n_clipdistance_entry = 0;\n" 2992 " n_clipdistance_entry < N_GL_CLIPDISTANCE_ENTRIES;\n" 2993 " ++n_clipdistance_entry)\n" 2994 " {\n" 2995 " gl_ClipDistance[n_clipdistance_entry] = float(n_clipdistance_entry) / " 2996 "float(N_GL_CLIPDISTANCE_ENTRIES);\n" 2997 " }\n" 2998 "\n" 2999 " for (int n_culldistance_entry = 0;\n" 3000 " n_culldistance_entry < N_GL_CULLDISTANCE_ENTRIES;\n" 3001 " ++n_culldistance_entry)\n" 3002 " {\n" 3003 " gl_CullDistance[n_culldistance_entry] = float(n_culldistance_entry) / " 3004 "float(N_GL_CULLDISTANCE_ENTRIES);\n" 3005 " }\n" 3006 "#else\n" 3007 " INSERT_STATIC_WRITES\n" 3008 "#endif\n" 3009 "}\n"; 3010 3011 /* This test should only be executed if ARB_cull_distance is supported, or if 3012 * we're running a GL4.5 context 3013 */ 3014 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_cull_distance") && 3015 !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))) 3016 { 3017 throw tcu::NotSupportedError("GL_ARB_cull_distance is not supported"); 3018 } 3019 3020 /* It only makes sense to run this test if GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 3021 * is lower than a sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CLIP_CULL_DISTANCES. 3022 */ 3023 glw::GLint gl_max_clip_distances_value = 0; 3024 glw::GLint gl_max_combined_clip_and_cull_distances_value = 0; 3025 glw::GLint gl_max_cull_distances_value = 0; 3026 glw::GLuint n_gl_clipdistance_array_items = 0; 3027 std::string n_gl_clipdistance_array_items_string; 3028 glw::GLuint n_gl_culldistance_array_items = 0; 3029 std::string n_gl_culldistance_array_items_string; 3030 std::string static_write_shader_body_part; 3031 3032 gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &gl_max_clip_distances_value); 3033 gl.getIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &gl_max_combined_clip_and_cull_distances_value); 3034 gl.getIntegerv(GL_MAX_CULL_DISTANCES, &gl_max_cull_distances_value); 3035 3036 if (gl_max_clip_distances_value + gl_max_cull_distances_value < gl_max_combined_clip_and_cull_distances_value) 3037 { 3038 m_testCtx.getLog() << tcu::TestLog::Message 3039 << "GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES is larger than or equal to " 3040 "the sum of GL_MAX_CLIP_DISTANCES and GL_MAX_CULL_DISTANCES. Skipping." 3041 << tcu::TestLog::EndMessage; 3042 3043 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 3044 3045 return STOP; 3046 } 3047 3048 n_gl_clipdistance_array_items = gl_max_clip_distances_value; 3049 n_gl_culldistance_array_items = gl_max_combined_clip_and_cull_distances_value - gl_max_clip_distances_value + 1; 3050 3051 /* Determine the number of items we will want the gl_ClipDistance and gl_CullDistance arrays 3052 * to hold for test iterations that will re-declare the built-in output variables. 3053 */ 3054 { 3055 std::stringstream temp_sstream; 3056 3057 temp_sstream << n_gl_clipdistance_array_items; 3058 3059 n_gl_clipdistance_array_items_string = temp_sstream.str(); 3060 } 3061 3062 { 3063 std::stringstream temp_sstream; 3064 3065 temp_sstream << n_gl_culldistance_array_items; 3066 3067 n_gl_culldistance_array_items_string = temp_sstream.str(); 3068 } 3069 3070 /* Form the "static write" shader body part. */ 3071 { 3072 std::stringstream temp_sstream; 3073 3074 temp_sstream << "gl_ClipDistance[" << n_gl_clipdistance_array_items_string.c_str() << "] = 0.0f;\n" 3075 << "gl_CullDistance[" << n_gl_culldistance_array_items_string.c_str() << "] = 0.0f;\n"; 3076 3077 static_write_shader_body_part = temp_sstream.str(); 3078 } 3079 3080 /* Prepare GL objects before we continue */ 3081 glw::GLint compile_status = GL_FALSE; 3082 3083 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); 3084 m_po_id = gl.createProgram(); 3085 m_vs_id = gl.createShader(GL_VERTEX_SHADER); 3086 3087 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() / glCreateShader() calls failed."); 3088 3089 gl.attachShader(m_po_id, m_fs_id); 3090 gl.attachShader(m_po_id, m_vs_id); 3091 3092 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed."); 3093 3094 gl.shaderSource(m_fs_id, 1, /* count */ 3095 &fs_body, DE_NULL); /* length */ 3096 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); 3097 3098 gl.compileShader(m_fs_id); 3099 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); 3100 3101 gl.getShaderiv(m_fs_id, GL_COMPILE_STATUS, &compile_status); 3102 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); 3103 3104 if (compile_status == GL_FALSE) 3105 { 3106 TCU_FAIL("Fragment shader failed to compile."); 3107 } 3108 3109 /* Run three separate test iterations. */ 3110 struct _test_item 3111 { 3112 bool should_redeclare_output_variables; 3113 bool use_dynamic_index_based_writes; 3114 } test_items[] = { /* Negative Test 1 */ 3115 { true, false }, 3116 3117 /* Negative Test 2 */ 3118 { false, false }, 3119 3120 /* Negative Test 3 */ 3121 { false, true } 3122 }; 3123 const unsigned int n_test_items = sizeof(test_items) / sizeof(test_items[0]); 3124 3125 for (unsigned int n_test_item = 0; n_test_item < n_test_items; ++n_test_item) 3126 { 3127 const _test_item& current_test_item = test_items[n_test_item]; 3128 3129 /* Prepare vertex shader body */ 3130 std::size_t token_position = std::string::npos; 3131 std::stringstream vs_body_sstream; 3132 std::string vs_body_string; 3133 3134 vs_body_sstream << vs_body_preamble << "\n"; 3135 3136 if (current_test_item.should_redeclare_output_variables) 3137 { 3138 vs_body_sstream << "#define " << token_redeclare_output_variables << "\n"; 3139 } 3140 3141 if (current_test_item.use_dynamic_index_based_writes) 3142 { 3143 vs_body_sstream << "#define " << token_dynamic_index_based_writes << "\n"; 3144 } 3145 3146 vs_body_sstream << vs_body_main; 3147 3148 /* Replace tokens with meaningful values */ 3149 vs_body_string = vs_body_sstream.str(); 3150 3151 while ((token_position = vs_body_string.find(token_n_gl_clipdistance_entries)) != std::string::npos) 3152 { 3153 vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries), 3154 n_gl_clipdistance_array_items_string); 3155 } 3156 3157 while ((token_position = vs_body_string.find(token_n_gl_culldistance_entries)) != std::string::npos) 3158 { 3159 vs_body_string = vs_body_string.replace(token_position, strlen(token_n_gl_clipdistance_entries), 3160 n_gl_culldistance_array_items_string); 3161 } 3162 3163 while ((token_position = vs_body_string.find(token_insert_static_writes)) != std::string::npos) 3164 { 3165 vs_body_string = vs_body_string.replace(token_position, strlen(token_insert_static_writes), 3166 static_write_shader_body_part); 3167 } 3168 3169 /* Try to compile the vertex shader */ 3170 glw::GLint compile_status_internal = GL_FALSE; 3171 const char* vs_body_raw_ptr = vs_body_string.c_str(); 3172 3173 gl.shaderSource(m_vs_id, 1, /* count */ 3174 &vs_body_raw_ptr, DE_NULL); /* length */ 3175 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed."); 3176 3177 gl.compileShader(m_vs_id); 3178 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed."); 3179 3180 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status_internal); 3181 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); 3182 3183 if (compile_status_internal == GL_FALSE) 3184 { 3185 glw::GLint buffer_size = 0; 3186 3187 /* Log the compilation error */ 3188 m_testCtx.getLog() << tcu::TestLog::Message 3189 << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables, 3190 current_test_item.use_dynamic_index_based_writes) 3191 << "has failed (as expected) to compile with the following info log:\n\n" 3192 << tcu::TestLog::EndMessage; 3193 3194 gl.getShaderiv(m_vs_id, GL_INFO_LOG_LENGTH, &buffer_size); 3195 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed."); 3196 3197 m_temp_buffer = new glw::GLchar[buffer_size + 1]; 3198 3199 memset(m_temp_buffer, 0, buffer_size + 1); 3200 3201 gl.getShaderInfoLog(m_vs_id, buffer_size, DE_NULL, /* length */ 3202 m_temp_buffer); 3203 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog() call failed."); 3204 3205 m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage; 3206 3207 delete[] m_temp_buffer; 3208 m_temp_buffer = DE_NULL; 3209 3210 /* Move on to the next iteration */ 3211 continue; 3212 } 3213 3214 /* Try to link the program object */ 3215 glw::GLint link_status = GL_FALSE; 3216 3217 gl.linkProgram(m_po_id); 3218 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed."); 3219 3220 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status); 3221 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); 3222 3223 if (link_status == GL_TRUE) 3224 { 3225 m_testCtx.getLog() << tcu::TestLog::Message 3226 << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables, 3227 current_test_item.use_dynamic_index_based_writes) 3228 << "has linked successfully which is invalid!" << tcu::TestLog::EndMessage; 3229 3230 TCU_FAIL("Program object has linked successfully, even though the process should have failed."); 3231 } 3232 else 3233 { 3234 glw::GLint buffer_size = 0; 3235 3236 m_testCtx.getLog() << tcu::TestLog::Message 3237 << getTestDescription(n_test_item, current_test_item.should_redeclare_output_variables, 3238 current_test_item.use_dynamic_index_based_writes) 3239 << "has failed (as expected) to link with the following info log:\n\n" 3240 << tcu::TestLog::EndMessage; 3241 3242 gl.getProgramiv(m_po_id, GL_INFO_LOG_LENGTH, &buffer_size); 3243 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed."); 3244 3245 m_temp_buffer = new glw::GLchar[buffer_size + 1]; 3246 3247 memset(m_temp_buffer, 0, buffer_size + 1); 3248 3249 gl.getProgramInfoLog(m_po_id, buffer_size, DE_NULL, /* length */ 3250 m_temp_buffer); 3251 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog() call failed."); 3252 3253 m_testCtx.getLog() << tcu::TestLog::Message << m_temp_buffer << tcu::TestLog::EndMessage; 3254 3255 delete[] m_temp_buffer; 3256 m_temp_buffer = DE_NULL; 3257 } 3258 } /* for (all test items) */ 3259 3260 /* All done */ 3261 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 3262 3263 return STOP; 3264 } 3265 3266 /** Constructor. 3267 * 3268 * @param context Rendering context. 3269 */ 3270 CullDistance::Tests::Tests(deqp::Context& context) : TestCaseGroup(context, "cull_distance", "Cull Distance Test Suite") 3271 { 3272 } 3273 3274 /** Initializes the test group contents. */ 3275 void CullDistance::Tests::init() 3276 { 3277 addChild(new CullDistance::APICoverageTest(m_context)); 3278 addChild(new CullDistance::FunctionalTest(m_context)); 3279 addChild(new CullDistance::NegativeTest(m_context)); 3280 } 3281 } /* glcts namespace */ 3282