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 **/
set(GLuint bit_field,const subroutineUniformSet subroutine_indices[2])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 **/
operator !=(const subroutineUniformSet & arg) const144 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 **/
UniformPreservationTest(tcu::TestContext & testCtx,glu::ApiType apiType)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 **/
deinit()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 */
iterate()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}, {4, 0, 1, 2, 3},
215 {27, 28, 29, 30, 31}, {28, 29, 30, 31, 27}, {29, 30, 31, 27, 28}, {30, 31, 27, 28, 29}, {31, 27, 28, 29, 30},
216 };
217 static const GLuint n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
218
219 glu::ContextType context_type(m_api_type);
220 m_base_context = de::SharedPtr<deqp::Context>(new deqp::Context(m_testCtx, context_type));
221
222 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
223 if (!m_base_context->getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
224 {
225 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
226 }
227
228 /* Prepare contexts */
229 initSharedContexts();
230
231 /* Test result */
232 bool result = true;
233
234 /* Program pointers */
235 Utils::program *program_pointers[5];
236
237 /* Test monolithic program */
238 {
239 /* Prepare program */
240 Utils::program program(*m_base_context.get());
241
242 program_pointers[m_fragment_stage_index] = &program;
243
244 prepareProgram(program_pointers, false);
245
246 /* Execute test */
247 if (false == testProgram(program_pointers, false, test_cases, n_test_cases))
248 {
249 m_testCtx.getLog() << tcu::TestLog::Message << "Last error message was caused by monolithic program."
250 << tcu::TestLog::EndMessage;
251
252 result = false;
253 }
254 }
255
256 /* Test separable programs */
257 if (true == m_base_context->getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
258 {
259 /* Prepare programs */
260 Utils::program vertex_program(*m_base_context.get());
261 Utils::program tesselation_control_program(*m_base_context.get());
262 Utils::program tesselation_evaluation_program(*m_base_context.get());
263 Utils::program geometry_program(*m_base_context.get());
264 Utils::program fragment_program(*m_base_context.get());
265
266 program_pointers[m_fragment_stage_index] = &fragment_program;
267 program_pointers[m_geometry_stage_index] = &geometry_program;
268 program_pointers[m_tesselation_control_stage_index] = &tesselation_control_program;
269 program_pointers[m_tesselation_evaluation_stage_index] = &tesselation_evaluation_program;
270 program_pointers[m_vertex_stage_index] = &vertex_program;
271
272 prepareProgram(program_pointers, true);
273
274 /* Execute test */
275 if (false == testProgram(program_pointers, true, test_cases, n_test_cases))
276 {
277 m_testCtx.getLog() << tcu::TestLog::Message << "Last error message was caused by separable program."
278 << tcu::TestLog::EndMessage;
279 result = false;
280 }
281 }
282
283 /* All done */
284 if (true == result)
285 {
286 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
287 }
288 else
289 {
290 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
291 }
292
293 return tcu::TestNode::STOP;
294 }
295
296 /** Query state of subroutine uniforms of current program/pipeline
297 *
298 * @param set Storage for results
299 **/
captureCurrentSubroutineSet(subroutineUniformSet & set)300 void UniformPreservationTest::captureCurrentSubroutineSet(subroutineUniformSet &set)
301 {
302 /* GL entry points */
303 const glw::Functions &gl = m_base_context->getRenderContext().getFunctions();
304
305 /* Fragment */
306 gl.getUniformSubroutineuiv(GL_FRAGMENT_SHADER, m_subroutine_uniform_locations.m_fragment_shader_stage,
307 &set.m_fragment_shader_stage);
308 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
309
310 /* Geometry */
311 gl.getUniformSubroutineuiv(GL_GEOMETRY_SHADER, m_subroutine_uniform_locations.m_geometry_shader_stage,
312 &set.m_geometry_shader_stage);
313 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
314
315 /* Tess ctrl */
316 gl.getUniformSubroutineuiv(GL_TESS_CONTROL_SHADER,
317 m_subroutine_uniform_locations.m_tesselation_control_shader_stage,
318 &set.m_tesselation_control_shader_stage);
319 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
320
321 /* Tess eval */
322 gl.getUniformSubroutineuiv(GL_TESS_EVALUATION_SHADER,
323 m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage,
324 &set.m_tesselation_evaluation_shader_stage);
325 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
326
327 /* Vertex */
328 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_subroutine_uniform_locations.m_vertex_shader_stage,
329 &set.m_vertex_shader_stage);
330 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
331 }
332
333 /** Get shaders' source code
334 *
335 * @param out_vertex_shader_code Vertex source code
336 * @param out_tesselation_control_shader_code Tess ctrl source code
337 * @param out_tesselation_evaluation_shader_code Tess eval source code
338 * @param out_geometry_shader_code Geometry source code
339 * @param out_fragment_shader_code Fragment source code
340 **/
getShaders(const glw::GLchar * & out_vertex_shader_code,const glw::GLchar * & out_tesselation_control_shader_code,const glw::GLchar * & out_tesselation_evaluation_shader_code,const glw::GLchar * & out_geometry_shader_code,const glw::GLchar * & out_fragment_shader_code)341 void UniformPreservationTest::getShaders(const glw::GLchar *&out_vertex_shader_code,
342 const glw::GLchar *&out_tesselation_control_shader_code,
343 const glw::GLchar *&out_tesselation_evaluation_shader_code,
344 const glw::GLchar *&out_geometry_shader_code,
345 const glw::GLchar *&out_fragment_shader_code)
346 {
347 static const GLchar *vertex_shader_code = "#version 400 core\n"
348 "#extension GL_ARB_shader_subroutine : require\n"
349 "\n"
350 "precision highp float;\n"
351 "\n"
352 "// Subroutine type\n"
353 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
354 "\n"
355 "// Subroutine definition\n"
356 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
357 "{\n"
358 " return left + right;\n"
359 "}\n"
360 "\n"
361 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
362 "{\n"
363 " return left * right;\n"
364 "}\n"
365 "\n"
366 "// Sub routine uniform\n"
367 "subroutine uniform routine_type routine;\n"
368 "\n"
369 "// Input data\n"
370 "uniform vec4 uni_vs_left;\n"
371 "uniform vec4 uni_vs_right;\n"
372 "\n"
373 "// Output\n"
374 "out vec4 vs_tcs_result;\n"
375 "\n"
376 "void main()\n"
377 "{\n"
378 " vs_tcs_result = routine(uni_vs_left, uni_vs_right);\n"
379 "}\n"
380 "\n";
381
382 static const GLchar *tesselation_control_shader_code =
383 "#version 400 core\n"
384 "#extension GL_ARB_shader_subroutine : require\n"
385 "\n"
386 "precision highp float;\n"
387 "\n"
388 "layout(vertices = 1) out;\n"
389 "\n"
390 "// Subroutine type\n"
391 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
392 "\n"
393 "// Subroutine definition\n"
394 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
395 "{\n"
396 " return left + right;\n"
397 "}\n"
398 "\n"
399 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
400 "{\n"
401 " return left * right;\n"
402 "}\n"
403 "\n"
404 "// Sub routine uniform\n"
405 "subroutine uniform routine_type routine;\n"
406 "\n"
407 "// Input data\n"
408 "uniform vec4 uni_tcs_left;\n"
409 "uniform vec4 uni_tcs_right;\n"
410 "\n"
411 "in vec4 vs_tcs_result[];\n"
412 "\n"
413 "// Output\n"
414 "out vec4 tcs_tes_result[];\n"
415 "\n"
416 "void main()\n"
417 "{\n"
418 " gl_TessLevelOuter[0] = 1.0;\n"
419 " gl_TessLevelOuter[1] = 1.0;\n"
420 " gl_TessLevelOuter[2] = 1.0;\n"
421 " gl_TessLevelOuter[3] = 1.0;\n"
422 " gl_TessLevelInner[0] = 1.0;\n"
423 " gl_TessLevelInner[1] = 1.0;\n"
424 "\n"
425 " tcs_tes_result[gl_InvocationID] = routine(uni_tcs_left, uni_tcs_right) + vs_tcs_result[gl_InvocationID];\n"
426 "}\n"
427 "\n";
428
429 static const GLchar *tesselation_evaluation_shader_code =
430 "#version 400 core\n"
431 "#extension GL_ARB_shader_subroutine : require\n"
432 "\n"
433 "precision highp float;\n"
434 "\n"
435 "layout(isolines, point_mode) in;\n"
436 "\n"
437 "// Subroutine type\n"
438 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
439 "\n"
440 "// Subroutine definition\n"
441 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
442 "{\n"
443 " return left + right;\n"
444 "}\n"
445 "\n"
446 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
447 "{\n"
448 " return left * right;\n"
449 "}\n"
450 "\n"
451 "// Sub routine uniform\n"
452 "subroutine uniform routine_type routine;\n"
453 "\n"
454 "// Input data\n"
455 "uniform vec4 uni_tes_left;\n"
456 "uniform vec4 uni_tes_right;\n"
457 "\n"
458 "in vec4 tcs_tes_result[];\n"
459 "\n"
460 "// Output\n"
461 "out vec4 tes_gs_result;\n"
462 "\n"
463 "void main()\n"
464 "{\n"
465 " tes_gs_result = routine(uni_tes_left, uni_tes_right) + tcs_tes_result[0];\n"
466 "}\n"
467 "\n";
468
469 static const GLchar *geometry_shader_code =
470 "#version 400 core\n"
471 "#extension GL_ARB_shader_subroutine : require\n"
472 "\n"
473 "precision highp float;\n"
474 "\n"
475 "layout(points) in;\n"
476 "layout(points, max_vertices = 1) out;\n"
477 "\n"
478 "// Subroutine type\n"
479 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
480 "\n"
481 "// Subroutine definition\n"
482 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
483 "{\n"
484 " return left + right;\n"
485 "}\n"
486 "\n"
487 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
488 "{\n"
489 " return left * right;\n"
490 "}\n"
491 "\n"
492 "// Sub routine uniform\n"
493 "subroutine uniform routine_type routine;\n"
494 "\n"
495 "// Input data\n"
496 "uniform vec4 uni_gs_left;\n"
497 "uniform vec4 uni_gs_right;\n"
498 "\n"
499 "in vec4 tes_gs_result[];\n"
500 "\n"
501 "// Output\n"
502 "out vec4 gs_fs_result;\n"
503 "\n"
504 "void main()\n"
505 "{\n"
506 " gs_fs_result = routine(uni_gs_left, uni_gs_right) + tes_gs_result[0];\n"
507 "}\n"
508 "\n";
509
510 static const GLchar *fragmenty_shader_code =
511 "#version 400 core\n"
512 "#extension GL_ARB_shader_subroutine : require\n"
513 "\n"
514 "precision highp float;\n"
515 "\n"
516 "// Subroutine type\n"
517 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
518 "\n"
519 "// Subroutine definition\n"
520 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
521 "{\n"
522 " return left + right;\n"
523 "}\n"
524 "\n"
525 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
526 "{\n"
527 " return left * right;\n"
528 "}\n"
529 "\n"
530 "// Sub routine uniform\n"
531 "subroutine uniform routine_type routine;\n"
532 "\n"
533 "// Input data\n"
534 "uniform vec4 uni_fs_left;\n"
535 "uniform vec4 uni_fs_right;\n"
536 "\n"
537 "in vec4 gs_fs_result;\n"
538 "\n"
539 "// Output\n"
540 "out vec4 fs_out_result;\n"
541 "\n"
542 "void main()\n"
543 "{\n"
544 " fs_out_result = routine(uni_fs_left, uni_fs_right) + gs_fs_result;\n"
545 "}\n"
546 "\n";
547
548 out_vertex_shader_code = vertex_shader_code;
549 out_tesselation_control_shader_code = tesselation_control_shader_code;
550 out_tesselation_evaluation_shader_code = tesselation_evaluation_shader_code;
551 out_geometry_shader_code = geometry_shader_code;
552 out_fragment_shader_code = fragmenty_shader_code;
553 }
554
555 /** Create <m_n_shared_contexts> shared contexts
556 *
557 **/
initSharedContexts()558 void UniformPreservationTest::initSharedContexts()
559 {
560 glu::ContextType context_type(m_api_type);
561 glu::RenderConfig render_config(context_type);
562 const tcu::CommandLine &command_line(m_testCtx.getCommandLine());
563 glu::RenderContext *shared_context = &(m_base_context->getRenderContext());
564 glu::parseRenderConfig(&render_config, command_line);
565
566 #if (DE_OS == DE_OS_ANDROID)
567 // Android can only have one Window created at a time
568 // Note that this surface type is not supported on all platforms
569 render_config.surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;
570 #endif
571
572 for (GLuint i = 0; i < m_n_shared_contexts; ++i)
573 {
574 m_shared_contexts[i] =
575 glu::createRenderContext(m_testCtx.getPlatform(), command_line, render_config, shared_context);
576 }
577 m_base_context->getRenderContext().makeCurrent();
578 }
579
580 /** Prepare program(s)
581 *
582 * @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
583 * @param is_separable Select if monolithic or separable programs should be prepared
584 **/
prepareProgram(Utils::program ** programs,bool is_separable)585 void UniformPreservationTest::prepareProgram(Utils::program **programs, bool is_separable)
586 {
587 /* Get shader sources */
588 const GLchar *vertex_shader_code;
589 const GLchar *tesselation_control_shader_code;
590 const GLchar *tesselation_evaluation_shader_code;
591 const GLchar *geometry_shader_code;
592 const GLchar *fragmenty_shader_code;
593
594 getShaders(vertex_shader_code, tesselation_control_shader_code, tesselation_evaluation_shader_code,
595 geometry_shader_code, fragmenty_shader_code);
596
597 /* Subroutines and uniform names */
598 static const GLchar *subroutine_names[] = {"add", "multiply"};
599 static const GLuint n_subroutines = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
600
601 static const GLchar *subroutine_uniform_name = "routine";
602
603 /* Build program */
604 if (false == is_separable)
605 {
606 programs[0]->build(0 /* compute shader source */, fragmenty_shader_code, geometry_shader_code,
607 tesselation_control_shader_code, tesselation_evaluation_shader_code, vertex_shader_code,
608 0 /* varying_names */, 0 /* n_varying_names */);
609
610 programs[m_geometry_stage_index] = programs[m_fragment_stage_index];
611 programs[m_tesselation_control_stage_index] = programs[m_fragment_stage_index];
612 programs[m_tesselation_evaluation_stage_index] = programs[m_fragment_stage_index];
613 programs[m_vertex_stage_index] = programs[m_fragment_stage_index];
614 }
615 else
616 {
617 programs[m_fragment_stage_index]->build(0, fragmenty_shader_code, 0, 0, 0, 0, 0, 0, true);
618 programs[m_geometry_stage_index]->build(0, 0, geometry_shader_code, 0, 0, 0, 0, 0, true);
619 programs[m_tesselation_control_stage_index]->build(0, 0, 0, tesselation_control_shader_code, 0, 0, 0, 0, true);
620 programs[m_tesselation_evaluation_stage_index]->build(0, 0, 0, 0, tesselation_evaluation_shader_code, 0, 0, 0,
621 true);
622 programs[m_vertex_stage_index]->build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0, true);
623 }
624
625 /* Get subroutine indices */
626 for (GLuint i = 0; i < n_subroutines; ++i)
627 {
628 m_subroutine_indices[i].m_fragment_shader_stage =
629 programs[m_fragment_stage_index]->getSubroutineIndex(subroutine_names[i], GL_FRAGMENT_SHADER);
630
631 m_subroutine_indices[i].m_geometry_shader_stage =
632 programs[m_geometry_stage_index]->getSubroutineIndex(subroutine_names[i], GL_GEOMETRY_SHADER);
633
634 m_subroutine_indices[i].m_tesselation_control_shader_stage =
635 programs[m_tesselation_control_stage_index]->getSubroutineIndex(subroutine_names[i],
636 GL_TESS_CONTROL_SHADER);
637
638 m_subroutine_indices[i].m_tesselation_evaluation_shader_stage =
639 programs[m_tesselation_evaluation_stage_index]->getSubroutineIndex(subroutine_names[i],
640 GL_TESS_EVALUATION_SHADER);
641
642 m_subroutine_indices[i].m_vertex_shader_stage =
643 programs[m_vertex_stage_index]->getSubroutineIndex(subroutine_names[i], GL_VERTEX_SHADER);
644 }
645
646 /* Get subroutine uniform locations */
647 m_subroutine_uniform_locations.m_fragment_shader_stage =
648 programs[m_fragment_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_FRAGMENT_SHADER);
649
650 m_subroutine_uniform_locations.m_geometry_shader_stage =
651 programs[m_geometry_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_GEOMETRY_SHADER);
652
653 m_subroutine_uniform_locations.m_tesselation_control_shader_stage =
654 programs[m_tesselation_control_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name,
655 GL_TESS_CONTROL_SHADER);
656
657 m_subroutine_uniform_locations.m_tesselation_evaluation_shader_stage =
658 programs[m_tesselation_evaluation_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name,
659 GL_TESS_EVALUATION_SHADER);
660
661 m_subroutine_uniform_locations.m_vertex_shader_stage =
662 programs[m_vertex_stage_index]->getSubroutineUniformLocation(subroutine_uniform_name, GL_VERTEX_SHADER);
663 }
664
665 /** Generate program pipeline for current context and attach separable programs
666 *
667 * @param out_pipeline_id Id of generated pipeline
668 * @param programs Collection of separable programs
669 **/
prepareProgramPipeline(glw::GLuint & out_pipeline_id,Utils::program ** programs)670 void UniformPreservationTest::prepareProgramPipeline(glw::GLuint &out_pipeline_id, Utils::program **programs)
671 {
672 /* GL entry points */
673 const glw::Functions &gl = m_base_context->getRenderContext().getFunctions();
674
675 /* Generate */
676 gl.genProgramPipelines(1, &out_pipeline_id);
677 GLU_EXPECT_NO_ERROR(gl.getError(), "GenProgramPipelines");
678
679 /* Bind */
680 gl.bindProgramPipeline(out_pipeline_id);
681 GLU_EXPECT_NO_ERROR(gl.getError(), "BindProgramPipeline");
682
683 /* Set up programs */
684 gl.useProgramStages(out_pipeline_id, GL_FRAGMENT_SHADER_BIT, programs[m_fragment_stage_index]->m_program_object_id);
685 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
686
687 gl.useProgramStages(out_pipeline_id, GL_GEOMETRY_SHADER_BIT, programs[m_geometry_stage_index]->m_program_object_id);
688 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
689
690 gl.useProgramStages(out_pipeline_id, GL_TESS_CONTROL_SHADER_BIT,
691 programs[m_tesselation_control_stage_index]->m_program_object_id);
692 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
693
694 gl.useProgramStages(out_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT,
695 programs[m_tesselation_evaluation_stage_index]->m_program_object_id);
696 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
697
698 gl.useProgramStages(out_pipeline_id, GL_VERTEX_SHADER_BIT, programs[m_vertex_stage_index]->m_program_object_id);
699 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages");
700 }
701
702 /** Test specific case
703 *
704 * @param bit_field An array of 5 bit fields used to set up subroutine uniforms, one element per context
705 *
706 * @return True if test pass, false otherwise
707 **/
testCase(const glw::GLuint bit_field[5])708 bool UniformPreservationTest::testCase(const glw::GLuint bit_field[5])
709 {
710 /* Storage for subroutine indices */
711 subroutineUniformSet captured_subroutine_indices[m_n_shared_contexts + 1];
712 subroutineUniformSet subroutine_indices[m_n_shared_contexts + 1];
713
714 /* Prepare subroutine_indices with bit fields */
715 for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
716 {
717 subroutine_indices[i].set(bit_field[i], m_subroutine_indices);
718 }
719
720 /* Update subroutine uniforms, each context gets different set */
721 for (GLuint i = 0; i < m_n_shared_contexts; ++i)
722 {
723 m_shared_contexts[i]->makeCurrent();
724 updateCurrentSubroutineSet(subroutine_indices[i]);
725 }
726
727 m_base_context->getRenderContext().makeCurrent();
728 updateCurrentSubroutineSet(subroutine_indices[m_n_shared_contexts]);
729
730 /* Capture subroutine uniforms */
731 for (GLuint i = 0; i < m_n_shared_contexts; ++i)
732 {
733 m_shared_contexts[i]->makeCurrent();
734 captureCurrentSubroutineSet(captured_subroutine_indices[i]);
735 }
736
737 m_base_context->getRenderContext().makeCurrent();
738 captureCurrentSubroutineSet(captured_subroutine_indices[m_n_shared_contexts]);
739
740 /* Verify that captured uniforms match expected values */
741 for (GLuint i = 0; i < m_n_shared_contexts + 1; ++i)
742 {
743 if (subroutine_indices[i] != captured_subroutine_indices[i])
744 {
745 m_testCtx.getLog() << tcu::TestLog::Message << "Error."
746 << " Context: " << i << " VS, expected: " << subroutine_indices[i].m_vertex_shader_stage
747 << " captured: " << captured_subroutine_indices[i].m_vertex_shader_stage
748 << " TCS, expected: " << subroutine_indices[i].m_tesselation_control_shader_stage
749 << " captured: " << captured_subroutine_indices[i].m_tesselation_control_shader_stage
750 << " TES, expected: " << subroutine_indices[i].m_tesselation_evaluation_shader_stage
751 << " captured: " << captured_subroutine_indices[i].m_tesselation_evaluation_shader_stage
752 << " GS, expected: " << subroutine_indices[i].m_geometry_shader_stage
753 << " captured: " << captured_subroutine_indices[i].m_geometry_shader_stage
754 << " FS, expected: " << subroutine_indices[i].m_fragment_shader_stage
755 << " captured: " << captured_subroutine_indices[i].m_fragment_shader_stage
756 << tcu::TestLog::EndMessage;
757
758 return false;
759 }
760 }
761
762 return true;
763 }
764
765 /** Test a program or pipeline
766 *
767 * @param programs An array of 5 programs\ pointers, as in preparePrograms
768 * @param is_separable Selects if monolithic or separable programs should be used
769 * @param test_cases Collection of test cases
770 * @param n_test_cases Number of test cases
771 *
772 * @return True if all cases pass, false otherwise
773 **/
testProgram(Utils::program ** programs,bool is_separable,const glw::GLuint test_cases[][5],glw::GLuint n_test_cases)774 bool UniformPreservationTest::testProgram(Utils::program **programs, bool is_separable,
775 const glw::GLuint test_cases[][5], glw::GLuint n_test_cases)
776 {
777 /* Set program/pipeline as current for all contexts */
778 if (false == is_separable)
779 {
780 programs[0]->use();
781
782 for (GLuint i = 0; i < m_n_shared_contexts; ++i)
783 {
784 m_shared_contexts[i]->makeCurrent();
785 programs[0]->use();
786 }
787 }
788 else
789 {
790 /* GL entry points */
791 const glw::Functions &gl = m_base_context->getRenderContext().getFunctions();
792
793 /* Make sure that program pipeline will be used */
794 gl.useProgram(0);
795 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
796
797 prepareProgramPipeline(m_program_pipelines[m_n_shared_contexts], programs);
798
799 for (GLuint i = 0; i < m_n_shared_contexts; ++i)
800 {
801 m_shared_contexts[i]->makeCurrent();
802
803 /* Make sure that program pipeline will be used */
804 gl.useProgram(0);
805 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
806
807 prepareProgramPipeline(m_program_pipelines[i], programs);
808 }
809 }
810
811 /* Execute test */
812 bool result = true;
813 for (GLuint i = 0; i < n_test_cases; ++i)
814 {
815 if (false == testCase(test_cases[i]))
816 {
817 result = false;
818 break;
819 }
820 }
821
822 return result;
823 }
824
825 /** Set up subroutine uniforms for current program or pipeline
826 *
827 * @param set Set of subroutine indices
828 **/
updateCurrentSubroutineSet(const subroutineUniformSet & set)829 void UniformPreservationTest::updateCurrentSubroutineSet(const subroutineUniformSet &set)
830 {
831 /* GL entry points */
832 const glw::Functions &gl = m_base_context->getRenderContext().getFunctions();
833
834 /* Fragment */
835 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1 /* count */, &set.m_fragment_shader_stage);
836 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
837
838 /* Geometry */
839 gl.uniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1 /* count */, &set.m_geometry_shader_stage);
840 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
841
842 /* Tess ctrl */
843 gl.uniformSubroutinesuiv(GL_TESS_CONTROL_SHADER, 1 /* count */, &set.m_tesselation_control_shader_stage);
844 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
845
846 /* Tess eval */
847 gl.uniformSubroutinesuiv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &set.m_tesselation_evaluation_shader_stage);
848 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
849
850 /* Vertex */
851 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, &set.m_vertex_shader_stage);
852 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
853 }
854
855 /** Constructor.
856 *
857 * @param context Rendering context.
858 **/
MultipleContextsTests(tcu::TestContext & testCtx,glu::ApiType apiType)859 MultipleContextsTests::MultipleContextsTests(tcu::TestContext &testCtx, glu::ApiType apiType)
860 : tcu::TestCaseGroup(testCtx, "multiple_contexts", "Verifies \"shader_subroutine\" functionality")
861 , m_apiType(apiType)
862 {
863 /* Left blank on purpose */
864 }
865
866 /** Initializes a texture_storage_multisample test group.
867 *
868 **/
init(void)869 void MultipleContextsTests::init(void)
870 {
871 addChild(new UniformPreservationTest(m_testCtx, m_apiType));
872 }
873
874 } // namespace glcts
875