• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 },
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  **/
captureCurrentSubroutineSet(subroutineUniformSet & set)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  **/
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)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  **/
initSharedContexts()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  **/
prepareProgram(Utils::program ** programs,bool is_separable)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  **/
prepareProgramPipeline(glw::GLuint & out_pipeline_id,Utils::program ** programs)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  **/
testCase(const glw::GLuint bit_field[5])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  **/
testProgram(Utils::program ** programs,bool is_separable,const glw::GLuint test_cases[][5],glw::GLuint n_test_cases)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  **/
updateCurrentSubroutineSet(const subroutineUniformSet & set)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  **/
MultipleContextsTests(tcu::TestContext & testCtx,glu::ApiType apiType)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  **/
init(void)870 void MultipleContextsTests::init(void)
871 {
872 	addChild(new UniformPreservationTest(m_testCtx, m_apiType));
873 }
874 
875 } /* glcts namespace */
876