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 #include "gl4cStencilTexturingTests.hpp" 25 26 #include "gluContextInfo.hpp" 27 #include "gluDefs.hpp" 28 #include "gluStrUtil.hpp" 29 #include "glwEnums.hpp" 30 #include "glwFunctions.hpp" 31 #include "tcuTestLog.hpp" 32 33 #include <algorithm> 34 #include <string> 35 #include <vector> 36 37 #define DEBUG_REPLACE_TOKEN 0 38 39 using namespace glw; 40 41 namespace gl4cts 42 { 43 namespace StencilTexturing 44 { 45 class Utils 46 { 47 public: 48 static GLuint createAndBuildProgram(deqp::Context& context, const GLchar* cs_code, const GLchar* fs_code, 49 const GLchar* gs_code, const GLchar* tcs_code, const GLchar* tes_code, 50 const GLchar* vs_code); 51 52 static GLuint createAndCompileShader(deqp::Context& context, const GLenum type, const GLchar* code); 53 54 static GLuint createAndFill2DTexture(deqp::Context& context, GLuint width, GLuint height, GLenum internal_format, 55 GLenum format, GLenum type, const GLvoid* data); 56 57 static void deleteProgram(deqp::Context& context, const GLuint id); 58 static void deleteShader(deqp::Context& context, const GLuint id); 59 static void deleteTexture(deqp::Context& context, const GLuint id); 60 static bool isExtensionSupported(deqp::Context& context, const GLchar* extension_name); 61 62 static void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string); 63 }; 64 65 /** Create and build program from provided sources 66 * 67 * @param context Test context 68 * @param cs_code Source code for compute shader stage 69 * @param fs_code Source code for fragment shader stage 70 * @param gs_code Source code for geometry shader stage 71 * @param tcs_code Source code for tesselation control shader stage 72 * @param tes_code Source code for tesselation evaluation shader stage 73 * @param vs_code Source code for vertex shader stage 74 * 75 * @return ID of program object 76 **/ 77 GLuint Utils::createAndBuildProgram(deqp::Context& context, const GLchar* cs_code, const GLchar* fs_code, 78 const GLchar* gs_code, const GLchar* tcs_code, const GLchar* tes_code, 79 const GLchar* vs_code) 80 { 81 #define N_SHADER_STAGES 6 82 83 const Functions& gl = context.getRenderContext().getFunctions(); 84 GLuint id = 0; 85 GLuint shader_ids[N_SHADER_STAGES] = { 0 }; 86 87 const GLchar* shader_sources[N_SHADER_STAGES] = { cs_code, fs_code, gs_code, tcs_code, tes_code, vs_code }; 88 89 const GLenum shader_types[N_SHADER_STAGES] = { GL_COMPUTE_SHADER, GL_FRAGMENT_SHADER, 90 GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER, 91 GL_TESS_EVALUATION_SHADER, GL_VERTEX_SHADER }; 92 GLint status = GL_FALSE; 93 94 /* Compile all shaders */ 95 try 96 { 97 for (GLuint i = 0; i < N_SHADER_STAGES; ++i) 98 { 99 if (0 != shader_sources[i]) 100 { 101 shader_ids[i] = createAndCompileShader(context, shader_types[i], shader_sources[i]); 102 } 103 } 104 105 /* Check compilation */ 106 for (GLuint i = 0; i < N_SHADER_STAGES; ++i) 107 { 108 if ((0 != shader_sources[i]) && (0 == shader_ids[i])) 109 { 110 context.getTestContext().getLog() << tcu::TestLog::Message 111 << "Failed to build program due to compilation problems" 112 << tcu::TestLog::EndMessage; 113 114 /* Delete shaders */ 115 for (GLuint j = 0; j < N_SHADER_STAGES; ++j) 116 { 117 deleteShader(context, shader_ids[j]); 118 } 119 120 /* Done */ 121 return 0; 122 } 123 } 124 125 /* Create program */ 126 id = gl.createProgram(); 127 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram"); 128 129 /* Attach shaders */ 130 for (GLuint i = 0; i < N_SHADER_STAGES; ++i) 131 { 132 if (0 != shader_ids[i]) 133 { 134 gl.attachShader(id, shader_ids[i]); 135 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader"); 136 } 137 } 138 139 /* Link program */ 140 gl.linkProgram(id); 141 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram"); 142 143 /* Clean shaders */ 144 for (GLuint j = 0; j < N_SHADER_STAGES; ++j) 145 { 146 deleteShader(context, shader_ids[j]); 147 } 148 149 /* Get link status */ 150 gl.getProgramiv(id, GL_LINK_STATUS, &status); 151 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv"); 152 153 /* Log link error */ 154 if (GL_TRUE != status) 155 { 156 glw::GLint length = 0; 157 std::string message; 158 159 /* Get error log length */ 160 gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length); 161 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv"); 162 163 message.resize(length, 0); 164 165 /* Get error log */ 166 gl.getProgramInfoLog(id, length, 0, &message[0]); 167 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog"); 168 169 context.getTestContext().getLog() << tcu::TestLog::Message << "Program linking failed: " << message 170 << tcu::TestLog::EndMessage; 171 172 /* Clean program */ 173 deleteProgram(context, id); 174 175 /* Done */ 176 return 0; 177 } 178 } 179 catch (std::exception& exc) 180 { 181 /* Delete shaders */ 182 for (GLuint j = 0; j < N_SHADER_STAGES; ++j) 183 { 184 deleteShader(context, shader_ids[j]); 185 } 186 187 throw exc; 188 } 189 190 return id; 191 } 192 193 /** Create and compile shader 194 * 195 * @param context Test context 196 * @param type Type of shader 197 * @param code Source code for shader 198 * 199 * @return ID of shader object 200 **/ 201 GLuint Utils::createAndCompileShader(deqp::Context& context, const GLenum type, const GLchar* code) 202 { 203 const Functions& gl = context.getRenderContext().getFunctions(); 204 GLuint id = gl.createShader(type); 205 GLint status = GL_FALSE; 206 207 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader"); 208 209 try 210 { 211 gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */); 212 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource"); 213 214 /* Compile */ 215 gl.compileShader(id); 216 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader"); 217 218 /* Get compilation status */ 219 gl.getShaderiv(id, GL_COMPILE_STATUS, &status); 220 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv"); 221 222 /* Log compilation error */ 223 if (GL_TRUE != status) 224 { 225 glw::GLint length = 0; 226 std::string message; 227 228 /* Error log length */ 229 gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length); 230 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv"); 231 232 /* Prepare storage */ 233 message.resize(length, 0); 234 235 /* Get error log */ 236 gl.getShaderInfoLog(id, length, 0, &message[0]); 237 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog"); 238 239 context.getTestContext().getLog() << tcu::TestLog::Message << "Shader (" << glu::getShaderTypeStr(type) 240 << ") compilation failed: " << message << tcu::TestLog::EndMessage; 241 242 deleteShader(context, id); 243 id = 0; 244 } 245 } 246 catch (std::exception& exc) 247 { 248 deleteShader(context, id); 249 throw exc; 250 } 251 252 return id; 253 } 254 255 /** Generate and fill 2d texture 256 * 257 * @param context Test context 258 * @param width Width of texture 259 * @param height Height of texture 260 * @param internal_format Internal format of texture 261 * @param format Format of data 262 * @param type Type of data 263 * @param data Data 264 * 265 * @return ID of texture object 266 **/ 267 GLuint Utils::createAndFill2DTexture(deqp::Context& context, GLuint width, GLuint height, GLenum internal_format, 268 GLenum format, GLenum type, const GLvoid* data) 269 { 270 const Functions& gl = context.getRenderContext().getFunctions(); 271 GLuint id = 0; 272 273 gl.genTextures(1, &id); 274 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures"); 275 276 try 277 { 278 gl.bindTexture(GL_TEXTURE_2D, id); 279 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 280 281 gl.texImage2D(GL_TEXTURE_2D, 0 /* level */, internal_format, width, height, 0 /* border */, format, type, data); 282 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D"); 283 284 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); 285 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 286 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); 287 288 gl.bindTexture(GL_TEXTURE_2D, 0); 289 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 290 } 291 catch (std::exception& exc) 292 { 293 gl.deleteTextures(1, &id); 294 id = 0; 295 296 throw exc; 297 } 298 299 return id; 300 } 301 302 /** Delete program 303 * 304 * @param context Test context 305 * @param id ID of program 306 **/ 307 void Utils::deleteProgram(deqp::Context& context, const GLuint id) 308 { 309 const glw::Functions& gl = context.getRenderContext().getFunctions(); 310 311 if (0 != id) 312 { 313 gl.deleteProgram(id); 314 } 315 } 316 317 /** Delete shader 318 * 319 * @param context Test context 320 * @param id ID of shader 321 **/ 322 void Utils::deleteShader(deqp::Context& context, const GLuint id) 323 { 324 const glw::Functions& gl = context.getRenderContext().getFunctions(); 325 326 if (0 != id) 327 { 328 gl.deleteShader(id); 329 } 330 } 331 332 /** Delete texture 333 * 334 * @param context Test context 335 * @param id ID of texture 336 **/ 337 void Utils::deleteTexture(deqp::Context& context, const GLuint id) 338 { 339 const glw::Functions& gl = context.getRenderContext().getFunctions(); 340 341 if (0 != id) 342 { 343 gl.deleteTextures(1, &id); 344 } 345 } 346 347 /** Checks if extensions is not available. 348 * 349 * @param context Test context 350 * @param extension_name Name of extension 351 * 352 * @return true if extension is reported as available, false otherwise 353 **/ 354 bool Utils::isExtensionSupported(deqp::Context& context, const GLchar* extension_name) 355 { 356 const std::vector<std::string>& extensions = context.getContextInfo().getExtensions(); 357 358 if (std::find(extensions.begin(), extensions.end(), extension_name) == extensions.end()) 359 { 360 std::string message = "Required extension is not supported: "; 361 message.append(extension_name); 362 363 return false; 364 } 365 366 return true; 367 } 368 369 /** Replace first occurance of <token> with <text> in <string> starting at <search_posistion> 370 * 371 * @param token Token string 372 * @param search_position Position at which find will start, it is updated to position at which replaced text ends 373 * @param text String that will be used as replacement for <token> 374 * @param string String to work on 375 **/ 376 void Utils::replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string) 377 { 378 const size_t text_length = strlen(text); 379 const size_t token_length = strlen(token); 380 const size_t token_position = string.find(token, search_position); 381 382 #if DEBUG_REPLACE_TOKEN 383 if (std::string::npos == token_position) 384 { 385 string.append("\n\nInvalid token: "); 386 string.append(token); 387 388 TCU_FAIL(string.c_str()); 389 } 390 #endif /* DEBUG_REPLACE_TOKEN */ 391 392 string.replace(token_position, token_length, text, text_length); 393 394 search_position = token_position + text_length; 395 } 396 397 /* FunctionalTest */ 398 /* Shader sources */ 399 const GLchar* FunctionalTest::m_compute_shader_code = 400 "#version 430 core\n" 401 "\n" 402 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 403 "\n" 404 "IMAGE_DEFINITION;\n" 405 "SAMPLER_DEFINITION;\n" 406 "\n" 407 "void main()\n" 408 "{\n" 409 " vec2 tex_coord = vec2(gl_GlobalInvocationID.xy) / 8.0;\n" 410 "\n" 411 " imageStore(uni_image,\n" 412 " ivec2(gl_GlobalInvocationID.xy),\n" 413 " TYPE(texture(uni_sampler, tex_coord).r, 0, 0, 0));\n" 414 "}\n" 415 "\n"; 416 417 const GLchar* FunctionalTest::m_fragment_shader_code = 418 "#version 430 core\n" 419 "\n" 420 " in vec2 gs_fs_tex_coord;\n" 421 "flat in uint gs_fs_result;\n" 422 " out TYPE fs_out_result;\n" 423 "\n" 424 "SAMPLER_DEFINITION;\n" 425 "\n" 426 "void main()\n" 427 "{\n" 428 " if (1 != gs_fs_result)\n" 429 " {\n" 430 " fs_out_result = texture(uni_sampler, vec2(0.9375, 0.9375));\n" 431 " }\n" 432 " else\n" 433 " {\n" 434 " fs_out_result = texture(uni_sampler, gs_fs_tex_coord);\n" 435 " }\n" 436 "}\n" 437 "\n"; 438 439 const GLchar* FunctionalTest::m_geometry_shader_code = 440 "#version 430 core\n" 441 "\n" 442 "layout(points) in;\n" 443 "layout(triangle_strip, max_vertices = 4) out;\n" 444 "\n" 445 " in uint tes_gs_result[];\n" 446 "flat out uint gs_fs_result;\n" 447 " out vec2 gs_fs_tex_coord;\n" 448 "\n" 449 "SAMPLER_DEFINITION;\n" 450 "\n" 451 "void main()\n" 452 "{\n" 453 " uint result = 1u;\n" 454 "\n" 455 " if (1 != tes_gs_result[0])\n" 456 " {\n" 457 " result = 0u;\n" 458 " }\n" 459 "\n" 460 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n" 461 " {\n" 462 " result = 0u;\n" 463 " }\n" 464 "\n" 465 " gs_fs_result = result;\n" 466 " gs_fs_tex_coord = vec2(0, 0);\n" 467 " gl_Position = vec4(-1, -1, 0, 1);\n" 468 " EmitVertex();\n" 469 " gs_fs_result = result;\n" 470 " gs_fs_tex_coord = vec2(0, 1);\n" 471 " gl_Position = vec4(-1, 1, 0, 1);\n" 472 " EmitVertex();\n" 473 " gs_fs_result = result;\n" 474 " gs_fs_tex_coord = vec2(1, 0);\n" 475 " gl_Position = vec4(1, -1, 0, 1);\n" 476 " EmitVertex();\n" 477 " gs_fs_result = result;\n" 478 " gs_fs_tex_coord = vec2(1, 1);\n" 479 " gl_Position = vec4(1, 1, 0, 1);\n" 480 " EmitVertex();\n" 481 "}\n" 482 "\n"; 483 484 const GLchar* FunctionalTest::m_tesselation_control_shader_code = 485 "#version 430 core\n" 486 "\n" 487 "layout(vertices = 1) out;\n" 488 "\n" 489 "in uint vs_tcs_result[];\n" 490 "out uint tcs_tes_result[];\n" 491 "\n" 492 "SAMPLER_DEFINITION;\n" 493 "\n" 494 "void main()\n" 495 "{\n" 496 " uint result = 1u;\n" 497 "\n" 498 " if (1u != vs_tcs_result[gl_InvocationID])\n" 499 " {\n" 500 " result = 0u;\n" 501 " }\n" 502 "\n" 503 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n" 504 " {\n" 505 " result = 0u;\n" 506 " }\n" 507 "\n" 508 " tcs_tes_result[gl_InvocationID] = result;\n" 509 "\n" 510 " gl_TessLevelOuter[0] = 1.0;\n" 511 " gl_TessLevelOuter[1] = 1.0;\n" 512 " gl_TessLevelOuter[2] = 1.0;\n" 513 " gl_TessLevelOuter[3] = 1.0;\n" 514 " gl_TessLevelInner[0] = 1.0;\n" 515 " gl_TessLevelInner[1] = 1.0;\n" 516 "}\n" 517 "\n"; 518 519 const GLchar* FunctionalTest::m_tesselation_evaluation_shader_code = 520 "#version 430 core\n" 521 "\n" 522 "layout(isolines, point_mode) in;\n" 523 "\n" 524 "in uint tcs_tes_result[];\n" 525 "out uint tes_gs_result;\n" 526 "\n" 527 "SAMPLER_DEFINITION;\n" 528 "\n" 529 "void main()\n" 530 "{\n" 531 " uint result = 1u;\n" 532 "\n" 533 " if (1u != tcs_tes_result[0])\n" 534 " {\n" 535 " result = 0u;\n" 536 " }\n" 537 "\n" 538 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n" 539 " {\n" 540 " result = 0u;\n" 541 " }\n" 542 "\n" 543 " tes_gs_result = result;\n" 544 "}\n" 545 "\n"; 546 547 const GLchar* FunctionalTest::m_vertex_shader_code = 548 "#version 430 core\n" 549 "\n" 550 "out uint vs_tcs_result;\n" 551 "\n" 552 "SAMPLER_DEFINITION;\n" 553 "\n" 554 "void main()\n" 555 "{\n" 556 " uint result = 1u;\n" 557 "\n" 558 " if (EXPECTED_VALUE != texture(uni_sampler, vec2(0.9375, 0.9375)).r)\n" 559 " {\n" 560 " result = 0u;\n" 561 " }\n" 562 "\n" 563 " vs_tcs_result = result;\n" 564 "}\n" 565 "\n"; 566 567 const GLchar* FunctionalTest::m_expected_value_depth = "0.0"; 568 569 const GLchar* FunctionalTest::m_expected_value_stencil = "15u"; 570 571 const GLchar* FunctionalTest::m_image_definition_depth = "writeonly uniform image2D uni_image"; 572 573 const GLchar* FunctionalTest::m_image_definition_stencil = "writeonly uniform uimage2D uni_image"; 574 575 const GLchar* FunctionalTest::m_output_type_depth = "vec4"; 576 577 const GLchar* FunctionalTest::m_output_type_stencil = "uvec4"; 578 579 const GLchar* FunctionalTest::m_sampler_definition_depth = "uniform sampler2D uni_sampler"; 580 581 const GLchar* FunctionalTest::m_sampler_definition_stencil = "uniform usampler2D uni_sampler"; 582 583 /* Constants */ 584 const GLuint FunctionalTest::m_height = 8; 585 const GLint FunctionalTest::m_image_unit = 1; 586 const GLint FunctionalTest::m_texture_unit = 1; 587 const GLuint FunctionalTest::m_width = 8; 588 589 /** Constructor 590 * 591 * @param context Test context 592 **/ 593 FunctionalTest::FunctionalTest(deqp::Context& context) 594 : TestCase(context, "functional", "Checks if sampling stencil texture gives expected results") 595 { 596 /* Nothing to be done here */ 597 } 598 599 /** Execute test 600 * 601 * @return tcu::TestNode::STOP 602 **/ 603 tcu::TestNode::IterateResult FunctionalTest::iterate() 604 { 605 bool test_result = true; 606 607 if (false == test(GL_DEPTH24_STENCIL8, true)) 608 { 609 m_context.getTestContext().getLog() << tcu::TestLog::Message 610 << "Test failed. Case format: GL_DEPTH24_STENCIL8, channel: S" 611 << tcu::TestLog::EndMessage; 612 test_result = false; 613 } 614 615 if (false == test(GL_DEPTH24_STENCIL8, false)) 616 { 617 m_context.getTestContext().getLog() << tcu::TestLog::Message 618 << "Test failed. Case format: GL_DEPTH24_STENCIL8, channel: D" 619 << tcu::TestLog::EndMessage; 620 test_result = false; 621 } 622 623 if (false == test(GL_DEPTH32F_STENCIL8, true)) 624 { 625 m_context.getTestContext().getLog() << tcu::TestLog::Message 626 << "Test failed. Case format: GL_DEPTH32F_STENCIL8, channel: S" 627 << tcu::TestLog::EndMessage; 628 test_result = false; 629 } 630 631 if (false == test(GL_DEPTH32F_STENCIL8, false)) 632 { 633 m_context.getTestContext().getLog() << tcu::TestLog::Message 634 << "Test failed. Case format: GL_DEPTH32F_STENCIL8, channel: D" 635 << tcu::TestLog::EndMessage; 636 test_result = false; 637 } 638 639 /* Set result */ 640 if (true == test_result) 641 { 642 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); 643 } 644 else 645 { 646 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 647 } 648 649 /* Done */ 650 return tcu::TestNode::STOP; 651 } 652 653 /** Execute compute program 654 * 655 * @param program_id ID of program 656 * @param is_stencil Selects if stencil or depth channel is sampled 657 * @param dst_texture_id ID of destination texture 658 * @param src_texture_id ID of source texture 659 **/ 660 void FunctionalTest::dispatch(GLuint program_id, bool is_stencil, GLuint dst_texture_id, GLuint src_texture_id) 661 { 662 const Functions& gl = m_context.getRenderContext().getFunctions(); 663 GLenum internal_format = GL_R8UI; 664 GLint uni_image_loc = -1; 665 GLint uni_sampler_loc = -1; 666 667 if (false == is_stencil) 668 { 669 internal_format = GL_R32F; 670 } 671 672 /* Set program */ 673 gl.useProgram(program_id); 674 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram"); 675 676 /* Get uniform location and bind texture to proper image unit */ 677 uni_image_loc = gl.getUniformLocation(program_id, "uni_image"); 678 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation"); 679 680 gl.bindImageTexture(m_image_unit, dst_texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* Layer */, 681 GL_WRITE_ONLY, internal_format); 682 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 683 684 gl.uniform1i(uni_image_loc, m_image_unit); 685 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 686 687 /* Get uniform location and bind texture to proper texture unit */ 688 uni_sampler_loc = gl.getUniformLocation(program_id, "uni_sampler"); 689 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation"); 690 691 gl.activeTexture(GL_TEXTURE0 + m_texture_unit); 692 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture"); 693 694 gl.bindTexture(GL_TEXTURE_2D, src_texture_id); 695 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 696 697 gl.uniform1i(uni_sampler_loc, m_texture_unit); 698 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 699 700 /* Dispatch program */ 701 gl.dispatchCompute(m_width, m_height, 1); 702 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 703 704 /* Sync */ 705 gl.memoryBarrier(GL_ALL_BARRIER_BITS); 706 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 707 } 708 709 /** Execute draw program 710 * 711 * @param program_id ID of program 712 * @param dst_texture_id ID of destination texture 713 * @param src_texture_id ID of source texture 714 **/ 715 void FunctionalTest::draw(GLuint program_id, GLuint dst_texture_id, GLuint src_texture_id) 716 { 717 GLuint fb_id = 0; 718 const Functions& gl = m_context.getRenderContext().getFunctions(); 719 GLint uni_sampler_loc = -1; 720 GLuint vao_id = 0; 721 722 try 723 { 724 /* Tesselation patch set up */ 725 gl.patchParameteri(GL_PATCH_VERTICES, 1); 726 GLU_EXPECT_NO_ERROR(gl.getError(), "PatchParameteri"); 727 728 /* Prepare VAO */ 729 gl.genVertexArrays(1, &vao_id); 730 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays"); 731 732 gl.bindVertexArray(vao_id); 733 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray"); 734 735 /* Prepare FBO */ 736 gl.genFramebuffers(1, &fb_id); 737 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers"); 738 739 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_id); 740 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer"); 741 742 gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dst_texture_id, 0 /* level */); 743 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture"); 744 745 gl.viewport(0 /* x */, 0 /* y */, m_width, m_height); 746 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport"); 747 748 /* Set program */ 749 gl.useProgram(program_id); 750 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram"); 751 752 /* Get uniform location and bind texture to proper texture unit */ 753 uni_sampler_loc = gl.getUniformLocation(program_id, "uni_sampler"); 754 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation"); 755 756 gl.activeTexture(GL_TEXTURE0 + m_texture_unit); 757 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture"); 758 759 gl.bindTexture(GL_TEXTURE_2D, src_texture_id); 760 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 761 762 gl.uniform1i(uni_sampler_loc, m_texture_unit); 763 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 764 765 /* Draw */ 766 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); 767 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); 768 769 /* Sync */ 770 gl.memoryBarrier(GL_ALL_BARRIER_BITS); 771 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 772 } 773 catch (std::exception& exc) 774 { 775 gl.bindVertexArray(0); 776 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 777 gl.bindTexture(GL_TEXTURE_2D, 0); 778 779 if (0 != vao_id) 780 { 781 gl.deleteVertexArrays(1, &vao_id); 782 } 783 784 if (0 != fb_id) 785 { 786 gl.deleteFramebuffers(1, &fb_id); 787 } 788 789 throw exc; 790 } 791 792 gl.bindVertexArray(0); 793 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 794 gl.bindTexture(GL_TEXTURE_2D, 0); 795 796 if (0 != vao_id) 797 { 798 gl.deleteVertexArrays(1, &vao_id); 799 } 800 801 if (0 != fb_id) 802 { 803 gl.deleteFramebuffers(1, &fb_id); 804 } 805 } 806 807 /** Prepare destination texture 808 * 809 * @param is_stencil Selects if stencil or depth channel is sampled 810 * 811 * @return ID of texture 812 **/ 813 GLuint FunctionalTest::prepareDestinationTexture(bool is_stencil) 814 { 815 static const GLuint n_pixels = m_width * m_height; 816 GLenum format = 0; 817 GLenum internal_format = 0; 818 GLuint pixel_size = 0; 819 std::vector<GLubyte> texture_data; 820 GLuint texture_id = 0; 821 GLuint texture_size = 0; 822 GLenum type = 0; 823 824 /* Select size of pixel */ 825 if (true == is_stencil) 826 { 827 format = GL_RED_INTEGER; 828 internal_format = GL_R8UI; 829 pixel_size = 1; 830 type = GL_UNSIGNED_BYTE; 831 } 832 else 833 { 834 format = GL_RED; 835 internal_format = GL_R32F; 836 pixel_size = 4; 837 type = GL_FLOAT; 838 } 839 840 /* Allocate storage */ 841 texture_size = pixel_size * n_pixels; 842 texture_data.resize(texture_size); 843 844 /* Fill texture data */ 845 memset(&texture_data[0], 0, texture_size); 846 847 /* Create texture */ 848 texture_id = 849 Utils::createAndFill2DTexture(m_context, m_width, m_height, internal_format, format, type, &texture_data[0]); 850 851 /* Done */ 852 return texture_id; 853 } 854 855 /** Prepare program 856 * 857 * @param is_draw Selects if draw or compute program is prepared 858 * @param is_stencil Selects if stencil or depth channel is sampled 859 * 860 * @return ID of texture 861 **/ 862 GLuint FunctionalTest::prepareProgram(bool is_draw, bool is_stencil) 863 { 864 GLuint program_id = 0; 865 866 if (true != is_draw) 867 { 868 std::string cs_code = m_compute_shader_code; 869 const GLchar* image_definition = m_image_definition_stencil; 870 size_t position = 0; 871 const GLchar* sampler_definition = m_sampler_definition_stencil; 872 const GLchar* type = m_output_type_stencil; 873 874 if (false == is_stencil) 875 { 876 image_definition = m_image_definition_depth; 877 sampler_definition = m_sampler_definition_depth; 878 type = m_output_type_depth; 879 } 880 881 Utils::replaceToken("IMAGE_DEFINITION", position, image_definition, cs_code); 882 Utils::replaceToken("SAMPLER_DEFINITION", position, sampler_definition, cs_code); 883 Utils::replaceToken("TYPE", position, type, cs_code); 884 885 program_id = Utils::createAndBuildProgram(m_context, cs_code.c_str(), 0 /* fs_code */, 0 /* gs_code */, 886 0 /* tcs_code */, 0 /* tes_code */, 0 /* vs_code */); 887 } 888 else 889 { 890 #define N_FUNCTIONAL_TEST_SHADER_STAGES 5 891 892 const GLchar* expected_value = m_expected_value_stencil; 893 const GLchar* sampler_definition = m_sampler_definition_stencil; 894 std::string shader_code[N_FUNCTIONAL_TEST_SHADER_STAGES]; 895 const GLchar* shader_templates[N_FUNCTIONAL_TEST_SHADER_STAGES] = { 896 m_fragment_shader_code, m_geometry_shader_code, m_tesselation_control_shader_code, 897 m_tesselation_evaluation_shader_code, m_vertex_shader_code 898 }; 899 const GLchar* type = m_output_type_stencil; 900 901 if (false == is_stencil) 902 { 903 expected_value = m_expected_value_depth; 904 sampler_definition = m_sampler_definition_depth; 905 type = m_output_type_depth; 906 } 907 908 for (GLuint i = 0; i < N_FUNCTIONAL_TEST_SHADER_STAGES; ++i) 909 { 910 size_t position = 0; 911 912 shader_code[i] = shader_templates[i]; 913 914 if (0 == i) 915 { 916 Utils::replaceToken("TYPE", position, type, shader_code[i]); 917 Utils::replaceToken("SAMPLER_DEFINITION", position, sampler_definition, shader_code[i]); 918 //Utils::replaceToken("TYPE", position, type, shader_code[i]); 919 } 920 else 921 { 922 Utils::replaceToken("SAMPLER_DEFINITION", position, sampler_definition, shader_code[i]); 923 Utils::replaceToken("EXPECTED_VALUE", position, expected_value, shader_code[i]); 924 } 925 } 926 927 program_id = 928 Utils::createAndBuildProgram(m_context, 0 /* cs_code */, shader_code[0].c_str() /* fs_code */, 929 shader_code[1].c_str() /* gs_code */, shader_code[2].c_str() /* tcs_code */, 930 shader_code[3].c_str() /* tes_code */, shader_code[4].c_str() /* vs_code */); 931 } 932 933 /* Done */ 934 return program_id; 935 } 936 937 /** Prepare source texture 938 * 939 * @param internal_format Internal format of texture 940 * @param is_stencil Selects if stencil or depth channel is sampled 941 * @param texture_data Texture contents 942 * 943 * @return ID of texture 944 **/ 945 GLuint FunctionalTest::prepareSourceTexture(GLenum internal_format, bool is_stencil, 946 const std::vector<glw::GLubyte>& texture_data) 947 { 948 const Functions& gl = m_context.getRenderContext().getFunctions(); 949 GLuint texture_id = 0; 950 GLenum type = 0; 951 952 /* Select size of pixel */ 953 switch (internal_format) 954 { 955 case GL_DEPTH24_STENCIL8: 956 type = GL_UNSIGNED_INT_24_8; 957 break; 958 case GL_DEPTH32F_STENCIL8: 959 type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; 960 break; 961 default: 962 TCU_FAIL("Invalid enum"); 963 break; 964 } 965 966 /* Create texture */ 967 texture_id = Utils::createAndFill2DTexture(m_context, m_width, m_height, internal_format, GL_DEPTH_STENCIL, type, 968 &texture_data[0]); 969 970 /* Set DS texture mode */ 971 gl.bindTexture(GL_TEXTURE_2D, texture_id); 972 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 973 974 if (true == is_stencil) 975 { 976 gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); 977 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); 978 } 979 else 980 { 981 gl.texParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT); 982 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); 983 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); 984 } 985 986 /* Set nearest filtering */ 987 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 988 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 989 GLU_EXPECT_NO_ERROR(gl.getError(), "TexParameteri"); 990 991 /* Unbind */ 992 gl.bindTexture(GL_TEXTURE_2D, 0); 993 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 994 995 /* Done */ 996 return texture_id; 997 } 998 999 /** Prepare data for source texture 1000 * 1001 * @param internal_format Internal format of texture 1002 * @param texture_data Texture contents 1003 * 1004 * @return ID of texture 1005 **/ 1006 void FunctionalTest::prepareSourceTextureData(GLenum internal_format, std::vector<GLubyte>& texture_data) 1007 { 1008 static const GLfloat depth_step_h = -0.5f / ((GLfloat)(m_width - 1)); 1009 static const GLfloat depth_step_v = -0.5f / ((GLfloat)(m_height - 1)); 1010 static const GLuint stencil_step_h = 1; 1011 static const GLuint stencil_step_v = 1; 1012 static const GLuint n_pixels = m_width * m_height; 1013 GLuint pixel_size = 0; 1014 GLuint line_size = 0; 1015 GLuint texture_size = 0; 1016 1017 /* Select size of pixel */ 1018 switch (internal_format) 1019 { 1020 case GL_DEPTH24_STENCIL8: 1021 pixel_size = 4; 1022 break; 1023 case GL_DEPTH32F_STENCIL8: 1024 pixel_size = 8; 1025 break; 1026 default: 1027 TCU_FAIL("Invalid enum"); 1028 break; 1029 } 1030 1031 line_size = pixel_size * m_width; 1032 texture_size = pixel_size * n_pixels; 1033 1034 /* Allocate storage */ 1035 texture_data.resize(texture_size); 1036 1037 /* Fill texture data */ 1038 for (GLuint y = 0; y < m_height; ++y) 1039 { 1040 const GLfloat depth_v = depth_step_v * (GLfloat)y; 1041 const GLuint line_offset = line_size * y; 1042 const GLuint stencil_v = stencil_step_v * y; 1043 1044 for (GLuint x = 0; x < m_width; ++x) 1045 { 1046 const GLfloat depth_h = depth_step_h * (GLfloat)x; 1047 const GLfloat depth_f = 1 + depth_h + depth_v; 1048 const GLuint depth_i = (GLuint)(((GLfloat)0xffffff) * depth_f); 1049 const GLuint pixel_offset = pixel_size * x; 1050 const GLuint stencil_h = stencil_step_h * x; 1051 const GLuint stencil = 1 + stencil_h + stencil_v; 1052 1053 GLubyte* depth_f_data = (GLubyte*)&depth_f; 1054 GLubyte* depth_i_data = (GLubyte*)&depth_i; 1055 GLubyte* pixel_data = &texture_data[0] + line_offset + pixel_offset; 1056 GLubyte* stencil_data = (GLubyte*)&stencil; 1057 1058 switch (pixel_size) 1059 { 1060 case 4: 1061 memcpy(pixel_data, stencil_data, 1); 1062 memcpy(pixel_data + 1, depth_i_data, 3); 1063 break; 1064 case 8: 1065 memcpy(pixel_data, depth_f_data, 4); 1066 memcpy(pixel_data + 4, stencil_data, 1); 1067 break; 1068 default: 1069 TCU_FAIL("Invalid value"); 1070 break; 1071 } 1072 } 1073 } 1074 } 1075 1076 /** Verifies that destination texture contents match expectations 1077 * 1078 * @param id ID of destination texture 1079 * @param source_internal_format Internal format of source texture 1080 * @param is_stencil Selects if stencil of depth channel is sampled 1081 * @param src_texture_data Contents of source texture 1082 * 1083 * @return true if everything is fine, false otherwise 1084 **/ 1085 bool FunctionalTest::verifyTexture(GLuint id, GLenum source_internal_format, bool is_stencil, 1086 const std::vector<GLubyte>& src_texture_data) 1087 { 1088 static const GLuint n_pixels = m_width * m_height; 1089 const Functions& gl = m_context.getRenderContext().getFunctions(); 1090 GLuint dst_pixel_size = 0; 1091 std::vector<GLubyte> dst_texture_data; 1092 GLuint dst_texture_size = 0; 1093 GLenum format = 0; 1094 GLuint src_pixel_size = 0; 1095 GLuint src_stencil_off = 0; 1096 GLenum type = 0; 1097 1098 /* Select size of pixel */ 1099 if (true == is_stencil) 1100 { 1101 format = GL_RED_INTEGER; 1102 dst_pixel_size = 1; 1103 type = GL_UNSIGNED_BYTE; 1104 } 1105 else 1106 { 1107 format = GL_RED; 1108 dst_pixel_size = 4; 1109 type = GL_FLOAT; 1110 } 1111 1112 if (GL_DEPTH24_STENCIL8 == source_internal_format) 1113 { 1114 src_pixel_size = 4; 1115 } 1116 else 1117 { 1118 src_pixel_size = 8; 1119 src_stencil_off = 4; 1120 } 1121 1122 /* Allocate storage */ 1123 dst_texture_size = dst_pixel_size * n_pixels; 1124 dst_texture_data.resize(dst_texture_size); 1125 1126 /* Get texture contents */ 1127 gl.bindTexture(GL_TEXTURE_2D, id); 1128 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 1129 1130 gl.getTexImage(GL_TEXTURE_2D, 0 /* level */, format, type, &dst_texture_data[0]); 1131 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage"); 1132 1133 gl.bindTexture(GL_TEXTURE_2D, 0); 1134 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 1135 1136 /* For each pixel */ 1137 for (GLuint i = 0; i < n_pixels; ++i) 1138 { 1139 const GLuint dst_pixel_offset = dst_pixel_size * i; 1140 const GLuint src_pixel_offset = src_pixel_size * i; 1141 1142 const GLubyte* dst_pixel_data = &dst_texture_data[0] + dst_pixel_offset; 1143 const GLubyte* src_pixel_data = &src_texture_data[0] + src_pixel_offset; 1144 1145 if (true == is_stencil) /* Stencil channel */ 1146 { 1147 const GLubyte dst_stencil = dst_pixel_data[0]; 1148 const GLubyte src_stencil = src_pixel_data[src_stencil_off]; 1149 1150 if (src_stencil != dst_stencil) 1151 { 1152 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel [" << i 1153 << "], got: " << (GLuint)dst_stencil 1154 << " expected: " << (GLuint)src_stencil << tcu::TestLog::EndMessage; 1155 1156 return false; 1157 } 1158 } 1159 else /* Depth channel */ 1160 { 1161 if (GL_DEPTH24_STENCIL8 == source_internal_format) /* DEPTH24 */ 1162 { 1163 GLfloat dst_depth = 0.0f; 1164 GLuint src_depth_i = 0; 1165 GLfloat src_depth_f = 0.0f; 1166 1167 memcpy(&dst_depth, dst_pixel_data, 4); 1168 memcpy(&src_depth_i, src_pixel_data + 1, 3); 1169 1170 src_depth_f = ((GLfloat)src_depth_i) / ((GLfloat)0xffffff); 1171 1172 if (de::abs(src_depth_f - dst_depth) > 0.0001f) 1173 { 1174 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel [" << i 1175 << "], got: " << dst_depth << " expected: " << src_depth_f 1176 << tcu::TestLog::EndMessage; 1177 1178 return false; 1179 } 1180 } 1181 else /* DEPTH32F */ 1182 { 1183 GLfloat dst_depth = 0.0f; 1184 GLfloat src_depth = 0.0f; 1185 1186 memcpy(&dst_depth, dst_pixel_data, 4); 1187 memcpy(&src_depth, src_pixel_data, 4); 1188 1189 if (de::abs(src_depth - dst_depth) > 0.0001f) 1190 { 1191 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixel [" << i 1192 << "], got: " << dst_depth << " expected: " << src_depth 1193 << tcu::TestLog::EndMessage; 1194 1195 return false; 1196 } 1197 } 1198 } 1199 } 1200 1201 return true; 1202 } 1203 1204 /** Test given internal format and channel 1205 * 1206 * @param internal_format Internal fromat of source texture 1207 * @param is_stencil Selects if stencil or depth channel is sampled 1208 * 1209 * @return true if results from compute and draw programs are positive, false otherwise 1210 **/ 1211 bool FunctionalTest::test(GLenum internal_format, bool is_stencil) 1212 { 1213 GLuint compute_dst_tex_id = 0; 1214 GLuint compute_program_id = 0; 1215 GLuint compute_src_tex_id = 0; 1216 GLuint draw_dst_tex_id = 0; 1217 GLuint draw_program_id = 0; 1218 GLuint draw_src_tex_id = 0; 1219 const Functions& gl = m_context.getRenderContext().getFunctions(); 1220 bool test_result = true; 1221 std::vector<GLubyte> texture_data; 1222 1223 prepareSourceTextureData(internal_format, texture_data); 1224 1225 try 1226 { 1227 if (true == Utils::isExtensionSupported(m_context, "GL_ARB_compute_shader")) 1228 { 1229 compute_dst_tex_id = prepareDestinationTexture(is_stencil); 1230 compute_program_id = prepareProgram(false, is_stencil); 1231 compute_src_tex_id = prepareSourceTexture(internal_format, is_stencil, texture_data); 1232 1233 dispatch(compute_program_id, is_stencil, compute_dst_tex_id, compute_src_tex_id); 1234 1235 if (false == verifyTexture(compute_dst_tex_id, internal_format, is_stencil, texture_data)) 1236 { 1237 test_result = false; 1238 } 1239 } 1240 1241 { 1242 draw_dst_tex_id = prepareDestinationTexture(is_stencil); 1243 draw_program_id = prepareProgram(true, is_stencil); 1244 draw_src_tex_id = prepareSourceTexture(internal_format, is_stencil, texture_data); 1245 1246 draw(draw_program_id, draw_dst_tex_id, draw_src_tex_id); 1247 1248 if (false == verifyTexture(draw_dst_tex_id, internal_format, is_stencil, texture_data)) 1249 { 1250 test_result = false; 1251 } 1252 } 1253 } 1254 catch (std::exception& exc) 1255 { 1256 gl.bindVertexArray(0); 1257 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 1258 gl.useProgram(0); 1259 1260 Utils::deleteProgram(m_context, compute_program_id); 1261 Utils::deleteProgram(m_context, draw_program_id); 1262 1263 Utils::deleteTexture(m_context, compute_dst_tex_id); 1264 Utils::deleteTexture(m_context, compute_src_tex_id); 1265 Utils::deleteTexture(m_context, draw_dst_tex_id); 1266 Utils::deleteTexture(m_context, draw_src_tex_id); 1267 1268 TCU_FAIL(exc.what()); 1269 } 1270 1271 gl.bindVertexArray(0); 1272 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 1273 gl.useProgram(0); 1274 1275 Utils::deleteProgram(m_context, compute_program_id); 1276 Utils::deleteProgram(m_context, draw_program_id); 1277 1278 Utils::deleteTexture(m_context, compute_dst_tex_id); 1279 Utils::deleteTexture(m_context, compute_src_tex_id); 1280 Utils::deleteTexture(m_context, draw_dst_tex_id); 1281 Utils::deleteTexture(m_context, draw_src_tex_id); 1282 1283 /* Done */ 1284 return test_result; 1285 } 1286 } /* namespace StencilTexturing */ 1287 1288 StencilTexturingTests::StencilTexturingTests(deqp::Context& context) : TestCaseGroup(context, "stencil_texturing", "") 1289 { 1290 } 1291 1292 StencilTexturingTests::~StencilTexturingTests(void) 1293 { 1294 } 1295 1296 void StencilTexturingTests::init() 1297 { 1298 addChild(new StencilTexturing::FunctionalTest(m_context)); 1299 } 1300 } /* namespace gl4cts */ 1301