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 /* Includes. */ 25 #include "gl3cClipDistance.hpp" 26 #include "gluContextInfo.hpp" 27 #include "gluDefs.hpp" 28 #include "gluRenderContext.hpp" 29 #include "gluStrUtil.hpp" 30 #include "tcuTestLog.hpp" 31 32 #include <cmath> 33 #include <sstream> 34 35 /* Stringify macro. */ 36 #define _STR(s) STR(s) 37 #define STR(s) #s 38 39 /* In OpenGL 3.0 specification GL_CLIP_DISTANCEi is named GL_CLIP_PLANEi */ 40 #ifndef GL_CLIP_DISTANCE0 41 #define GL_CLIP_DISTANCE0 GL_CLIP_PLANE0 42 #endif 43 44 /* In OpenGL 3.0 specification GL_MAX_CLIP_DISTANCES is named GL_MAX_CLIP_PLANES */ 45 #ifndef GL_MAX_CLIP_DISTANCES 46 #define GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES 47 #endif 48 49 /******************************** Test Group Implementation ********************************/ 50 51 /** @brief Clip distances tests group constructor. 52 * 53 * @param [in] context OpenGL context. 54 */ 55 gl3cts::ClipDistance::Tests::Tests(deqp::Context& context) 56 : TestCaseGroup(context, "clip_distance", "Clip Distance Test Suite") 57 { 58 /* Intentionally left blank */ 59 } 60 61 /** @brief Clip distances tests initializer. */ 62 void gl3cts::ClipDistance::Tests::init() 63 { 64 addChild(new gl3cts::ClipDistance::CoverageTest(m_context)); 65 addChild(new gl3cts::ClipDistance::FunctionalTest(m_context)); 66 addChild(new gl3cts::ClipDistance::NegativeTest(m_context)); 67 } 68 69 /******************************** Coverage Tests Implementation ********************************/ 70 71 /** @brief API coverage tests constructor. 72 * 73 * @param [in] context OpenGL context. 74 */ 75 gl3cts::ClipDistance::CoverageTest::CoverageTest(deqp::Context& context) 76 : deqp::TestCase(context, "coverage", "Clip Distance API Coverage Test"), m_gl_max_clip_distances_value(0) 77 { 78 /* Intentionally left blank. */ 79 } 80 81 /** @brief Iterate API coverage tests. 82 * 83 * @return Iteration result. 84 */ 85 tcu::TestNode::IterateResult gl3cts::ClipDistance::CoverageTest::iterate() 86 { 87 /* Shortcut for GL functionality */ 88 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 89 90 /* This test should only be executed if we're running a GL3.0 context */ 91 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(3, 0, glu::PROFILE_CORE))) 92 { 93 throw tcu::NotSupportedError("GL_ARB_clip_distance is not supported"); 94 } 95 96 /* Running tests. */ 97 bool is_ok = true; 98 99 is_ok = is_ok && MaxClipDistancesValueTest(gl); 100 is_ok = is_ok && EnableDisableTest(gl); 101 is_ok = is_ok && MaxClipDistancesValueInVertexShaderTest(gl); 102 is_ok = is_ok && MaxClipDistancesValueInFragmentShaderTest(gl); 103 is_ok = is_ok && ClipDistancesValuePassing(gl); 104 105 /* Result's setup. */ 106 if (is_ok) 107 { 108 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 109 } 110 else 111 { 112 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 113 } 114 115 return STOP; 116 } 117 118 /* @brief glGet GL_MAX_CLIP_DISTANCES limit coverage test. 119 * 120 * @param [in] gl OpenGL functions' access. 121 * 122 * @return True if passed, false otherwise. 123 */ 124 bool gl3cts::ClipDistance::CoverageTest::MaxClipDistancesValueTest(const glw::Functions& gl) 125 { 126 /* Check that calling GetIntegerv with GL_MAX_CLIP_DISTANCES doesn't 127 generate any errors and returns a value at least 6 in OpenGL 3.0 128 or 8 in OpenGL 3.1 and higher (see issues). */ 129 130 glw::GLint error_code = GL_NO_ERROR; 131 132 gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &m_gl_max_clip_distances_value); 133 134 error_code = gl.getError(); 135 136 if (error_code != GL_NO_ERROR) 137 { 138 m_testCtx.getLog() << tcu::TestLog::Message << "glGetIntegerv(" << STR(GL_MAX_CLIP_DISTANCES) 139 << ") returned error code " << glu::getErrorStr(error_code) << " instead of GL_NO_ERROR." 140 << tcu::TestLog::EndMessage; 141 142 return false; 143 } 144 else 145 { 146 glw::GLint gl_max_clip_distances_minimum_value = 6; /* OpenGL 3.0 Specification minimum value */ 147 148 if (glu::contextSupports( 149 m_context.getRenderContext().getType(), 150 glu::ApiType(3, 1, glu::PROFILE_CORE))) /* OpenGL 3.1 Specification minimum value, see bug #4803 */ 151 { 152 gl_max_clip_distances_minimum_value = 8; 153 } 154 155 if (m_gl_max_clip_distances_value < gl_max_clip_distances_minimum_value) 156 { 157 m_testCtx.getLog() << tcu::TestLog::Message << "Value of " << STR(GL_MAX_CLIP_DISTANCES) << "is equal to " 158 << m_gl_max_clip_distances_value << " which is less than minimum required (" 159 << gl_max_clip_distances_minimum_value << ")." << tcu::TestLog::EndMessage; 160 161 return false; 162 } 163 } 164 165 return true; 166 } 167 168 /* @brief glEnable / glDisable of GL_CLIP_DISTANCEi coverage test. 169 * 170 * @param [in] gl OpenGL functions' access. 171 * 172 * @return True if passed, false otherwise. 173 */ 174 bool gl3cts::ClipDistance::CoverageTest::EnableDisableTest(const glw::Functions& gl) 175 { 176 /* Check that calling Enable and Disable with GL_CLIP_DISTANCEi for all 177 available clip distances does not generate errors. 178 glw::GLint error_code = GL_NO_ERROR; */ 179 180 glw::GLint error_code = GL_NO_ERROR; 181 182 /* Test glEnable */ 183 for (glw::GLint i = 0; i < m_gl_max_clip_distances_value; ++i) 184 { 185 gl.enable(GL_CLIP_DISTANCE0 + i); 186 187 error_code = gl.getError(); 188 189 if (error_code != GL_NO_ERROR) 190 { 191 m_testCtx.getLog() << tcu::TestLog::Message << "glEnable(GL_CLIP_DISTANCE" << i << ") returned error code " 192 << glu::getErrorStr(error_code) << " instead of GL_NO_ERROR." 193 << tcu::TestLog::EndMessage; 194 195 return false; 196 } 197 } 198 199 /* Test glDisable */ 200 for (glw::GLint i = 0; i < m_gl_max_clip_distances_value; ++i) 201 { 202 gl.disable(GL_CLIP_DISTANCE0 + i); 203 204 error_code = gl.getError(); 205 206 if (error_code != GL_NO_ERROR) 207 { 208 m_testCtx.getLog() << tcu::TestLog::Message << "glDisable(GL_CLIP_DISTANCE" << i << ") returned error code " 209 << glu::getErrorStr(error_code) << " instead of GL_NO_ERROR." 210 << tcu::TestLog::EndMessage; 211 212 return false; 213 } 214 } 215 216 return true; 217 } 218 219 /* @brief gl_MaxClipDistances value test in the vertex shader coverage test. 220 * 221 * @param [in] gl OpenGL functions' access. 222 * 223 * @return True if passed, false otherwise. 224 */ 225 bool gl3cts::ClipDistance::CoverageTest::MaxClipDistancesValueInVertexShaderTest(const glw::Functions& gl) 226 { 227 /* Make a program that consist of vertex and fragment shader stages. A 228 vertex shader shall assign the value of gl_MaxClipDistances to transform 229 feedback output variable. Setup gl_Position with passed in attribute. 230 Use blank fragment shader. Check that the shaders compiles and links 231 successfully. Draw a single GL_POINT with screen centered position 232 attribute, a configured transform feedback and GL_RASTERIZER_DISCARD. 233 Query transform feedback value and compare it against 234 GL_MAX_CLIP_DISTANCES. Expect that both values are equal. */ 235 236 /* Building program. */ 237 const std::string vertex_shader = m_vertex_shader_code_case_0; 238 const std::string fragment_shader = m_fragment_shader_code_case_0; 239 std::string transform_feedback_varying_name = "max_value"; 240 241 std::vector<std::string> transform_feedback_varyings(1, transform_feedback_varying_name); 242 243 gl3cts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader, transform_feedback_varyings); 244 245 if (program.ProgramStatus().program_id == 0) 246 { 247 m_testCtx.getLog() << tcu::TestLog::Message << "Program failed to build.\n Vertex Shader:\n" 248 << m_vertex_shader_code_case_0 << "\nVertex Shader compilation log:\n" 249 << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n" 250 << m_fragment_shader_code_case_0 << "\nWith Fragment Shader compilation log:\n" 251 << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n" 252 << program.FragmentShaderStatus().shader_log << "\n" 253 << tcu::TestLog::EndMessage; 254 return false; 255 } 256 257 program.UseProgram(); 258 259 /* Creating and binding empty VAO. */ 260 gl3cts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, GL_POINTS); 261 262 /* Creating and binding output VBO */ 263 gl3cts::ClipDistance::Utility::VertexBufferObject<glw::GLint> vertex_buffer_object(gl, GL_TRANSFORM_FEEDBACK_BUFFER, 264 std::vector<glw::GLint>(1, 0)); 265 266 /* Draw test. */ 267 vertex_array_object.drawWithTransformFeedback(0, 1, true); 268 269 /* Check results. */ 270 std::vector<glw::GLint> results = vertex_buffer_object.readBuffer(); 271 272 if (results.size() < 1) 273 { 274 m_testCtx.getLog() << tcu::TestLog::Message << "Results reading error." << tcu::TestLog::EndMessage; 275 return false; 276 } 277 278 if (results[0] != m_gl_max_clip_distances_value) 279 { 280 m_testCtx.getLog() << tcu::TestLog::Message 281 << "Vertex shader's gl_MaxClipDistances constant has improper value equal to " << results[0] 282 << "but " << m_gl_max_clip_distances_value << "is expected. Test failed." 283 << tcu::TestLog::EndMessage; 284 return false; 285 } 286 287 /* Test passed. */ 288 return true; 289 } 290 291 /* @brief gl_MaxClipDistances value test in the fragment shader coverage test. 292 * 293 * @param [in] gl OpenGL functions' access. 294 * 295 * @return True if passed, false otherwise. 296 */ 297 bool gl3cts::ClipDistance::CoverageTest::MaxClipDistancesValueInFragmentShaderTest(const glw::Functions& gl) 298 { 299 /* Make a program that consist of vertex and fragment shader stages. In 300 vertex shader setup gl_Position with passed in attribute. Check in 301 fragment shader using "if" statement that gl_MaxClipDistances is equal 302 to GL_MAX_CLIP_DISTANCES passed by uniform. If compared values are not 303 equal, discard the fragment. Output distinguishable color otherwise. 304 Check that the shader program compiles and links successfully. Draw a 305 single GL_POINT with screen centered position attribute and with a 306 configured 1 x 1 pixel size framebuffer. Using glReadPixels function, 307 check that point's fragments were not discarded. */ 308 309 /* Creating red-color-only frambuffer. */ 310 gl3cts::ClipDistance::Utility::Framebuffer framebuffer(gl, 1, 1); 311 312 if (!framebuffer.isValid()) 313 { 314 m_testCtx.getLog() << tcu::TestLog::Message << "Unable to create framebuffer with size [1,1].\n" 315 << tcu::TestLog::EndMessage; 316 return false; 317 } 318 319 framebuffer.bind(); 320 framebuffer.clear(); 321 322 /* Building program. */ 323 const std::string vertex_shader = m_vertex_shader_code_case_1; 324 const std::string fragment_shader = m_fragment_shader_code_case_1; 325 326 gl3cts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader); 327 328 if (program.ProgramStatus().program_id == 0) 329 { 330 m_testCtx.getLog() << tcu::TestLog::Message << "Program failed to build.\n Vertex Shader:\n" 331 << m_vertex_shader_code_case_1 << "\nVertex Shader compilation log:\n" 332 << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n" 333 << m_fragment_shader_code_case_1 << "\nWith Fragment Shader compilation log:\n" 334 << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n" 335 << program.FragmentShaderStatus().shader_log << "\n" 336 << tcu::TestLog::EndMessage; 337 return false; 338 } 339 340 program.UseProgram(); 341 342 /* Creating empty VAO. */ 343 gl3cts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, GL_POINTS); 344 345 /* Draw test. */ 346 vertex_array_object.draw(0, 1); 347 348 /* Fetch results. */ 349 std::vector<glw::GLfloat> pixels = framebuffer.readPixels(); 350 351 if (pixels.size() < 1) 352 { 353 m_testCtx.getLog() << tcu::TestLog::Message << "ReadPixels error.\n" << tcu::TestLog::EndMessage; 354 return false; 355 } 356 357 /* Check results. */ 358 glw::GLuint gl_max_clip_distances_value_in_fragment_shader = glw::GLuint(pixels.front()); 359 360 if (gl_max_clip_distances_value_in_fragment_shader != glw::GLuint(m_gl_max_clip_distances_value)) 361 { 362 m_testCtx.getLog() << tcu::TestLog::Message 363 << "Fragment shader's gl_MaxClipDistances constant has improper value equal to " 364 << gl_max_clip_distances_value_in_fragment_shader << "but " << m_gl_max_clip_distances_value 365 << "is expected. Test failed." << tcu::TestLog::EndMessage; 366 return false; 367 } 368 369 /* Test passed. */ 370 return true; 371 } 372 373 /* @brief Vertex shader to fragment shader passing coverage test. 374 * 375 * @param [in] gl OpenGL functions' access. 376 * 377 * @return True if passed, false otherwise. 378 */ 379 bool gl3cts::ClipDistance::CoverageTest::ClipDistancesValuePassing(const glw::Functions& gl) 380 { 381 /* Make a program that consist of vertex and fragment shader stages. 382 Redeclare gl_ClipDistance with size equal to GL_MAX_CLIP_DISTANCES in 383 vertex and fragment shader. In vertex shader, assign values to 384 gl_ClipDistance array using function of clip distance index i: 385 386 f(i) = float(i + 1) / float(gl_MaxClipDistances). 387 388 Setup gl_Position with passed in attribute. Read gl_ClipDistance in the 389 fragment shader and compare them with the same function. Take into 390 account low precision errors. If compared values are not equal, discard 391 the fragment. Output distinguishable color otherwise. Check that the 392 shaders compiles and the program links successfully. Enable all 393 GL_CLIP_DISTANCEs. Draw a single GL_POINT with screen centered position 394 attribute and with a configured 1 x 1 pixel size framebuffer. Using 395 glReadPixels function, check that point's fragments were not discarded. */ 396 397 /* Creating red-color-only frambuffer. */ 398 gl3cts::ClipDistance::Utility::Framebuffer framebuffer(gl, 1, 1); 399 400 if (!framebuffer.isValid()) 401 { 402 m_testCtx.getLog() << tcu::TestLog::Message << "Unable to create framebuffer with size [1,1].\n" 403 << tcu::TestLog::EndMessage; 404 return false; 405 } 406 407 framebuffer.bind(); 408 framebuffer.clear(); 409 410 /* Building program. */ 411 const std::string vertex_shader = m_vertex_shader_code_case_2; 412 const std::string fragment_shader = m_fragment_shader_code_case_2; 413 414 gl3cts::ClipDistance::Utility::Program program(gl, vertex_shader, fragment_shader); 415 416 if (program.ProgramStatus().program_id == 0) 417 { 418 m_testCtx.getLog() << tcu::TestLog::Message << "Program failed to build.\n Vertex Shader:\n" 419 << m_vertex_shader_code_case_2 << "\nVertex Shader compilation log:\n" 420 << program.VertexShaderStatus().shader_log << "\nWith Fragment Shader:\n" 421 << m_fragment_shader_code_case_2 << "\nWith Fragment Shader compilation log:\n" 422 << program.FragmentShaderStatus().shader_log << "\nWith Program linkage log:\n" 423 << program.FragmentShaderStatus().shader_log << "\n" 424 << tcu::TestLog::EndMessage; 425 return false; 426 } 427 428 program.UseProgram(); 429 430 /* Creating empty VAO. */ 431 gl3cts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, GL_POINTS); 432 433 /* Draw test. */ 434 vertex_array_object.draw(0, 1); 435 436 /* Fetch results. */ 437 std::vector<glw::GLfloat> pixels = framebuffer.readPixels(); 438 439 if (pixels.size() < 1) 440 { 441 m_testCtx.getLog() << tcu::TestLog::Message << "ReadPixels error.\n" << tcu::TestLog::EndMessage; 442 return false; 443 } 444 445 /* Check results. */ 446 glw::GLfloat results = pixels.front(); 447 448 if (fabs(results - 1.f) > 0.0125) 449 { 450 m_testCtx.getLog() << tcu::TestLog::Message 451 << "Fragment shader values of gl_Clip_distance does not match vertex shader's output value." 452 << tcu::TestLog::EndMessage; 453 return false; 454 } 455 456 /* Test passed. */ 457 return true; 458 } 459 460 /** @brief Vertex shader source code to test gl_MaxClipDistances limit value in vertex shader (API Coverage Test). */ 461 const glw::GLchar* gl3cts::ClipDistance::CoverageTest::m_vertex_shader_code_case_0 = 462 "#version 130\n" 463 "\n" 464 "out int max_value;\n" 465 "\n" 466 "void main()\n" 467 "{\n" 468 " max_value = gl_MaxClipDistances;\n" 469 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 470 "}\n"; 471 472 /** @brief Fragment shader source code to test gl_MaxClipDistances limit value in vertex shader (API Coverage Test). */ 473 const glw::GLchar* gl3cts::ClipDistance::CoverageTest::m_fragment_shader_code_case_0 = 474 "#version 130\n" 475 "\n" 476 "out vec4 color;\n" 477 "\n" 478 "void main()\n" 479 "{\n" 480 " color = vec4(0.0, 0.0, 0.0, 1.0);\n" 481 "}\n"; 482 483 /** @brief Vertex shader source code to test gl_MaxClipDistances limit value in fragment shader (API Coverage Test). */ 484 const glw::GLchar* gl3cts::ClipDistance::CoverageTest::m_vertex_shader_code_case_1 = 485 "#version 130\n" 486 "\n" 487 "void main()\n" 488 "{\n" 489 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 490 "}\n"; 491 492 /** @brief Fragment shader source code to test gl_MaxClipDistances limit value in fragment shader (API Coverage Test). */ 493 const glw::GLchar* gl3cts::ClipDistance::CoverageTest::m_fragment_shader_code_case_1 = 494 "#version 130\n" 495 "\n" 496 "out highp vec4 color;\n" 497 "\n" 498 "void main()\n" 499 "{\n" 500 " color = vec4(float(gl_MaxClipDistances), 0.0, 0.0, 1.0);\n" 501 "}\n"; 502 503 /** @brief Vertex shader source code to test if the gl_ClipDistance[] are passed properly to the fragment shader from vertex shader (API Coverage Test). */ 504 const glw::GLchar* gl3cts::ClipDistance::CoverageTest::m_vertex_shader_code_case_2 = 505 "#version 130\n" 506 "\n" 507 "out float gl_ClipDistance[gl_MaxClipDistances];\n" 508 "\n" 509 "void main()\n" 510 "{\n" 511 " for(int i = 0; i < gl_MaxClipDistances; i++)\n" 512 " {\n" 513 " gl_ClipDistance[i] = float(i + 1) / float(gl_MaxClipDistances);\n" 514 " }\n" 515 "\n" 516 " gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n" 517 "}\n"; 518 519 /** @brief Fragment shader source code to test if the gl_ClipDistance[] are passed properly to the fragment shader from vertex shader (API Coverage Test). */ 520 const glw::GLchar* gl3cts::ClipDistance::CoverageTest::m_fragment_shader_code_case_2 = 521 "#version 130\n" 522 "\n" 523 "in float gl_ClipDistance[gl_MaxClipDistances];\n" 524 "\n" 525 "out highp vec4 color;\n" 526 "\n" 527 "void main()\n" 528 "{\n" 529 " for(int i = 0; i < gl_MaxClipDistances; i++)\n" 530 " {\n" 531 " if(abs(gl_ClipDistance[i] - float(i + 1) / float(gl_MaxClipDistances)) > 0.0125)\n" 532 " {\n" 533 " discard;\n" 534 " }\n" 535 " }\n" 536 "\n" 537 " color = vec4(1.0, 0.0, 0.0, 1.0);\n" 538 "}\n"; 539 540 /******************************** Functional Tests Implementation ********************************/ 541 542 /** @brief Functional test constructor. 543 * 544 * @param [in] context OpenGL context. 545 */ 546 gl3cts::ClipDistance::FunctionalTest::FunctionalTest(deqp::Context& context) 547 : deqp::TestCase(context, "functional", "Clip Distance Functional Test") 548 , m_gl_max_clip_distances_value(8) /* Specification minimum required */ 549 { 550 /* Intentionally left blank */ 551 } 552 553 /** @brief Initialize functional test. */ 554 void gl3cts::ClipDistance::FunctionalTest::init() 555 { 556 /* Shortcut for GL functionality */ 557 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 558 559 gl.getIntegerv(GL_MAX_CLIP_DISTANCES, &m_gl_max_clip_distances_value); 560 561 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed."); 562 } 563 564 /** @brief Iterate functional test cases. 565 * 566 * @return Iteration result. 567 */ 568 tcu::TestNode::IterateResult gl3cts::ClipDistance::FunctionalTest::iterate() 569 { 570 /* Shortcut for GL functionality */ 571 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 572 573 /* This test should only be executed if we're running a GL>=3.0 context */ 574 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 0))) 575 { 576 throw tcu::NotSupportedError("GL_ARB_clip_distance is not supported"); 577 } 578 579 /* Functional test */ 580 581 /* For all primitive modes. */ 582 for (glw::GLuint i_primitive_type = 0; i_primitive_type < m_primitive_types_count; ++i_primitive_type) 583 { 584 glw::GLenum primitive_type = m_primitive_types[i_primitive_type]; 585 glw::GLenum primitive_indices_count = m_primitive_indices[i_primitive_type]; 586 587 /* Framebuffer setup. */ 588 glw::GLuint framebuffer_size = (primitive_type == GL_POINTS) ? 1 : 32; 589 590 gl3cts::ClipDistance::Utility::Framebuffer framebuffer(gl, framebuffer_size, 591 framebuffer_size); /* Framebuffer shall be square */ 592 593 framebuffer.bind(); 594 595 /* For all clip combinations. */ 596 for (glw::GLuint i_clip_function = 0; 597 i_clip_function < 598 m_clip_function_count - 599 int(i_primitive_type == GL_POINTS); /* Do not use last clip function with GL_POINTS. */ 600 ++i_clip_function) 601 { 602 /* For both redeclaration types (implicit/explicit). */ 603 for (glw::GLuint i_redeclaration = 0; i_redeclaration < 2; ++i_redeclaration) 604 { 605 bool redeclaration = (i_redeclaration == 1); 606 607 /* For different clip array sizes. */ 608 for (glw::GLuint i_clip_count = 1; i_clip_count <= glw::GLuint(m_gl_max_clip_distances_value); 609 ++i_clip_count) 610 { 611 /* Create and build program. */ 612 std::string vertex_shader_code = gl3cts::ClipDistance::FunctionalTest::prepareVertexShaderCode( 613 redeclaration, redeclaration, i_clip_count, i_clip_function, primitive_type); 614 615 gl3cts::ClipDistance::Utility::Program program(gl, vertex_shader_code, m_fragment_shader_code); 616 617 if (program.ProgramStatus().program_id == GL_NONE) 618 { 619 /* Result's setup. */ 620 m_testCtx.getLog() 621 << tcu::TestLog::Message 622 << "Functional test have failed when building program.\nVertex shader code:\n" 623 << vertex_shader_code << "\nFragment shader code:\n" 624 << m_fragment_shader_code << "\n" 625 << tcu::TestLog::EndMessage; 626 627 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 628 629 return STOP; 630 } 631 632 program.UseProgram(); 633 634 /* Framebuffer clear */ 635 framebuffer.clear(); 636 637 /* Clip setup */ 638 gl.enable(GL_CLIP_DISTANCE0 + i_clip_count - 1); 639 640 /* Geometry Setup */ 641 gl3cts::ClipDistance::Utility::VertexArrayObject vertex_array_object(gl, primitive_type); 642 643 gl3cts::ClipDistance::Utility::VertexBufferObject<glw::GLfloat>* vertex_buffer_object = 644 prepareGeometry(gl, primitive_type); 645 646 if (!vertex_buffer_object->useAsShaderInput(program, "position", 4)) 647 { 648 /* Result's setup. */ 649 m_testCtx.getLog() << tcu::TestLog::Message 650 << "Functional test have failed when enabling vertex attribute array.\n" 651 << tcu::TestLog::EndMessage; 652 653 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); 654 655 delete vertex_buffer_object; 656 return STOP; 657 } 658 659 /* Draw geometry to the framebuffer */ 660 vertex_array_object.draw(0, primitive_indices_count); 661 662 /* Check results */ 663 std::vector<glw::GLfloat> results = framebuffer.readPixels(); 664 665 if (!checkResults(primitive_type, i_clip_function, results)) 666 { 667 /* Result's setup. */ 668 m_testCtx.getLog() << tcu::TestLog::Message << "Functional test have failed when drawing " 669 << glu::getPrimitiveTypeStr(primitive_type) 670 << ((redeclaration) ? " with " : " without ") 671 << "dynamic redeclaration, when " << i_clip_count 672 << " GL_CLIP_DISTANCES where enabled and set up using function:\n" 673 << m_clip_function[i_clip_function] << tcu::TestLog::EndMessage; 674 675 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 676 677 delete vertex_buffer_object; 678 return STOP; 679 } 680 681 delete vertex_buffer_object; 682 } 683 684 /* Clip clean */ 685 for (glw::GLuint i_clip_count = 0; i_clip_count < glw::GLuint(m_gl_max_clip_distances_value); 686 ++i_clip_count) 687 { 688 gl.disable(GL_CLIP_DISTANCE0 + i_clip_count); 689 } 690 } 691 } 692 } 693 694 /* Result's setup. */ 695 696 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 697 698 return STOP; 699 } 700 701 /** @brief Prepare vertex shader code for functional test. 702 * 703 * @param [in] explicit_redeclaration Use explicit redeclaration with size. 704 * @param [in] dynamic_setter Use dynamic array setter. 705 * @param [in] clip_count Set all first # of gl_ClipDistance-s. 706 * @param [in] clip_function Use #th clip function for gl_ClipDistance[] setup (see m_clip_function[]). 707 * @param [in] primitive_type Primitive mode. 708 * 709 * @return Compilation ready vertex shader source code. 710 */ 711 std::string gl3cts::ClipDistance::FunctionalTest::prepareVertexShaderCode(bool explicit_redeclaration, 712 bool dynamic_setter, glw::GLuint clip_count, 713 glw::GLuint clip_function, 714 glw::GLenum primitive_type) 715 { 716 std::string vertex_shader = m_vertex_shader_code; 717 718 if (explicit_redeclaration) 719 { 720 vertex_shader = gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_REDECLARATION", 721 m_explicit_redeclaration); 722 } 723 else 724 { 725 vertex_shader = gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_REDECLARATION", ""); 726 } 727 728 if (dynamic_setter) 729 { 730 vertex_shader = 731 gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_SETUP", m_dynamic_array_setter); 732 } 733 else 734 { 735 std::string static_setters = ""; 736 737 for (glw::GLuint i = 0; i < clip_count; ++i) 738 { 739 std::string i_setter = m_static_array_setter; 740 741 i_setter = gl3cts::ClipDistance::Utility::preprocessCode(i_setter, "CLIP_INDEX", 742 gl3cts::ClipDistance::Utility::itoa(i)); 743 744 static_setters.append(i_setter); 745 } 746 747 vertex_shader = 748 gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_DISTANCE_SETUP", static_setters); 749 } 750 751 vertex_shader = 752 gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_FUNCTION", m_clip_function[clip_function]); 753 754 vertex_shader = gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "CLIP_COUNT", 755 gl3cts::ClipDistance::Utility::itoa(clip_count)); 756 757 switch (primitive_type) 758 { 759 case GL_POINTS: 760 vertex_shader = gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "VERTEX_COUNT", "1"); 761 break; 762 case GL_LINES: 763 vertex_shader = gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "VERTEX_COUNT", "2"); 764 break; 765 case GL_TRIANGLES: 766 vertex_shader = gl3cts::ClipDistance::Utility::preprocessCode(vertex_shader, "VERTEX_COUNT", "3"); 767 break; 768 } 769 770 return vertex_shader; 771 } 772 773 /** @brief Prepare geometry for functional test. 774 * 775 * @param [in] gl OpenGL functions' access. 776 * @param [in] primitive_type Primitive mode. 777 * 778 * @return Vertex Buffer Object pointer. 779 */ 780 gl3cts::ClipDistance::Utility::VertexBufferObject<glw::GLfloat>* gl3cts::ClipDistance::FunctionalTest::prepareGeometry( 781 const glw::Functions& gl, const glw::GLenum primitive_type) 782 { 783 std::vector<glw::GLfloat> data; 784 785 switch (primitive_type) 786 { 787 case GL_POINTS: 788 data.push_back(0.0); 789 data.push_back(0.0); 790 data.push_back(0.0); 791 data.push_back(1.0); 792 break; 793 case GL_LINES: 794 data.push_back(1.0); 795 data.push_back(1.0); 796 data.push_back(0.0); 797 data.push_back(1.0); 798 data.push_back(-1.0); 799 data.push_back(-1.0); 800 data.push_back(0.0); 801 data.push_back(1.0); 802 break; 803 case GL_TRIANGLES: 804 data.push_back(-1.0); 805 data.push_back(-1.0); 806 data.push_back(0.0); 807 data.push_back(1.0); 808 data.push_back(0.0); 809 data.push_back(1.0); 810 data.push_back(0.0); 811 data.push_back(1.0); 812 data.push_back(1.0); 813 data.push_back(-1.0); 814 data.push_back(0.0); 815 data.push_back(1.0); 816 break; 817 default: 818 return NULL; 819 } 820 821 return new gl3cts::ClipDistance::Utility::VertexBufferObject<glw::GLfloat>(gl, GL_ARRAY_BUFFER, data); 822 } 823 824 /** @brief Check results fetched from framebuffer of functional test. 825 * 826 * @param [in] primitive_type Primitive mode. 827 * @param [in] clip_function Use #th clip function for gl_ClipDistance[] setup (see m_clip_function[]). 828 * @param [in] results Array with framebuffer content. 829 * 830 * @return True if proper result, false otherwise. 831 */ 832 bool gl3cts::ClipDistance::FunctionalTest::checkResults(glw::GLenum primitive_type, glw::GLuint clip_function, 833 std::vector<glw::GLfloat>& results) 834 { 835 /* Check for errors */ 836 if (results.size() == 0) 837 { 838 return false; 839 } 840 841 /* Calculate surface/line integral */ 842 glw::GLfloat integral = 0.f; 843 844 glw::GLuint increment = (glw::GLuint)((primitive_type == GL_LINES) ? 845 glw::GLuint(sqrt(glw::GLfloat(results.size()))) + 1 /* line integral */ : 846 1 /* surface integral */); 847 glw::GLuint base = (glw::GLuint)((primitive_type == GL_LINES) ? 848 glw::GLuint(sqrt(glw::GLfloat(results.size()))) /* line integral */ : 849 results.size() /* surface integral */); 850 851 for (glw::GLuint i_pixels = 0; i_pixels < results.size(); i_pixels += increment) 852 { 853 integral += results[i_pixels]; 854 } 855 856 integral /= static_cast<glw::GLfloat>(base); 857 858 /* Check with results' lookup table */ 859 glw::GLuint i_primitive_type = (primitive_type == GL_POINTS) ? 0 : ((primitive_type == GL_LINES) ? 1 : 2); 860 861 if (fabs(m_expected_integral[i_primitive_type * m_clip_function_count + clip_function] - integral) > 862 0.01 /* Precision */) 863 { 864 return false; 865 } 866 867 return true; 868 } 869 870 /* @brief Vertex Shader template for functional tests. */ 871 const glw::GLchar* gl3cts::ClipDistance::FunctionalTest::m_vertex_shader_code = "#version 130\n" 872 "\n" 873 "CLIP_DISTANCE_REDECLARATION" 874 "\n" 875 "CLIP_FUNCTION" 876 "\n" 877 "in vec4 position;\n" 878 "\n" 879 "void main()\n" 880 "{\n" 881 "CLIP_DISTANCE_SETUP" 882 "\n" 883 " gl_Position = position;\n" 884 "}\n"; 885 886 /* @brief Explicit redeclaration key value to preprocess the Vertex Shader template for functional tests. */ 887 const glw::GLchar* gl3cts::ClipDistance::FunctionalTest::m_explicit_redeclaration = 888 "out float gl_ClipDistance[CLIP_COUNT];\n"; 889 890 /* @brief Dynamic array setter key value to preprocess the Vertex Shader template for functional tests. */ 891 const glw::GLchar* gl3cts::ClipDistance::FunctionalTest::m_dynamic_array_setter = 892 " for(int i = 0; i < CLIP_COUNT; i++)\n" 893 " {\n" 894 " gl_ClipDistance[i] = f(i);\n" 895 " }\n"; 896 897 /* @brief Static array setter key value to preprocess the Vertex Shader template for functional tests. */ 898 const glw::GLchar* gl3cts::ClipDistance::FunctionalTest::m_static_array_setter = 899 " gl_ClipDistance[CLIP_INDEX] = f(CLIP_INDEX);\n"; 900 901 /* @brief Clip Distance functions to preprocess the Vertex Shader template for functional tests. */ 902 const glw::GLchar* gl3cts::ClipDistance::FunctionalTest::m_clip_function[] = { 903 "float f(int i)\n" 904 "{\n" 905 " return 0.0;\n" 906 "}\n", 907 908 "float f(int i)\n" 909 "{\n" 910 " return 0.25 + 0.75 * (float(i) + 1.0) * (float(gl_VertexID) + 1.0) / (float(CLIP_COUNT) * " 911 "float(VERTEX_COUNT));\n" 912 "}\n", 913 914 "float f(int i)\n" 915 "{\n" 916 " return - 0.25 - 0.75 * (float(i) + 1.0) * (float(gl_VertexID) + 1.0) / (float(CLIP_COUNT) * " 917 "float(VERTEX_COUNT));\n" 918 "}\n", 919 920 /* This case must be last (it is not rendered for GL_POINTS). */ 921 "#define PI 3.1415926535897932384626433832795\n" 922 "\n" 923 "float f(int i)\n" 924 "{\n" 925 " if(i == 0)\n" 926 " {\n" 927 /* This function case generates such series of gl_VertexID: 928 1.0, -1.0 - for VERTEX_COUNT == 2 aka GL_LINES 929 1.0, 0.0, -1.0 - for VERTEX_COUNT == 3 aka GL_TRIANGLES 930 and if needed in future: 931 1.0, 0.0, -1.0, 0.0 - for VERTEX_COUNT == 4 aka GL_QUADS */ 932 " return cos( gl_VertexID * PI / ceil( float(VERTEX_COUNT)/2.0 ) );\n" 933 " }\n" 934 "\n" 935 " return 0.25 + 0.75 * (float(i) + 1.0) * (float(gl_VertexID) + 1.0) / (float(CLIP_COUNT) * " 936 "float(VERTEX_COUNT));\n" 937 "}\n" 938 }; 939 940 /* @brief Count of Clip Distance functions. */ 941 const glw::GLuint gl3cts::ClipDistance::FunctionalTest::m_clip_function_count = 942 static_cast<glw::GLuint>(sizeof(m_clip_function) / sizeof(m_clip_function[0])); 943 944 /* @brief Fragment shader source code for functional tests. */ 945 const glw::GLchar* gl3cts::ClipDistance::FunctionalTest::m_fragment_shader_code = 946 "#version 130\n" 947 "\n" 948 "out highp vec4 color;\n" 949 "\n" 950 "void main()\n" 951 "{\n" 952 " color = vec4(1.0, 0.0, 0.0, 1.0);\n" 953 "}\n"; 954 955 /* @brief Primitive modes to be tested in functional test. */ 956 const glw::GLenum gl3cts::ClipDistance::FunctionalTest::m_primitive_types[] = { GL_POINTS, GL_LINES, GL_TRIANGLES }; 957 958 /* @brief Number of primitive indices for each primitive mode. */ 959 const glw::GLenum gl3cts::ClipDistance::FunctionalTest::m_primitive_indices[] = { 1, 2, 3 }; 960 961 /* @brief Primitive modes count. */ 962 const glw::GLuint gl3cts::ClipDistance::FunctionalTest::m_primitive_types_count = 963 static_cast<glw::GLuint>(sizeof(m_primitive_types) / sizeof(m_primitive_types[0])); 964 965 /* @brief Expected results of testing integral for functional test. */ 966 const glw::GLfloat 967 gl3cts::ClipDistance::FunctionalTest::m_expected_integral[m_primitive_types_count * m_clip_function_count] = { 968 1.0, 1.0, 0.0, 0.0, /* for GL_POINTS */ 969 1.0, 1.0, 0.0, 0.5, /* for GL_LINES */ 970 0.5, 0.5, 0.0, 0.25 /* for GL_TRIANGLES */ 971 }; 972 973 /******************************** Negative Tests Implementation ********************************/ 974 975 /** @brief Negative tests constructor. 976 * 977 * @param [in] context OpenGL context. 978 */ 979 gl3cts::ClipDistance::NegativeTest::NegativeTest(deqp::Context& context) 980 : deqp::TestCase(context, "negative", "Clip Distance Negative Tests") 981 { 982 /* Intentionally left blank */ 983 } 984 985 /** @brief Iterate negative tests 986 * 987 * @return Iteration result. 988 */ 989 tcu::TestNode::IterateResult gl3cts::ClipDistance::NegativeTest::iterate() 990 { 991 /* Shortcut for GL functionality */ 992 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 993 994 /* Iterate tests */ 995 bool is_ok = true; 996 bool may_be_ok = true; 997 998 is_ok = is_ok && testClipVertexBuildingErrors(gl); 999 is_ok = is_ok && testMaxClipDistancesBuildingErrors(gl); 1000 may_be_ok = may_be_ok && testClipDistancesRedeclarationBuildingErrors(gl); 1001 1002 /* Result's setup. */ 1003 if (is_ok) 1004 { 1005 if (may_be_ok) 1006 { 1007 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1008 } 1009 else 1010 { 1011 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Pass with warning"); 1012 } 1013 } 1014 else 1015 { 1016 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 1017 } 1018 1019 return STOP; 1020 } 1021 1022 /** @brief Clip Distance / Clip Vertex negative test sub-case. 1023 * 1024 * @param [in] gl OpenGL functions' access. 1025 * 1026 * @return True if passed, false otherwise. 1027 */ 1028 bool gl3cts::ClipDistance::NegativeTest::testClipVertexBuildingErrors(const glw::Functions& gl) 1029 { 1030 /* If OpenGL version < 3.1 is available, check that building shader program 1031 fails when vertex shader statically writes to both gl_ClipVertex and 1032 gl_ClipDistance[0]. Validate that the vertex shader which statically 1033 writes to only the gl_ClipVertex or to the gl_ClipDistance[0] builds 1034 without fail. */ 1035 1036 /* This test should only be executed if we're running a GL3.0 or less context */ 1037 if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType(3, 1, glu::PROFILE_CORE))) 1038 { 1039 return true; 1040 } 1041 1042 gl3cts::ClipDistance::Utility::Program program(gl, m_vertex_shader_code_case_0, m_fragment_shader_code); 1043 1044 if (program.ProgramStatus().program_id) 1045 { 1046 m_testCtx.getLog() << tcu::TestLog::Message << "Functional test have failed. " 1047 "Building shader which statically writes to both gl_ClipVertex " 1048 "and gl_ClipDistances[] has unexpectedly succeeded." 1049 << tcu::TestLog::EndMessage; 1050 1051 return false; 1052 } 1053 1054 return true; 1055 } 1056 1057 /** @brief Explicit redeclaration negative test sub-case. 1058 * 1059 * @param [in] gl OpenGL functions' access. 1060 * 1061 * @return True if passed, false otherwise. 1062 */ 1063 bool gl3cts::ClipDistance::NegativeTest::testMaxClipDistancesBuildingErrors(const glw::Functions& gl) 1064 { 1065 /* Check that building shader program fails when gl_ClipDistance is 1066 redeclared in the shader with size higher than GL_MAX_CLIP_DISTANCES. */ 1067 1068 gl3cts::ClipDistance::Utility::Program program(gl, m_vertex_shader_code_case_1, m_fragment_shader_code); 1069 1070 if (program.ProgramStatus().program_id) 1071 { 1072 m_testCtx.getLog() << tcu::TestLog::Message 1073 << "Functional test have failed. " 1074 "Building shader with explicit redeclaration of gl_ClipDistance[] array with size " 1075 "(gl_MaxClipDistances + 1) has unexpectedly succeeded." 1076 << tcu::TestLog::EndMessage; 1077 1078 return false; 1079 } 1080 1081 return true; 1082 } 1083 1084 /** @brief Implicit redeclaration negative test sub-case. 1085 * 1086 * @param [in] gl OpenGL functions' access. 1087 * 1088 * @return True if passed, false when quality warning occured. 1089 */ 1090 bool gl3cts::ClipDistance::NegativeTest::testClipDistancesRedeclarationBuildingErrors(const glw::Functions& gl) 1091 { 1092 /* Check that building shader program fails when gl_ClipDistance is not 1093 redeclared with explicit size and dynamic indexing is used.*/ 1094 1095 gl3cts::ClipDistance::Utility::Program program(gl, m_vertex_shader_code_case_2, m_fragment_shader_code); 1096 1097 if (program.ProgramStatus().program_id) 1098 { 1099 m_testCtx.getLog() 1100 << tcu::TestLog::Message 1101 << "Functional test have passed but with warning. " 1102 "Building shader without explicit redeclaration and with variable indexing has unexpectedly succeeded. " 1103 "This is within the bound of the specification (no error is being), but it may lead to errors." 1104 << tcu::TestLog::EndMessage; 1105 1106 return false; 1107 } 1108 1109 return true; 1110 } 1111 1112 /** @brief Vertex shader source code for gl_ClipVertex negative test. */ 1113 const glw::GLchar* gl3cts::ClipDistance::NegativeTest::m_vertex_shader_code_case_0 = 1114 "#version 130\n" 1115 "\n" 1116 "void main()\n" 1117 "{\n" 1118 " gl_ClipDistance[0] = 0.0;\n" 1119 " gl_ClipVertex = vec4(0.0);\n" 1120 " gl_Position = vec4(1.0);\n" 1121 "}\n"; 1122 1123 /** @brief Vertex shader source code for explicit redeclaration negative test. */ 1124 const glw::GLchar* gl3cts::ClipDistance::NegativeTest::m_vertex_shader_code_case_1 = 1125 "#version 130\n" 1126 "\n" 1127 "out float gl_ClipDistance[gl_MaxClipDistances + 1];\n" 1128 "\n" 1129 "void main()\n" 1130 "{\n" 1131 " gl_ClipDistance[0] = 0.0;\n" 1132 " gl_Position = vec4(1.0);\n" 1133 "}\n"; 1134 1135 /** @brief Vertex shader source code for impilicit redeclaration negative test. */ 1136 const glw::GLchar* gl3cts::ClipDistance::NegativeTest::m_vertex_shader_code_case_2 = 1137 "#version 130\n" 1138 "\n" 1139 "in int count;\n" 1140 "\n" 1141 "void main()\n" 1142 "{\n" 1143 " for(int i = 0; i < count; i++)\n" 1144 " {\n" 1145 " gl_ClipDistance[i] = 0.0;\n" 1146 " }\n" 1147 "\n" 1148 " gl_Position = vec4(1.0);\n" 1149 "}\n"; 1150 1151 /** @brief Simple passthrough fragment shader source code for negative tests. */ 1152 const glw::GLchar* gl3cts::ClipDistance::NegativeTest::m_fragment_shader_code = 1153 "#version 130\n" 1154 "\n" 1155 "out vec4 color;\n" 1156 "\n" 1157 "void main()\n" 1158 "{\n" 1159 " color = vec4(0.0, 0.0, 0.0, 1.0);\n" 1160 "}\n"; 1161 1162 /******************************** Utility Clases Implementations ********************************/ 1163 1164 /** @brief Program constructor. 1165 * 1166 * @param [in] gl OpenGL functions' access. 1167 * @param [in] vertex_shader_code Vertex shader source code. 1168 * @param [in] fragment_shader_code Fragment shader source code. 1169 * @param [in] transform_feedback_varyings Transform feedback varying names. 1170 */ 1171 gl3cts::ClipDistance::Utility::Program::Program(const glw::Functions& gl, const std::string& vertex_shader_code, 1172 const std::string& fragment_shader_code, 1173 std::vector<std::string> transform_feedback_varyings) 1174 : m_gl(gl) 1175 { 1176 /* Compilation */ 1177 const glw::GLchar* vertex_shader_code_c = (const glw::GLchar*)vertex_shader_code.c_str(); 1178 const glw::GLchar* fragment_shader_code_c = (const glw::GLchar*)fragment_shader_code.c_str(); 1179 1180 m_vertex_shader_status = compileShader(GL_VERTEX_SHADER, &vertex_shader_code_c); 1181 m_fragment_shader_status = compileShader(GL_FRAGMENT_SHADER, &fragment_shader_code_c); 1182 1183 /* Linking */ 1184 m_program_status.program_id = 0; 1185 if (m_vertex_shader_status.shader_compilation_status && m_fragment_shader_status.shader_compilation_status) 1186 { 1187 m_program_status = linkShaders(m_vertex_shader_status, m_fragment_shader_status, transform_feedback_varyings); 1188 } 1189 1190 /* Cleaning */ 1191 if (m_vertex_shader_status.shader_id) 1192 { 1193 m_gl.deleteShader(m_vertex_shader_status.shader_id); 1194 1195 m_vertex_shader_status.shader_id = 0; 1196 } 1197 1198 if (m_fragment_shader_status.shader_id) 1199 { 1200 m_gl.deleteShader(m_fragment_shader_status.shader_id); 1201 1202 m_fragment_shader_status.shader_id = 0; 1203 } 1204 } 1205 1206 /** @brief Program destructor. */ 1207 gl3cts::ClipDistance::Utility::Program::~Program() 1208 { 1209 if (m_vertex_shader_status.shader_id) 1210 { 1211 m_gl.deleteShader(m_vertex_shader_status.shader_id); 1212 1213 m_vertex_shader_status.shader_id = 0; 1214 } 1215 1216 if (m_fragment_shader_status.shader_id) 1217 { 1218 m_gl.deleteShader(m_fragment_shader_status.shader_id); 1219 1220 m_fragment_shader_status.shader_id = 0; 1221 } 1222 1223 if (m_program_status.program_id) 1224 { 1225 m_gl.deleteProgram(m_program_status.program_id); 1226 1227 m_program_status.program_id = 0; 1228 } 1229 } 1230 1231 /** @brief Vertex shader compilation status getter. 1232 * 1233 * @return Vertex shader compilation status. 1234 */ 1235 const gl3cts::ClipDistance::Utility::Program::CompilationStatus& gl3cts::ClipDistance::Utility::Program:: 1236 VertexShaderStatus() const 1237 { 1238 return m_vertex_shader_status; 1239 } 1240 1241 /** @brief Fragment shader compilation status getter. 1242 * 1243 * @return Fragment shader compilation status. 1244 */ 1245 const gl3cts::ClipDistance::Utility::Program::CompilationStatus& gl3cts::ClipDistance::Utility::Program:: 1246 FragmentShaderStatus() const 1247 { 1248 return m_fragment_shader_status; 1249 } 1250 1251 /** @brief Program building status getter. 1252 * 1253 * @return Program linkage status. 1254 */ 1255 const gl3cts::ClipDistance::Utility::Program::LinkageStatus& gl3cts::ClipDistance::Utility::Program::ProgramStatus() 1256 const 1257 { 1258 return m_program_status; 1259 } 1260 1261 /** @brief Compile shader. 1262 * 1263 * @param [in] shader_type Shader type. 1264 * @param [in] shader_code Shader source code. 1265 * 1266 * @return Compilation status. 1267 */ 1268 gl3cts::ClipDistance::Utility::Program::CompilationStatus gl3cts::ClipDistance::Utility::Program::compileShader( 1269 const glw::GLenum shader_type, const glw::GLchar* const* shader_code) 1270 { 1271 CompilationStatus shader = { 0, GL_NONE, "" }; 1272 1273 if (shader_code != DE_NULL) 1274 { 1275 try 1276 { 1277 /* Creation */ 1278 shader.shader_id = m_gl.createShader(shader_type); 1279 1280 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader() call failed."); 1281 1282 /* Compilation */ 1283 m_gl.shaderSource(shader.shader_id, 1, shader_code, NULL); 1284 1285 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource() call failed."); 1286 1287 m_gl.compileShader(shader.shader_id); 1288 1289 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader() call failed."); 1290 1291 /* Status */ 1292 m_gl.getShaderiv(shader.shader_id, GL_COMPILE_STATUS, &shader.shader_compilation_status); 1293 1294 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv() call failed."); 1295 1296 /* Logging */ 1297 if (shader.shader_compilation_status == GL_FALSE) 1298 { 1299 glw::GLint log_size = 0; 1300 1301 m_gl.getShaderiv(shader.shader_id, GL_INFO_LOG_LENGTH, &log_size); 1302 1303 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv() call failed."); 1304 1305 if (log_size) 1306 { 1307 glw::GLchar* log = new glw::GLchar[log_size]; 1308 1309 if (log) 1310 { 1311 memset(log, 0, log_size); 1312 1313 m_gl.getShaderInfoLog(shader.shader_id, log_size, DE_NULL, log); 1314 1315 shader.shader_log = log; 1316 1317 delete[] log; 1318 1319 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderInfoLog() call failed."); 1320 } 1321 } 1322 } 1323 } 1324 catch (...) 1325 { 1326 if (shader.shader_id) 1327 { 1328 m_gl.deleteShader(shader.shader_id); 1329 1330 shader.shader_id = 0; 1331 } 1332 } 1333 } 1334 1335 return shader; 1336 } 1337 1338 /** @brief Link compiled shaders. 1339 * 1340 * @param [in] vertex_shader Vertex shader compilation status. 1341 * @param [in] fragment_shader Fragment shader compilation status. 1342 * @param [in] transform_feedback_varyings Transform feedback varying names array. 1343 * 1344 * @return Linkage status. 1345 */ 1346 gl3cts::ClipDistance::Utility::Program::LinkageStatus gl3cts::ClipDistance::Utility::Program::linkShaders( 1347 const CompilationStatus& vertex_shader, const CompilationStatus& fragment_shader, 1348 std::vector<std::string>& transform_feedback_varyings) 1349 { 1350 LinkageStatus program = { 0, GL_NONE, "" }; 1351 1352 if (vertex_shader.shader_id && fragment_shader.shader_id) 1353 { 1354 try 1355 { 1356 /* Creation */ 1357 program.program_id = m_gl.createProgram(); 1358 1359 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader() call failed."); 1360 1361 if (program.program_id) 1362 { 1363 /* Transform Feedback setup */ 1364 for (std::vector<std::string>::iterator i = transform_feedback_varyings.begin(); 1365 i != transform_feedback_varyings.end(); ++i) 1366 { 1367 const glw::GLchar* varying = i->c_str(); 1368 1369 m_gl.transformFeedbackVaryings(program.program_id, 1, &varying, GL_INTERLEAVED_ATTRIBS); 1370 1371 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings() call failed."); 1372 } 1373 1374 /* Linking */ 1375 m_gl.attachShader(program.program_id, vertex_shader.shader_id); 1376 1377 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader() call failed."); 1378 1379 m_gl.attachShader(program.program_id, fragment_shader.shader_id); 1380 1381 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glAttachShader() call failed."); 1382 1383 m_gl.linkProgram(program.program_id); 1384 1385 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glLinkProgram() call failed."); 1386 1387 /* Status query */ 1388 m_gl.getProgramiv(program.program_id, GL_LINK_STATUS, &program.program_linkage_status); 1389 1390 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv() call failed."); 1391 1392 /* Logging */ 1393 if (program.program_linkage_status == GL_FALSE) 1394 { 1395 glw::GLint log_size = 0; 1396 1397 m_gl.getProgramiv(program.program_id, GL_INFO_LOG_LENGTH, &log_size); 1398 1399 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramiv() call failed."); 1400 1401 if (log_size) 1402 { 1403 glw::GLchar* log = new glw::GLchar[log_size]; 1404 1405 if (log) 1406 { 1407 memset(log, 0, log_size); 1408 1409 m_gl.getProgramInfoLog(program.program_id, log_size, DE_NULL, log); 1410 1411 program.program_linkage_log = log; 1412 1413 delete[] log; 1414 1415 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetProgramInfoLog() call failed."); 1416 } 1417 } 1418 } 1419 1420 /* Cleanup */ 1421 m_gl.detachShader(program.program_id, vertex_shader.shader_id); 1422 1423 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader() call failed."); 1424 1425 m_gl.detachShader(program.program_id, fragment_shader.shader_id); 1426 1427 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDetachShader() call failed."); 1428 1429 if (program.program_linkage_status == GL_FALSE) 1430 { 1431 m_gl.deleteProgram(program.program_id); 1432 1433 program.program_id = 0; 1434 } 1435 } 1436 } 1437 catch (...) 1438 { 1439 if (program.program_id) 1440 { 1441 m_gl.deleteProgram(program.program_id); 1442 1443 program.program_id = 0; 1444 } 1445 } 1446 } 1447 1448 return program; 1449 } 1450 1451 /** @brief Use program for drawing. */ 1452 void gl3cts::ClipDistance::Utility::Program::UseProgram() const 1453 { 1454 m_gl.useProgram(ProgramStatus().program_id); 1455 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram call failed."); 1456 } 1457 1458 /** @brief Framebuffer (GL_32R only) constructor. 1459 * 1460 * @param [in] gl OpenGL functions access. 1461 * @param [in] size_x X size of framebuffer. 1462 * @param [in] size_y Y size of framebuffer. 1463 */ 1464 gl3cts::ClipDistance::Utility::Framebuffer::Framebuffer(const glw::Functions& gl, const glw::GLsizei size_x, 1465 const glw::GLsizei size_y) 1466 : m_gl(gl), m_size_x(size_x), m_size_y(size_y), m_framebuffer_id(0), m_renderbuffer_id(0) 1467 { 1468 m_gl.genFramebuffers(1, &m_framebuffer_id); 1469 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenFramebuffers call failed."); 1470 1471 m_gl.genRenderbuffers(1, &m_renderbuffer_id); 1472 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenRenderbuffers call failed."); 1473 1474 m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_id); 1475 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer call failed."); 1476 1477 m_gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer_id); 1478 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindRenderbuffer call failed."); 1479 1480 m_gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32F, m_size_x, m_size_y); 1481 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glRenderbufferStorage call failed."); 1482 1483 m_gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer_id); 1484 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFramebufferRenderbuffer call failed."); 1485 1486 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 1487 { 1488 m_gl.deleteFramebuffers(1, &m_framebuffer_id); 1489 m_framebuffer_id = 0; 1490 1491 m_gl.deleteRenderbuffers(1, &m_renderbuffer_id); 1492 m_renderbuffer_id = 0; 1493 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteRenderbuffers call failed."); 1494 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteFramebuffers call failed."); 1495 } 1496 } 1497 1498 /** @brief Framebuffer destructor */ 1499 gl3cts::ClipDistance::Utility::Framebuffer::~Framebuffer() 1500 { 1501 if (m_framebuffer_id) 1502 { 1503 m_gl.deleteFramebuffers(1, &m_framebuffer_id); 1504 m_framebuffer_id = 0; 1505 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteFramebuffers call failed."); 1506 } 1507 1508 if (m_renderbuffer_id) 1509 { 1510 m_gl.deleteRenderbuffers(1, &m_renderbuffer_id); 1511 m_renderbuffer_id = 0; 1512 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteRenderbuffers call failed."); 1513 } 1514 } 1515 1516 /** @brief Check frambuffer completness. 1517 * 1518 * @return True if valid, false otherwise. 1519 */ 1520 bool gl3cts::ClipDistance::Utility::Framebuffer::isValid() 1521 { 1522 if (m_framebuffer_id) 1523 { 1524 return true; 1525 } 1526 1527 return false; 1528 } 1529 1530 /** @brief Bind framebuffer and setup viewport. */ 1531 void gl3cts::ClipDistance::Utility::Framebuffer::bind() 1532 { 1533 m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_id); 1534 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindFramebuffer call failed."); 1535 1536 m_gl.viewport(0, 0, m_size_x, m_size_y); 1537 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glViewport call failed."); 1538 } 1539 1540 /** @brief Read pixels from framebuffer. 1541 * 1542 * @return Vector of read pixels. 1543 */ 1544 std::vector<glw::GLfloat> gl3cts::ClipDistance::Utility::Framebuffer::readPixels() 1545 { 1546 std::vector<glw::GLfloat> pixels(m_size_x * m_size_y); 1547 1548 if ((m_size_x > 0) && (m_size_y > 0)) 1549 { 1550 m_gl.readPixels(0, 0, m_size_x, m_size_y, GL_RED, GL_FLOAT, pixels.data()); 1551 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glReadPixels call failed."); 1552 } 1553 1554 return pixels; 1555 } 1556 1557 /** @brief Clear framebuffer. */ 1558 void gl3cts::ClipDistance::Utility::Framebuffer::clear() 1559 { 1560 if (isValid()) 1561 { 1562 m_gl.clearColor(0.f, 0.f, 0.f, 1.f); 1563 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor call failed."); 1564 1565 m_gl.clear(GL_COLOR_BUFFER_BIT); 1566 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear call failed."); 1567 } 1568 } 1569 1570 /** @brief Vertex array object constructor. 1571 * 1572 * @note It silently binds VAO to OpenGL. 1573 * 1574 * @param [in] gl OpenGL functions access. 1575 * @param [in] primitive_type Primitive mode. 1576 */ 1577 gl3cts::ClipDistance::Utility::VertexArrayObject::VertexArrayObject(const glw::Functions& gl, 1578 const glw::GLenum primitive_type) 1579 : m_gl(gl), m_vertex_array_object_id(0), m_primitive_type(primitive_type) 1580 { 1581 m_gl.genVertexArrays(1, &m_vertex_array_object_id); 1582 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenVertexArrays call failed."); 1583 1584 m_gl.bindVertexArray(m_vertex_array_object_id); 1585 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray call failed."); 1586 } 1587 1588 /** @brief Vertex array object destructor. */ 1589 gl3cts::ClipDistance::Utility::VertexArrayObject::~VertexArrayObject() 1590 { 1591 if (m_vertex_array_object_id) 1592 { 1593 m_gl.deleteVertexArrays(1, &m_vertex_array_object_id); 1594 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteVertexArrays call failed."); 1595 } 1596 } 1597 1598 /** @brief Bind vertex array object. */ 1599 void gl3cts::ClipDistance::Utility::VertexArrayObject::bind() 1600 { 1601 if (m_vertex_array_object_id) 1602 { 1603 m_gl.bindVertexArray(m_vertex_array_object_id); 1604 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindVertexArray call failed."); 1605 } 1606 } 1607 1608 /** @brief Draw array. 1609 * 1610 * @param [in] first First index to be drawn. 1611 * @param [in] count Count of indices to be drawn. 1612 */ 1613 void gl3cts::ClipDistance::Utility::VertexArrayObject::draw(glw::GLuint first, glw::GLuint count) 1614 { 1615 m_gl.drawArrays(m_primitive_type, first, count); 1616 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() call failed."); 1617 } 1618 1619 /** @brief Draw array and fetch transform feedback varyings. 1620 * 1621 * @param [in] first First index to be drawn. 1622 * @param [in] count Count of indices to be drawn. 1623 * @param [in] discard_rasterizer Shall we discard rasterizer? 1624 */ 1625 void gl3cts::ClipDistance::Utility::VertexArrayObject::drawWithTransformFeedback(glw::GLuint first, glw::GLuint count, 1626 bool discard_rasterizer) 1627 { 1628 if (discard_rasterizer) 1629 { 1630 m_gl.enable(GL_RASTERIZER_DISCARD); 1631 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnable call failed."); 1632 } 1633 1634 m_gl.beginTransformFeedback(GL_POINTS); 1635 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback call failed."); 1636 1637 draw(first, count); 1638 1639 m_gl.endTransformFeedback(); 1640 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback call failed."); 1641 1642 if (discard_rasterizer) 1643 { 1644 m_gl.disable(GL_RASTERIZER_DISCARD); 1645 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisbale call failed."); 1646 } 1647 } 1648 1649 /** @brief Substitute key with value within source code. 1650 * 1651 * @param [in] source Source code to be prerocessed. 1652 * @param [in] key Key to be substituted. 1653 * @param [in] value Value to be inserted. 1654 * 1655 * @return Resulting string. 1656 */ 1657 std::string gl3cts::ClipDistance::Utility::preprocessCode(std::string source, std::string key, std::string value) 1658 { 1659 std::string destination = source; 1660 1661 while (true) 1662 { 1663 /* Find token in source code. */ 1664 size_t position = destination.find(key, 0); 1665 1666 /* No more occurences of this key. */ 1667 if (position == std::string::npos) 1668 { 1669 break; 1670 } 1671 1672 /* Replace token with sub_code. */ 1673 destination.replace(position, key.size(), value); 1674 } 1675 1676 return destination; 1677 } 1678 1679 /** @brief Convert an integer to a string. 1680 * 1681 * @param [in] i Integer to be converted. 1682 * 1683 * @return String representing integer. 1684 */ 1685 std::string gl3cts::ClipDistance::Utility::itoa(glw::GLint i) 1686 { 1687 std::stringstream stream; 1688 1689 stream << i; 1690 1691 return stream.str(); 1692 } 1693