1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24 #include "esextcTessellationShaderProgramInterfaces.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30
31 namespace glcts
32 {
33 /** Constructor
34 *
35 * @param context Test context
36 * @param name Test case's name
37 * @param description Test case's desricption
38 **/
TessellationShaderProgramInterfaces(Context & context,const ExtParameters & extParams)39 TessellationShaderProgramInterfaces::TessellationShaderProgramInterfaces(Context& context,
40 const ExtParameters& extParams)
41 : TestCaseBase(context, extParams, "ext_program_interface_query_dependency",
42 "Verifies EXT_program_interface_query works correctly for tessellation"
43 " control and tessellation evaluation shaders")
44 , m_fs_shader_id(0)
45 , m_po_id(0)
46 , m_tc_shader_id(0)
47 , m_te_shader_id(0)
48 , m_vs_shader_id(0)
49 , m_is_atomic_counters_supported(false)
50 , m_is_shader_storage_blocks_supported(false)
51 {
52 /* Left blank on purpose */
53 }
54
55 /** Deinitializes all ES objects created for the test. */
deinit()56 void TessellationShaderProgramInterfaces::deinit()
57 {
58 /** Call base class' deinit() function */
59 TestCaseBase::deinit();
60
61 /* Release all objects we might've created */
62 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
63
64 if (m_fs_shader_id != 0)
65 {
66 gl.deleteShader(m_fs_shader_id);
67
68 m_fs_shader_id = 0;
69 }
70
71 if (m_po_id != 0)
72 {
73 gl.deleteProgram(m_po_id);
74
75 m_po_id = 0;
76 }
77
78 if (m_tc_shader_id != 0)
79 {
80 gl.deleteShader(m_tc_shader_id);
81
82 m_tc_shader_id = 0;
83 }
84
85 if (m_te_shader_id != 0)
86 {
87 gl.deleteShader(m_te_shader_id);
88
89 m_te_shader_id = 0;
90 }
91
92 if (m_vs_shader_id != 0)
93 {
94 gl.deleteShader(m_vs_shader_id);
95
96 m_vs_shader_id = 0;
97 }
98 }
99
100 /** Initializes all ES objects that will be used for the test. */
initTest()101 void TessellationShaderProgramInterfaces::initTest()
102 {
103 /* The test requires EXT_tessellation_shader and EXT_program_interfaces_query extensions */
104 if (!m_is_tessellation_shader_supported || !m_is_program_interface_query_supported)
105 {
106 return;
107 }
108
109 /* Generate a program object we will later configure */
110 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
111
112 m_po_id = gl.createProgram();
113
114 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
115
116 /* Generate shader objects the test will use */
117 m_fs_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
118 m_tc_shader_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
119 m_te_shader_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
120 m_vs_shader_id = gl.createShader(GL_VERTEX_SHADER);
121
122 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
123
124 glw::GLint gl_max_tess_control_shader_storage_blocks;
125 glw::GLint gl_max_tess_control_atomic_counter_buffers;
126 glw::GLint gl_max_tess_control_atomic_counters;
127 glw::GLint gl_max_tess_evaluation_shader_storage_blocks;
128 glw::GLint gl_max_tess_evaluation_atomic_counter_buffers;
129 glw::GLint gl_max_tess_evaluation_atomic_counters;
130
131 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, &gl_max_tess_control_atomic_counter_buffers);
132 GLU_EXPECT_NO_ERROR(gl.getError(),
133 "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT pname");
134 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_ATOMIC_COUNTERS, &gl_max_tess_control_atomic_counters);
135 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT pname");
136 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &gl_max_tess_control_shader_storage_blocks);
137 GLU_EXPECT_NO_ERROR(gl.getError(),
138 "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT pname");
139 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,
140 &gl_max_tess_evaluation_atomic_counter_buffers);
141 GLU_EXPECT_NO_ERROR(gl.getError(),
142 "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT pname");
143 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &gl_max_tess_evaluation_atomic_counters);
144 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT pname");
145 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
146 &gl_max_tess_evaluation_shader_storage_blocks);
147 GLU_EXPECT_NO_ERROR(gl.getError(),
148 "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT pname");
149
150 m_is_atomic_counters_supported =
151 (gl_max_tess_control_atomic_counter_buffers > 1) && (gl_max_tess_evaluation_atomic_counter_buffers > 1) &&
152 (gl_max_tess_control_atomic_counters > 0) && (gl_max_tess_evaluation_atomic_counters > 0);
153
154 m_is_shader_storage_blocks_supported =
155 (gl_max_tess_control_shader_storage_blocks > 0) && (gl_max_tess_evaluation_shader_storage_blocks > 0);
156
157 const char* atomic_counters_header = NULL;
158 if (m_is_atomic_counters_supported)
159 {
160 atomic_counters_header = "#define USE_ATOMIC_COUNTERS 1\n";
161 }
162 else
163 {
164 atomic_counters_header = "\n";
165 }
166
167 const char* shader_storage_blocks_header = NULL;
168 if (m_is_shader_storage_blocks_supported)
169 {
170 shader_storage_blocks_header = "#define USE_SHADER_STORAGE_BLOCKS\n";
171 }
172 else
173 {
174 shader_storage_blocks_header = "\n";
175 }
176
177 /* Build shader program */
178 const char* fs_body = "${VERSION}\n"
179 "\n"
180 "precision highp float;\n"
181 "\n"
182 "out vec4 test_output;\n"
183 "\n"
184 "void main()\n"
185 "{\n"
186 " test_output = vec4(1, 0, 0, 0);\n"
187 "}\n";
188
189 const char* tc_body = "\n"
190 "layout (vertices = 1) out;\n"
191 "\n"
192 /* Uniforms */
193 "uniform vec2 tc_uniform1;\n"
194 "uniform mat4 tc_uniform2;\n"
195 "\n"
196 /* Uniform blocks */
197 "uniform tc_uniform_block1\n"
198 "{\n"
199 " float tc_uniform_block1_1;\n"
200 "};\n"
201 /* Atomic counter buffers */
202 "#ifdef USE_ATOMIC_COUNTERS\n"
203 "layout(binding = 1, offset = 0) uniform atomic_uint tc_atomic_counter1;\n"
204 "#endif\n"
205 /* Shader storage blocks & buffer variables */
206 "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
207 "layout(std140, binding = 0) buffer tc_shader_storage_block1\n"
208 "{\n"
209 " vec4 tc_shader_storage_buffer_object_1[];\n"
210 "};\n"
211 "#endif\n"
212 /* Body */
213 "void main()\n"
214 "{\n"
215 " int test = 1;\n"
216 "\n"
217 /* Uniforms */
218 " if (tc_uniform1.x == 0.0) test = 2;\n"
219 " if (tc_uniform2[0].y == 1.0) test = 3;\n"
220 /* Uniform blocks */
221 " if (tc_uniform_block1_1 == 3.0) test = 4;\n"
222 /* Atomic counter buffers */
223 "#ifdef USE_ATOMIC_COUNTERS\n"
224 " if (atomicCounter(tc_atomic_counter1) == 1u) test = 5;\n"
225 "#endif\n"
226 /* Shader storage blocks & buffer variables */
227 "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
228 " if (tc_shader_storage_buffer_object_1[0].x == 0.0) test = 6;\n"
229 "#endif\n"
230 "\n"
231 " gl_out [gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
232 " gl_TessLevelOuter[0] = 2.0 * float(test);\n"
233 " gl_TessLevelOuter[1] = 3.0;\n"
234 "}\n";
235
236 const char* tc_code[] = { "${VERSION}\n",
237 /* Required EXT_tessellation_shader functionality */
238 "${TESSELLATION_SHADER_REQUIRE}\n", atomic_counters_header, shader_storage_blocks_header,
239 tc_body };
240
241 const char* te_body = "\n"
242 "layout (isolines, ccw, equal_spacing, point_mode) in;\n"
243 "\n"
244 /* Uniforms */
245 "uniform vec2 te_uniform1;\n"
246 "uniform mat4 te_uniform2;\n"
247 "\n"
248 /* Uniform blocks */
249 "uniform te_uniform_block1\n"
250 "{\n"
251 " float te_uniform_block1_1;\n"
252 "};\n"
253 /* Atomic counter buffers */
254 "#ifdef USE_ATOMIC_COUNTERS\n"
255 "layout(binding = 2, offset = 0) uniform atomic_uint te_atomic_counter1;\n"
256 "#endif\n"
257 /* Shader storage blocks & buffer variables */
258 "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
259 "layout(std140, binding = 0) buffer te_shader_storage_block1\n"
260 "{\n"
261 " vec4 te_shader_storage_buffer_object_1[];\n"
262 "};\n"
263 "#endif\n"
264 "void main()\n"
265 "{\n"
266 " int test = 1;\n"
267 "\n"
268 /* Uniforms */
269 " if (te_uniform1.x == 0.0) test = 2;\n"
270 " if (te_uniform2[0].y == 1.0) test = 3;\n"
271 /* Uniform blocks */
272 " if (te_uniform_block1_1 == 3.0) test = 4;\n"
273 /* Atomic counter buffers */
274 "#ifdef USE_ATOMIC_COUNTERS\n"
275 " if (atomicCounter(te_atomic_counter1) == 1u) test = 5;\n"
276 "#endif\n"
277 /* Shader storage blocks & buffer variables */
278 "#ifdef USE_SHADER_STORAGE_BLOCKS\n"
279 " if (te_shader_storage_buffer_object_1[0].x == 0.0) test = 6;\n"
280 "#endif\n"
281 "\n"
282 " gl_Position = gl_in[0].gl_Position * float(test);\n"
283 "}\n";
284
285 const char* te_code[] = { "${VERSION}\n",
286 /* Required EXT_tessellation_shader functionality */
287 "${TESSELLATION_SHADER_REQUIRE}\n", atomic_counters_header, shader_storage_blocks_header,
288 te_body };
289
290 const char* vs_body = "${VERSION}\n"
291 "\n"
292 "in vec4 test_input;\n"
293 "\n"
294 "void main()\n"
295 "{\n"
296 " gl_Position = vec4(gl_VertexID, test_input.y, 0, 1);\n"
297 "}\n";
298
299 bool link_success = buildProgram(m_po_id, m_fs_shader_id, 1, &fs_body, m_tc_shader_id, 5, tc_code, m_te_shader_id,
300 5, te_code, m_vs_shader_id, 1, &vs_body);
301
302 if (!link_success)
303 {
304 TCU_FAIL("Program compilation and linking failed");
305 }
306
307 /* We're good to execute the test! */
308 }
309
310 /** Executes the test.
311 *
312 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
313 *
314 * Note the function throws exception should an error occur!
315 *
316 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
317 **/
iterate(void)318 tcu::TestNode::IterateResult TessellationShaderProgramInterfaces::iterate(void)
319 {
320 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
321
322 /* Do not execute if required extensions are not supported. */
323 if (!m_is_tessellation_shader_supported)
324 {
325 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
326 }
327
328 /* Initialize ES objects needed to run the test */
329 initTest();
330
331 /* Iterate through all interfaces */
332 const glw::GLenum interfaces[] = {
333 GL_UNIFORM, GL_UNIFORM_BLOCK, GL_ATOMIC_COUNTER_BUFFER, GL_SHADER_STORAGE_BLOCK,
334 GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT
335 };
336 const unsigned int n_interfaces = sizeof(interfaces) / sizeof(interfaces[0]);
337
338 for (unsigned int n_interface = 0; n_interface < n_interfaces; ++n_interface)
339 {
340 glw::GLenum interface = interfaces[n_interface];
341
342 if ((interface == GL_SHADER_STORAGE_BLOCK || interface == GL_BUFFER_VARIABLE) &&
343 !m_is_shader_storage_blocks_supported)
344 {
345 continue;
346 }
347
348 if (interface == GL_ATOMIC_COUNTER_BUFFER && !m_is_atomic_counters_supported)
349 {
350 continue;
351 }
352
353 /* For each interface, we want to check whether a specific resource
354 * is recognized by the implementation. If the name is unknown,
355 * the test should fail; if it's recognized, we should verify it's referenced
356 * by both TC and TE shaders
357 */
358 const char* tc_resource_name = DE_NULL;
359 const char* te_resource_name = DE_NULL;
360
361 switch (interface)
362 {
363 case GL_UNIFORM:
364 {
365 tc_resource_name = "tc_uniform1";
366 te_resource_name = "te_uniform1";
367
368 break;
369 }
370
371 case GL_UNIFORM_BLOCK:
372 {
373 tc_resource_name = "tc_uniform_block1";
374 te_resource_name = "te_uniform_block1";
375
376 break;
377 }
378
379 case GL_ATOMIC_COUNTER_BUFFER:
380 {
381 /* Atomic counter buffers are tested in a separate codepath. */
382 break;
383 }
384
385 case GL_SHADER_STORAGE_BLOCK:
386 {
387 tc_resource_name = "tc_shader_storage_block1";
388 te_resource_name = "te_shader_storage_block1";
389
390 break;
391 }
392
393 case GL_BUFFER_VARIABLE:
394 {
395 tc_resource_name = "tc_shader_storage_buffer_object_1";
396 te_resource_name = "te_shader_storage_buffer_object_1";
397
398 break;
399 }
400
401 case GL_PROGRAM_INPUT:
402 {
403 tc_resource_name = DE_NULL;
404 te_resource_name = DE_NULL;
405
406 break;
407 }
408
409 case GL_PROGRAM_OUTPUT:
410 {
411 tc_resource_name = DE_NULL;
412 te_resource_name = DE_NULL;
413
414 break;
415 }
416
417 default:
418 {
419 TCU_FAIL("Unrecognized interface type");
420 }
421 } /* switch (interface) */
422
423 /* Run in two iterations - first for TC, then for TE */
424 for (int n_iteration = 0; n_iteration < 2; ++n_iteration)
425 {
426 glw::GLenum property = (n_iteration == 0) ? m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER :
427 m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER;
428
429 if (interface == GL_ATOMIC_COUNTER_BUFFER)
430 {
431 /* We only need a single iteration run for this interface */
432 if (n_iteration == 1)
433 {
434 continue;
435 }
436
437 /* Atomic counter buffers are not assigned names, hence they need to be
438 * tested slightly differently.
439 *
440 * Exactly two atomic counter buffers should be defined. Make sure that's the case.
441 */
442 glw::GLint n_active_resources = 0;
443
444 gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources);
445 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed.");
446
447 if (n_active_resources != 2)
448 {
449 TCU_FAIL("Invalid amount of atomic counter buffer binding points reported");
450 }
451
452 /* Check both resources and make sure they report separate atomic counters */
453 bool was_tc_atomic_counter_buffer_reported = false;
454 bool was_te_atomic_counter_buffer_reported = false;
455
456 for (int n_resource = 0; n_resource < n_active_resources; ++n_resource)
457 {
458 const glw::GLenum tc_property = m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER;
459 glw::GLint tc_property_value = 0;
460 const glw::GLenum te_property = m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER;
461 glw::GLint te_property_value = 0;
462
463 gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */
464 &tc_property, 1, /* bufSize */
465 NULL, /* length */
466 &tc_property_value);
467 GLU_EXPECT_NO_ERROR(
468 gl.getError(),
469 "glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT property");
470
471 gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */
472 &te_property, 1, /* bufSize */
473 NULL, /* length */
474 &te_property_value);
475 GLU_EXPECT_NO_ERROR(
476 gl.getError(),
477 "glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT property");
478
479 if (tc_property_value == GL_TRUE)
480 {
481 if (was_tc_atomic_counter_buffer_reported)
482 {
483 TCU_FAIL("Tessellation control-specific atomic counter buffer is reported twice");
484 }
485
486 was_tc_atomic_counter_buffer_reported = true;
487 }
488
489 if (te_property_value == GL_TRUE)
490 {
491 if (was_te_atomic_counter_buffer_reported)
492 {
493 TCU_FAIL("Tessellation evaluation-specific atomic counter buffer is reported twice");
494 }
495
496 was_te_atomic_counter_buffer_reported = true;
497 }
498 } /* for (all active resources) */
499
500 if (!was_tc_atomic_counter_buffer_reported || !was_te_atomic_counter_buffer_reported)
501 {
502 TCU_FAIL("Either tessellation control or tessellation evaluation atomic counter buffer was not "
503 "reported");
504 }
505 }
506 else
507 {
508 /* Retrieve resource index first, as long as the name is not NULL.
509 * If it's NULL, the property's value is assumed to be GL_FALSE for
510 * all reported active resources.
511 **/
512 const char* resource_name = (n_iteration == 0) ? tc_resource_name : te_resource_name;
513
514 if (resource_name == DE_NULL)
515 {
516 /* Make sure the property has GL_FALSE value for any resources
517 * reported for this interface. */
518 glw::GLint n_active_resources = 0;
519
520 gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources);
521 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed.");
522
523 for (glw::GLint n_resource = 0; n_resource < n_active_resources; ++n_resource)
524 {
525 verifyPropertyValue(interface, property, n_resource, GL_FALSE);
526 } /* for (all resource indices) */
527 }
528 else
529 {
530 glw::GLuint resource_index = gl.getProgramResourceIndex(m_po_id, interface, resource_name);
531 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceIndex() failed");
532
533 if (resource_index == GL_INVALID_INDEX)
534 {
535 m_testCtx.getLog() << tcu::TestLog::Message << "Resource [" << resource_name
536 << "] was not recognized." << tcu::TestLog::EndMessage;
537
538 TCU_FAIL("Resource not recognized.");
539 }
540
541 /* Now that we know the index, we can check the GL_REFERENCED_BY_...
542 * property value */
543 verifyPropertyValue(interface, property, resource_index, GL_TRUE);
544 }
545 } /* (interface != GL_ATOMIC_COUNTER_BUFFER) */
546 } /* for (both iterations) */
547 } /* for (all interfaces) */
548
549 /* All done */
550 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
551 return STOP;
552 }
553
554 /** Checks if a property value reported for user-specified program object interface
555 * at given index is as expected.
556 *
557 * NOTE: This function throws TestError exception if retrieved value does not
558 * match @param expected_value.
559 *
560 * @param interface Program object interface to use for the query;
561 * @param property Interface property to check;
562 * @param index Property index to use for the test;
563 * @param expected_value Value that is expected to be reported by ES implementation.
564 **/
verifyPropertyValue(glw::GLenum interface,glw::GLenum property,glw::GLuint index,glw::GLint expected_value)565 void TessellationShaderProgramInterfaces::verifyPropertyValue(glw::GLenum interface, glw::GLenum property,
566 glw::GLuint index, glw::GLint expected_value)
567 {
568 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
569 glw::GLint property_value = 0;
570
571 gl.getProgramResourceiv(m_po_id, interface, index, 1, /* propCount */
572 &property, 1, /* bufSize */
573 NULL, /* length */
574 &property_value);
575 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv() failed");
576
577 if (property_value != expected_value)
578 {
579 TCU_FAIL("Invalid GL_REFERENCED_BY_... property value reported");
580 }
581 }
582
583 } /* namespace glcts */
584