• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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