1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2017 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 glcMultipleContextsTests.cpp 21 * \brief 22 */ /*-------------------------------------------------------------------*/ 23 24 #include "glcMultipleContextsTests.hpp" 25 #include "deSharedPtr.hpp" 26 #include "gl4cShaderSubroutineTests.hpp" 27 #include "gluContextInfo.hpp" 28 #include "glwEnums.hpp" 29 #include "glwFunctions.hpp" 30 #include "tcuMatrix.hpp" 31 #include <cmath> 32 #include <cstring> 33 #include <deMath.h> 34 35 using namespace glw; 36 using namespace gl4cts::ShaderSubroutine; 37 38 namespace glcts 39 { 40 41 /** 42 * * Create multiple contexts and verify that subroutine uniforms values 43 * are preserved for each program stage when switching rendering context. 44 * 45 * OpenGL 4.1 or ARB_separate_shader_objects support required 46 * * Same as above, but use pipelines instead of monolithic program. 47 **/ 48 class UniformPreservationTest : public tcu::TestCase 49 { 50 public: 51 /* Public methods */ 52 UniformPreservationTest(tcu::TestContext& testCtx, glu::ApiType apiType); 53 54 virtual void deinit(); 55 virtual tcu::TestNode::IterateResult iterate(); 56 57 private: 58 /* Private types */ 59 struct subroutineUniformSet 60 { 61 bool operator!=(const subroutineUniformSet& arg) const; 62 void set(glw::GLuint bit_field, const subroutineUniformSet subroutine_indices[2]); 63 64 glw::GLuint m_vertex_shader_stage; 65 glw::GLuint m_tesselation_control_shader_stage; 66 glw::GLuint m_tesselation_evaluation_shader_stage; 67 glw::GLuint m_geometry_shader_stage; 68 glw::GLuint m_fragment_shader_stage; 69 }; 70 71 /* Private methods */ 72 void captureCurrentSubroutineSet(subroutineUniformSet& set); 73 74 void getShaders(const glw::GLchar*& out_vertex_shader_code, const glw::GLchar*& out_tesselation_control_shader_code, 75 const glw::GLchar*& out_tesselation_evaluation_shader_code, 76 const glw::GLchar*& out_geometry_shader_code, const glw::GLchar*& out_fragment_shader_code); 77 78 void initSharedContexts(); 79 80 void prepareProgram(Utils::program** programs, bool is_separable); 81 82 void prepareProgramPipeline(glw::GLuint& pipeline_id, Utils::program** programs); 83 84 bool testCase(const glw::GLuint bit_field[5]); 85 86 bool testProgram(Utils::program** programs, bool is_separable, const glw::GLuint test_cases[][5], 87 glw::GLuint n_test_cases); 88 89 void updateCurrentSubroutineSet(const subroutineUniformSet& set); 90 91 /* Private fields */ 92 static const glw::GLuint m_n_shared_contexts; 93 static const glw::GLuint m_fragment_stage_index; 94 static const glw::GLuint m_geometry_stage_index; 95 static const glw::GLuint m_tesselation_control_stage_index; 96 static const glw::GLuint m_tesselation_evaluation_stage_index; 97 static const glw::GLuint m_vertex_stage_index; 98 99 glu::ApiType m_api_type; 100 de::SharedPtr<deqp::Context> m_base_context; 101 glu::RenderContext* m_shared_contexts[4]; 102 glw::GLuint m_program_pipelines[5]; 103 subroutineUniformSet m_subroutine_indices[2]; 104 subroutineUniformSet m_subroutine_uniform_locations; 105 }; 106 107 /* Constants used by FunctionalTest20_21 */ 108 const GLuint UniformPreservationTest::m_n_shared_contexts = 4; 109 const GLuint UniformPreservationTest::m_fragment_stage_index = 0; 110 const GLuint UniformPreservationTest::m_geometry_stage_index = 1; 111 const GLuint UniformPreservationTest::m_tesselation_control_stage_index = 2; 112 const GLuint UniformPreservationTest::m_tesselation_evaluation_stage_index = 3; 113 const GLuint UniformPreservationTest::m_vertex_stage_index = 4; 114 115 /** Set subroutine indices, indices are taken from one of two sets according to provided <bit_field> 116 * 117 * @param bit_field Selects source of of index for each stage 118 * @param subroutine_indices Array of two indices sets 119 **/ 120 void UniformPreservationTest::subroutineUniformSet::set(GLuint bit_field, 121 const subroutineUniformSet subroutine_indices[2]) 122 { 123 GLuint vertex_stage = ((bit_field & (0x01 << 0)) >> 0); 124 GLuint tesselation_control_stage = ((bit_field & (0x01 << 1)) >> 1); 125 GLuint tesselation_evaluation_stage = ((bit_field & (0x01 << 2)) >> 2); 126 GLuint geometry_stage = ((bit_field & (0x01 << 3)) >> 3); 127 GLuint fragment_stage = ((bit_field & (0x01 << 4)) >> 4); 128 129 m_vertex_shader_stage = subroutine_indices[vertex_stage].m_vertex_shader_stage; 130 m_tesselation_control_shader_stage = 131 subroutine_indices[tesselation_control_stage].m_tesselation_control_shader_stage; 132 m_tesselation_evaluation_shader_stage = 133 subroutine_indices[tesselation_evaluation_stage].m_tesselation_evaluation_shader_stage; 134 m_geometry_shader_stage = subroutine_indices[geometry_stage].m_geometry_shader_stage; 135 m_fragment_shader_stage = subroutine_indices[fragment_stage].m_fragment_shader_stage; 136 } 137 138 /** Negated comparison of two sets 139 * 140 * @param arg Instance that will be compared to this 141 * 142 * @return false when both objects are equal, true otherwise 143 **/ 144 bool UniformPreservationTest::subroutineUniformSet::operator!=(const subroutineUniformSet& arg) const 145 { 146 if ((arg.m_vertex_shader_stage != m_vertex_shader_stage) || 147 (arg.m_tesselation_control_shader_stage != m_tesselation_control_shader_stage) || 148 (arg.m_tesselation_evaluation_shader_stage != m_tesselation_evaluation_shader_stage) || 149 (arg.m_geometry_shader_stage != m_geometry_shader_stage) || 150 (arg.m_fragment_shader_stage != m_fragment_shader_stage)) 151 { 152 return true; 153 } 154 155 return false; 156 } 157 158 /** Constructor. 159 * 160 * @param context Rendering context. 161 * 162 **/ 163 UniformPreservationTest::UniformPreservationTest(tcu::TestContext& testCtx, glu::ApiType apiType) 164 : tcu::TestCase(testCtx, "uniform_preservation", 165 "Verifies that shader uniforms are preserved when rendering context is switched.") 166 , m_api_type(apiType) 167 { 168 for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i) 169 { 170 m_program_pipelines[i] = 0; 171 } 172 173 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 174 { 175 m_shared_contexts[i] = 0; 176 } 177 } 178 179 /** Deinitializes all GL objects that may have been created during 180 * test execution. 181 **/ 182 void UniformPreservationTest::deinit() 183 { 184 /* GL entry points */ 185 const glw::Functions& gl = m_base_context->getRenderContext().getFunctions(); 186 187 for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i) 188 { 189 if (0 != m_program_pipelines[i]) 190 { 191 gl.deleteProgramPipelines(1, &m_program_pipelines[i]); 192 m_program_pipelines[i] = 0; 193 } 194 } 195 196 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 197 { 198 if (0 != m_shared_contexts[i]) 199 { 200 delete m_shared_contexts[i]; 201 m_shared_contexts[i] = 0; 202 } 203 } 204 } 205 206 /** Executes test iteration. 207 * 208 * @return Returns STOP 209 */ 210 tcu::TestNode::IterateResult UniformPreservationTest::iterate() 211 { 212 /* Test cases, values stored here are used as bit fields */ 213 static const GLuint test_cases[][m_n_shared_contexts + 1] = { 214 { 0, 1, 2, 3, 4 }, { 1, 2, 3, 4, 0 }, { 2, 3, 4, 0, 1 }, { 3, 4, 0, 1, 2 }, 215 { 4, 0, 1, 2, 3 }, { 27, 28, 29, 30, 31 }, { 28, 29, 30, 31, 27 }, { 29, 30, 31, 27, 28 }, 216 { 30, 31, 27, 28, 29 }, { 31, 27, 28, 29, 30 }, 217 }; 218 static const GLuint n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]); 219 220 glu::ContextType context_type(m_api_type); 221 m_base_context = de::SharedPtr<deqp::Context>(new deqp::Context(m_testCtx, context_type)); 222 223 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */ 224 if (!m_base_context->getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine")) 225 { 226 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported."); 227 } 228 229 /* Prepare contexts */ 230 initSharedContexts(); 231 232 /* Test result */ 233 bool result = true; 234 235 /* Program pointers */ 236 Utils::program* program_pointers[5]; 237 238 /* Test monolithic program */ 239 { 240 /* Prepare program */ 241 Utils::program program(*m_base_context.get()); 242 243 program_pointers[m_fragment_stage_index] = &program; 244 245 prepareProgram(program_pointers, false); 246 247 /* Execute test */ 248 if (false == testProgram(program_pointers, false, test_cases, n_test_cases)) 249 { 250 m_testCtx.getLog() << tcu::TestLog::Message << "Last error message was caused by monolithic program." 251 << tcu::TestLog::EndMessage; 252 253 result = false; 254 } 255 } 256 257 /* Test separable programs */ 258 if (true == m_base_context->getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects")) 259 { 260 /* Prepare programs */ 261 Utils::program vertex_program(*m_base_context.get()); 262 Utils::program tesselation_control_program(*m_base_context.get()); 263 Utils::program tesselation_evaluation_program(*m_base_context.get()); 264 Utils::program geometry_program(*m_base_context.get()); 265 Utils::program fragment_program(*m_base_context.get()); 266 267 program_pointers[m_fragment_stage_index] = &fragment_program; 268 program_pointers[m_geometry_stage_index] = &geometry_program; 269 program_pointers[m_tesselation_control_stage_index] = &tesselation_control_program; 270 program_pointers[m_tesselation_evaluation_stage_index] = &tesselation_evaluation_program; 271 program_pointers[m_vertex_stage_index] = &vertex_program; 272 273 prepareProgram(program_pointers, true); 274 275 /* Execute test */ 276 if (false == testProgram(program_pointers, true, test_cases, n_test_cases)) 277 { 278 m_testCtx.getLog() << tcu::TestLog::Message << "Last error message was caused by separable program." 279 << tcu::TestLog::EndMessage; 280 result = false; 281 } 282 } 283 284 /* All done */ 285 if (true == result) 286 { 287 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 288 } 289 else 290 { 291 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 292 } 293 294 return tcu::TestNode::STOP; 295 } 296 297 /** Query state of subroutine uniforms of current program/pipeline 298 * 299 * @param set Storage for results 300 **/ 301 void UniformPreservationTest::captureCurrentSubroutineSet(subroutineUniformSet& set) 302 { 303 /* GL entry points */ 304 const glw::Functions& gl = m_base_context->getRenderContext().getFunctions(); 305 306 /* Fragment */ 307 gl.getUniformSubroutineuiv(GL_FRAGMENT_SHADER, m_subroutine_uniform_locations.m_fragment_shader_stage, 308 &set.m_fragment_shader_stage); 309 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv"); 310 311 /* Geometry */ 312 gl.getUniformSubroutineuiv(GL_GEOMETRY_SHADER, m_subroutine_uniform_locations.m_geometry_shader_stage, 313 &set.m_geometry_shader_stage); 314 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv"); 315 316 /* Tess ctrl */ 317 gl.getUniformSubroutineuiv(GL_TESS_CONTROL_SHADER, 318 m_subroutine_uniform_locations.m_tesselation_control_shader_stage, 319 &set.m_tesselation_control_shader_stage); 320 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv"); 321 322 /* Tess eval */ 323 gl.getUniformSubroutineuiv(GL_TESS_EVALUATION_SHADER, 324 m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage, 325 &set.m_tesselation_evaluation_shader_stage); 326 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv"); 327 328 /* Vertex */ 329 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_subroutine_uniform_locations.m_vertex_shader_stage, 330 &set.m_vertex_shader_stage); 331 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv"); 332 } 333 334 /** Get shaders' source code 335 * 336 * @param out_vertex_shader_code Vertex source code 337 * @param out_tesselation_control_shader_code Tess ctrl source code 338 * @param out_tesselation_evaluation_shader_code Tess eval source code 339 * @param out_geometry_shader_code Geometry source code 340 * @param out_fragment_shader_code Fragment source code 341 **/ 342 void UniformPreservationTest::getShaders(const glw::GLchar*& out_vertex_shader_code, 343 const glw::GLchar*& out_tesselation_control_shader_code, 344 const glw::GLchar*& out_tesselation_evaluation_shader_code, 345 const glw::GLchar*& out_geometry_shader_code, 346 const glw::GLchar*& out_fragment_shader_code) 347 { 348 static const GLchar* vertex_shader_code = "#version 400 core\n" 349 "#extension GL_ARB_shader_subroutine : require\n" 350 "\n" 351 "precision highp float;\n" 352 "\n" 353 "// Subroutine type\n" 354 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n" 355 "\n" 356 "// Subroutine definition\n" 357 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n" 358 "{\n" 359 " return left + right;\n" 360 "}\n" 361 "\n" 362 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n" 363 "{\n" 364 " return left * right;\n" 365 "}\n" 366 "\n" 367 "// Sub routine uniform\n" 368 "subroutine uniform routine_type routine;\n" 369 "\n" 370 "// Input data\n" 371 "uniform vec4 uni_vs_left;\n" 372 "uniform vec4 uni_vs_right;\n" 373 "\n" 374 "// Output\n" 375 "out vec4 vs_tcs_result;\n" 376 "\n" 377 "void main()\n" 378 "{\n" 379 " vs_tcs_result = routine(uni_vs_left, uni_vs_right);\n" 380 "}\n" 381 "\n"; 382 383 static const GLchar* tesselation_control_shader_code = 384 "#version 400 core\n" 385 "#extension GL_ARB_shader_subroutine : require\n" 386 "\n" 387 "precision highp float;\n" 388 "\n" 389 "layout(vertices = 1) out;\n" 390 "\n" 391 "// Subroutine type\n" 392 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n" 393 "\n" 394 "// Subroutine definition\n" 395 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n" 396 "{\n" 397 " return left + right;\n" 398 "}\n" 399 "\n" 400 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n" 401 "{\n" 402 " return left * right;\n" 403 "}\n" 404 "\n" 405 "// Sub routine uniform\n" 406 "subroutine uniform routine_type routine;\n" 407 "\n" 408 "// Input data\n" 409 "uniform vec4 uni_tcs_left;\n" 410 "uniform vec4 uni_tcs_right;\n" 411 "\n" 412 "in vec4 vs_tcs_result[];\n" 413 "\n" 414 "// Output\n" 415 "out vec4 tcs_tes_result[];\n" 416 "\n" 417 "void main()\n" 418 "{\n" 419 " gl_TessLevelOuter[0] = 1.0;\n" 420 " gl_TessLevelOuter[1] = 1.0;\n" 421 " gl_TessLevelOuter[2] = 1.0;\n" 422 " gl_TessLevelOuter[3] = 1.0;\n" 423 " gl_TessLevelInner[0] = 1.0;\n" 424 " gl_TessLevelInner[1] = 1.0;\n" 425 "\n" 426 " tcs_tes_result[gl_InvocationID] = routine(uni_tcs_left, uni_tcs_right) + vs_tcs_result[gl_InvocationID];\n" 427 "}\n" 428 "\n"; 429 430 static const GLchar* tesselation_evaluation_shader_code = 431 "#version 400 core\n" 432 "#extension GL_ARB_shader_subroutine : require\n" 433 "\n" 434 "precision highp float;\n" 435 "\n" 436 "layout(isolines, point_mode) in;\n" 437 "\n" 438 "// Subroutine type\n" 439 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n" 440 "\n" 441 "// Subroutine definition\n" 442 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n" 443 "{\n" 444 " return left + right;\n" 445 "}\n" 446 "\n" 447 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n" 448 "{\n" 449 " return left * right;\n" 450 "}\n" 451 "\n" 452 "// Sub routine uniform\n" 453 "subroutine uniform routine_type routine;\n" 454 "\n" 455 "// Input data\n" 456 "uniform vec4 uni_tes_left;\n" 457 "uniform vec4 uni_tes_right;\n" 458 "\n" 459 "in vec4 tcs_tes_result[];\n" 460 "\n" 461 "// Output\n" 462 "out vec4 tes_gs_result;\n" 463 "\n" 464 "void main()\n" 465 "{\n" 466 " tes_gs_result = routine(uni_tes_left, uni_tes_right) + tcs_tes_result[0];\n" 467 "}\n" 468 "\n"; 469 470 static const GLchar* geometry_shader_code = 471 "#version 400 core\n" 472 "#extension GL_ARB_shader_subroutine : require\n" 473 "\n" 474 "precision highp float;\n" 475 "\n" 476 "layout(points) in;\n" 477 "layout(points, max_vertices = 1) out;\n" 478 "\n" 479 "// Subroutine type\n" 480 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n" 481 "\n" 482 "// Subroutine definition\n" 483 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n" 484 "{\n" 485 " return left + right;\n" 486 "}\n" 487 "\n" 488 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n" 489 "{\n" 490 " return left * right;\n" 491 "}\n" 492 "\n" 493 "// Sub routine uniform\n" 494 "subroutine uniform routine_type routine;\n" 495 "\n" 496 "// Input data\n" 497 "uniform vec4 uni_gs_left;\n" 498 "uniform vec4 uni_gs_right;\n" 499 "\n" 500 "in vec4 tes_gs_result[];\n" 501 "\n" 502 "// Output\n" 503 "out vec4 gs_fs_result;\n" 504 "\n" 505 "void main()\n" 506 "{\n" 507 " gs_fs_result = routine(uni_gs_left, uni_gs_right) + tes_gs_result[0];\n" 508 "}\n" 509 "\n"; 510 511 static const GLchar* fragmenty_shader_code = 512 "#version 400 core\n" 513 "#extension GL_ARB_shader_subroutine : require\n" 514 "\n" 515 "precision highp float;\n" 516 "\n" 517 "// Subroutine type\n" 518 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n" 519 "\n" 520 "// Subroutine definition\n" 521 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n" 522 "{\n" 523 " return left + right;\n" 524 "}\n" 525 "\n" 526 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n" 527 "{\n" 528 " return left * right;\n" 529 "}\n" 530 "\n" 531 "// Sub routine uniform\n" 532 "subroutine uniform routine_type routine;\n" 533 "\n" 534 "// Input data\n" 535 "uniform vec4 uni_fs_left;\n" 536 "uniform vec4 uni_fs_right;\n" 537 "\n" 538 "in vec4 gs_fs_result;\n" 539 "\n" 540 "// Output\n" 541 "out vec4 fs_out_result;\n" 542 "\n" 543 "void main()\n" 544 "{\n" 545 " fs_out_result = routine(uni_fs_left, uni_fs_right) + gs_fs_result;\n" 546 "}\n" 547 "\n"; 548 549 out_vertex_shader_code = vertex_shader_code; 550 out_tesselation_control_shader_code = tesselation_control_shader_code; 551 out_tesselation_evaluation_shader_code = tesselation_evaluation_shader_code; 552 out_geometry_shader_code = geometry_shader_code; 553 out_fragment_shader_code = fragmenty_shader_code; 554 } 555 556 /** Create <m_n_shared_contexts> shared contexts 557 * 558 **/ 559 void UniformPreservationTest::initSharedContexts() 560 { 561 glu::ContextType context_type(m_api_type); 562 glu::RenderConfig render_config(context_type); 563 const tcu::CommandLine& command_line(m_testCtx.getCommandLine()); 564 glu::RenderContext* shared_context = &(m_base_context->getRenderContext()); 565 glu::parseRenderConfig(&render_config, command_line); 566 567 #if (DE_OS == DE_OS_ANDROID) 568 // Android can only have one Window created at a time 569 // Note that this surface type is not supported on all platforms 570 render_config.surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC; 571 #endif 572 573 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 574 { 575 m_shared_contexts[i] = 576 glu::createRenderContext(m_testCtx.getPlatform(), command_line, render_config, shared_context); 577 } 578 m_base_context->getRenderContext().makeCurrent(); 579 } 580 581 /** Prepare program(s) 582 * 583 * @param programs An array of 5 programs' pointers. If monolithic program is prepared that only index m_fragment_stage_index should be initialized, otherwise all 5 584 * @param is_separable Select if monolithic or separable programs should be prepared 585 **/ 586 void UniformPreservationTest::prepareProgram(Utils::program** programs, bool is_separable) 587 { 588 /* Get shader sources */ 589 const GLchar* vertex_shader_code; 590 const GLchar* tesselation_control_shader_code; 591 const GLchar* tesselation_evaluation_shader_code; 592 const GLchar* geometry_shader_code; 593 const GLchar* fragmenty_shader_code; 594 595 getShaders(vertex_shader_code, tesselation_control_shader_code, tesselation_evaluation_shader_code, 596 geometry_shader_code, fragmenty_shader_code); 597 598 /* Subroutines and uniform names */ 599 static const GLchar* subroutine_names[] = { "add", "multiply" }; 600 static const GLuint n_subroutines = sizeof(subroutine_names) / sizeof(subroutine_names[0]); 601 602 static const GLchar* subroutine_uniform_name = "routine"; 603 604 /* Build program */ 605 if (false == is_separable) 606 { 607 programs[0]->build(0 /* compute shader source */, fragmenty_shader_code, geometry_shader_code, 608 tesselation_control_shader_code, tesselation_evaluation_shader_code, vertex_shader_code, 609 0 /* varying_names */, 0 /* n_varying_names */); 610 611 programs[m_geometry_stage_index] = programs[m_fragment_stage_index]; 612 programs[m_tesselation_control_stage_index] = programs[m_fragment_stage_index]; 613 programs[m_tesselation_evaluation_stage_index] = programs[m_fragment_stage_index]; 614 programs[m_vertex_stage_index] = programs[m_fragment_stage_index]; 615 } 616 else 617 { 618 programs[m_fragment_stage_index]->build(0, fragmenty_shader_code, 0, 0, 0, 0, 0, 0, true); 619 programs[m_geometry_stage_index]->build(0, 0, geometry_shader_code, 0, 0, 0, 0, 0, true); 620 programs[m_tesselation_control_stage_index]->build(0, 0, 0, tesselation_control_shader_code, 0, 0, 0, 0, true); 621 programs[m_tesselation_evaluation_stage_index]->build(0, 0, 0, 0, tesselation_evaluation_shader_code, 0, 0, 0, 622 true); 623 programs[m_vertex_stage_index]->build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0, true); 624 } 625 626 /* Get subroutine indices */ 627 for (GLuint i = 0; i < n_subroutines; ++i) 628 { 629 m_subroutine_indices[i].m_fragment_shader_stage = 630 programs[m_fragment_stage_index]->getSubroutineIndex(subroutine_names[i], GL_FRAGMENT_SHADER); 631 632 m_subroutine_indices[i].m_geometry_shader_stage = 633 programs[m_geometry_stage_index]->getSubroutineIndex(subroutine_names[i], GL_GEOMETRY_SHADER); 634 635 m_subroutine_indices[i].m_tesselation_control_shader_stage = 636 programs[m_tesselation_control_stage_index]->getSubroutineIndex(subroutine_names[i], 637 GL_TESS_CONTROL_SHADER); 638 639 m_subroutine_indices[i].m_tesselation_evaluation_shader_stage = 640 programs[m_tesselation_evaluation_stage_index]->getSubroutineIndex(subroutine_names[i], 641 GL_TESS_EVALUATION_SHADER); 642 643 m_subroutine_indices[i].m_vertex_shader_stage = 644 programs[m_vertex_stage_index]->getSubroutineIndex(subroutine_names[i], GL_VERTEX_SHADER); 645 } 646 647 /* Get subroutine uniform locations */ 648 m_subroutine_uniform_locations.m_fragment_shader_stage = 649 programs[m_fragment_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_FRAGMENT_SHADER); 650 651 m_subroutine_uniform_locations.m_geometry_shader_stage = 652 programs[m_geometry_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_GEOMETRY_SHADER); 653 654 m_subroutine_uniform_locations.m_tesselation_control_shader_stage = 655 programs[m_tesselation_control_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, 656 GL_TESS_CONTROL_SHADER); 657 658 m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage = 659 programs[m_tesselation_evaluation_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, 660 GL_TESS_EVALUATION_SHADER); 661 662 m_subroutine_uniform_locations.m_vertex_shader_stage = 663 programs[m_vertex_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_VERTEX_SHADER); 664 } 665 666 /** Generate program pipeline for current context and attach separable programs 667 * 668 * @param out_pipeline_id Id of generated pipeline 669 * @param programs Collection of separable programs 670 **/ 671 void UniformPreservationTest::prepareProgramPipeline(glw::GLuint& out_pipeline_id, Utils::program** programs) 672 { 673 /* GL entry points */ 674 const glw::Functions& gl = m_base_context->getRenderContext().getFunctions(); 675 676 /* Generate */ 677 gl.genProgramPipelines(1, &out_pipeline_id); 678 GLU_EXPECT_NO_ERROR(gl.getError(), "GenProgramPipelines"); 679 680 /* Bind */ 681 gl.bindProgramPipeline(out_pipeline_id); 682 GLU_EXPECT_NO_ERROR(gl.getError(), "BindProgramPipeline"); 683 684 /* Set up programs */ 685 gl.useProgramStages(out_pipeline_id, GL_FRAGMENT_SHADER_BIT, programs[m_fragment_stage_index]->m_program_object_id); 686 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages"); 687 688 gl.useProgramStages(out_pipeline_id, GL_GEOMETRY_SHADER_BIT, programs[m_geometry_stage_index]->m_program_object_id); 689 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages"); 690 691 gl.useProgramStages(out_pipeline_id, GL_TESS_CONTROL_SHADER_BIT, 692 programs[m_tesselation_control_stage_index]->m_program_object_id); 693 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages"); 694 695 gl.useProgramStages(out_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT, 696 programs[m_tesselation_evaluation_stage_index]->m_program_object_id); 697 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages"); 698 699 gl.useProgramStages(out_pipeline_id, GL_VERTEX_SHADER_BIT, programs[m_vertex_stage_index]->m_program_object_id); 700 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages"); 701 } 702 703 /** Test specific case 704 * 705 * @param bit_field An array of 5 bit fields used to set up subroutine uniforms, one element per context 706 * 707 * @return True if test pass, false otherwise 708 **/ 709 bool UniformPreservationTest::testCase(const glw::GLuint bit_field[5]) 710 { 711 /* Storage for subroutine indices */ 712 subroutineUniformSet captured_subroutine_indices[m_n_shared_contexts + 1]; 713 subroutineUniformSet subroutine_indices[m_n_shared_contexts + 1]; 714 715 /* Prepare subroutine_indices with bit fields */ 716 for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i) 717 { 718 subroutine_indices[i].set(bit_field[i], m_subroutine_indices); 719 }; 720 721 /* Update subroutine uniforms, each context gets different set */ 722 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 723 { 724 m_shared_contexts[i]->makeCurrent(); 725 updateCurrentSubroutineSet(subroutine_indices[i]); 726 } 727 728 m_base_context->getRenderContext().makeCurrent(); 729 updateCurrentSubroutineSet(subroutine_indices[m_n_shared_contexts]); 730 731 /* Capture subroutine uniforms */ 732 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 733 { 734 m_shared_contexts[i]->makeCurrent(); 735 captureCurrentSubroutineSet(captured_subroutine_indices[i]); 736 } 737 738 m_base_context->getRenderContext().makeCurrent(); 739 captureCurrentSubroutineSet(captured_subroutine_indices[m_n_shared_contexts]); 740 741 /* Verify that captured uniforms match expected values */ 742 for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i) 743 { 744 if (subroutine_indices[i] != captured_subroutine_indices[i]) 745 { 746 m_testCtx.getLog() << tcu::TestLog::Message << "Error." 747 << " Context: " << i << " VS, expected: " << subroutine_indices[i].m_vertex_shader_stage 748 << " captured: " << captured_subroutine_indices[i].m_vertex_shader_stage 749 << " TCS, expected: " << subroutine_indices[i].m_tesselation_control_shader_stage 750 << " captured: " << captured_subroutine_indices[i].m_tesselation_control_shader_stage 751 << " TES, expected: " << subroutine_indices[i].m_tesselation_evaluation_shader_stage 752 << " captured: " << captured_subroutine_indices[i].m_tesselation_evaluation_shader_stage 753 << " GS, expected: " << subroutine_indices[i].m_geometry_shader_stage 754 << " captured: " << captured_subroutine_indices[i].m_geometry_shader_stage 755 << " FS, expected: " << subroutine_indices[i].m_fragment_shader_stage 756 << " captured: " << captured_subroutine_indices[i].m_fragment_shader_stage 757 << tcu::TestLog::EndMessage; 758 759 return false; 760 } 761 } 762 763 return true; 764 } 765 766 /** Test a program or pipeline 767 * 768 * @param programs An array of 5 programs\ pointers, as in preparePrograms 769 * @param is_separable Selects if monolithic or separable programs should be used 770 * @param test_cases Collection of test cases 771 * @param n_test_cases Number of test cases 772 * 773 * @return True if all cases pass, false otherwise 774 **/ 775 bool UniformPreservationTest::testProgram(Utils::program** programs, bool is_separable, 776 const glw::GLuint test_cases[][5], glw::GLuint n_test_cases) 777 { 778 /* Set program/pipeline as current for all contexts */ 779 if (false == is_separable) 780 { 781 programs[0]->use(); 782 783 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 784 { 785 m_shared_contexts[i]->makeCurrent(); 786 programs[0]->use(); 787 } 788 } 789 else 790 { 791 /* GL entry points */ 792 const glw::Functions& gl = m_base_context->getRenderContext().getFunctions(); 793 794 /* Make sure that program pipeline will be used */ 795 gl.useProgram(0); 796 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram"); 797 798 prepareProgramPipeline(m_program_pipelines[m_n_shared_contexts], programs); 799 800 for (GLuint i = 0; i < m_n_shared_contexts; ++i) 801 { 802 m_shared_contexts[i]->makeCurrent(); 803 804 /* Make sure that program pipeline will be used */ 805 gl.useProgram(0); 806 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram"); 807 808 prepareProgramPipeline(m_program_pipelines[i], programs); 809 } 810 } 811 812 /* Execute test */ 813 bool result = true; 814 for (GLuint i = 0; i < n_test_cases; ++i) 815 { 816 if (false == testCase(test_cases[i])) 817 { 818 result = false; 819 break; 820 } 821 } 822 823 return result; 824 } 825 826 /** Set up subroutine uniforms for current program or pipeline 827 * 828 * @param set Set of subroutine indices 829 **/ 830 void UniformPreservationTest::updateCurrentSubroutineSet(const subroutineUniformSet& set) 831 { 832 /* GL entry points */ 833 const glw::Functions& gl = m_base_context->getRenderContext().getFunctions(); 834 835 /* Fragment */ 836 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1 /* count */, &set.m_fragment_shader_stage); 837 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv"); 838 839 /* Geometry */ 840 gl.uniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1 /* count */, &set.m_geometry_shader_stage); 841 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv"); 842 843 /* Tess ctrl */ 844 gl.uniformSubroutinesuiv(GL_TESS_CONTROL_SHADER, 1 /* count */, &set.m_tesselation_control_shader_stage); 845 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv"); 846 847 /* Tess eval */ 848 gl.uniformSubroutinesuiv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &set.m_tesselation_evaluation_shader_stage); 849 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv"); 850 851 /* Vertex */ 852 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, &set.m_vertex_shader_stage); 853 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv"); 854 } 855 856 /** Constructor. 857 * 858 * @param context Rendering context. 859 **/ 860 MultipleContextsTests::MultipleContextsTests(tcu::TestContext& testCtx, glu::ApiType apiType) 861 : tcu::TestCaseGroup(testCtx, "multiple_contexts", "Verifies \"shader_subroutine\" functionality") 862 , m_apiType(apiType) 863 { 864 /* Left blank on purpose */ 865 } 866 867 /** Initializes a texture_storage_multisample test group. 868 * 869 **/ 870 void MultipleContextsTests::init(void) 871 { 872 addChild(new UniformPreservationTest(m_testCtx, m_apiType)); 873 } 874 875 } /* glcts namespace */ 876