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     const unsigned int n_interfaces = sizeof(interfaces) / sizeof(interfaces[0]);
336 
337     for (unsigned int n_interface = 0; n_interface < n_interfaces; ++n_interface)
338     {
339         glw::GLenum interface = interfaces[n_interface];
340 
341         if ((interface == GL_SHADER_STORAGE_BLOCK || interface == GL_BUFFER_VARIABLE) &&
342             !m_is_shader_storage_blocks_supported)
343         {
344             continue;
345         }
346 
347         if (interface == GL_ATOMIC_COUNTER_BUFFER && !m_is_atomic_counters_supported)
348         {
349             continue;
350         }
351 
352         /* For each interface, we want to check whether a specific resource
353          * is recognized by the implementation. If the name is unknown,
354          * the test should fail; if it's recognized, we should verify it's referenced
355          * by both TC and TE shaders
356          */
357         const char *tc_resource_name = DE_NULL;
358         const char *te_resource_name = DE_NULL;
359 
360         switch (interface)
361         {
362         case GL_UNIFORM:
363         {
364             tc_resource_name = "tc_uniform1";
365             te_resource_name = "te_uniform1";
366 
367             break;
368         }
369 
370         case GL_UNIFORM_BLOCK:
371         {
372             tc_resource_name = "tc_uniform_block1";
373             te_resource_name = "te_uniform_block1";
374 
375             break;
376         }
377 
378         case GL_ATOMIC_COUNTER_BUFFER:
379         {
380             /* Atomic counter buffers are tested in a separate codepath. */
381             break;
382         }
383 
384         case GL_SHADER_STORAGE_BLOCK:
385         {
386             tc_resource_name = "tc_shader_storage_block1";
387             te_resource_name = "te_shader_storage_block1";
388 
389             break;
390         }
391 
392         case GL_BUFFER_VARIABLE:
393         {
394             tc_resource_name = "tc_shader_storage_buffer_object_1";
395             te_resource_name = "te_shader_storage_buffer_object_1";
396 
397             break;
398         }
399 
400         case GL_PROGRAM_INPUT:
401         {
402             tc_resource_name = DE_NULL;
403             te_resource_name = DE_NULL;
404 
405             break;
406         }
407 
408         case GL_PROGRAM_OUTPUT:
409         {
410             tc_resource_name = DE_NULL;
411             te_resource_name = DE_NULL;
412 
413             break;
414         }
415 
416         default:
417         {
418             TCU_FAIL("Unrecognized interface type");
419         }
420         } /* switch (interface) */
421 
422         /* Run in two iterations - first for TC, then for TE */
423         for (int n_iteration = 0; n_iteration < 2; ++n_iteration)
424         {
425             glw::GLenum property = (n_iteration == 0) ? m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER :
426                                                         m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER;
427 
428             if (interface == GL_ATOMIC_COUNTER_BUFFER)
429             {
430                 /* We only need a single iteration run for this interface */
431                 if (n_iteration == 1)
432                 {
433                     continue;
434                 }
435 
436                 /* Atomic counter buffers are not assigned names, hence they need to be
437                  * tested slightly differently.
438                  *
439                  * Exactly two atomic counter buffers should be defined. Make sure that's the case.
440                  */
441                 glw::GLint n_active_resources = 0;
442 
443                 gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources);
444                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed.");
445 
446                 if (n_active_resources != 2)
447                 {
448                     TCU_FAIL("Invalid amount of atomic counter buffer binding points reported");
449                 }
450 
451                 /* Check both resources and make sure they report separate atomic counters */
452                 bool was_tc_atomic_counter_buffer_reported = false;
453                 bool was_te_atomic_counter_buffer_reported = false;
454 
455                 for (int n_resource = 0; n_resource < n_active_resources; ++n_resource)
456                 {
457                     const glw::GLenum tc_property = m_glExtTokens.REFERENCED_BY_TESS_CONTROL_SHADER;
458                     glw::GLint tc_property_value  = 0;
459                     const glw::GLenum te_property = m_glExtTokens.REFERENCED_BY_TESS_EVALUATION_SHADER;
460                     glw::GLint te_property_value  = 0;
461 
462                     gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */
463                                             &tc_property, 1,                   /* bufSize */
464                                             NULL,                              /* length */
465                                             &tc_property_value);
466                     GLU_EXPECT_NO_ERROR(
467                         gl.getError(),
468                         "glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT property");
469 
470                     gl.getProgramResourceiv(m_po_id, interface, n_resource, 1, /* propCount */
471                                             &te_property, 1,                   /* bufSize */
472                                             NULL,                              /* length */
473                                             &te_property_value);
474                     GLU_EXPECT_NO_ERROR(
475                         gl.getError(),
476                         "glGetProgramResourceiv() failed for GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT property");
477 
478                     if (tc_property_value == GL_TRUE)
479                     {
480                         if (was_tc_atomic_counter_buffer_reported)
481                         {
482                             TCU_FAIL("Tessellation control-specific atomic counter buffer is reported twice");
483                         }
484 
485                         was_tc_atomic_counter_buffer_reported = true;
486                     }
487 
488                     if (te_property_value == GL_TRUE)
489                     {
490                         if (was_te_atomic_counter_buffer_reported)
491                         {
492                             TCU_FAIL("Tessellation evaluation-specific atomic counter buffer is reported twice");
493                         }
494 
495                         was_te_atomic_counter_buffer_reported = true;
496                     }
497                 } /* for (all active resources) */
498 
499                 if (!was_tc_atomic_counter_buffer_reported || !was_te_atomic_counter_buffer_reported)
500                 {
501                     TCU_FAIL("Either tessellation control or tessellation evaluation atomic counter buffer was not "
502                              "reported");
503                 }
504             }
505             else
506             {
507                 /* Retrieve resource index first, as long as the name is not NULL.
508                  * If it's NULL, the property's value is assumed to be GL_FALSE for
509                  * all reported active resources.
510                  **/
511                 const char *resource_name = (n_iteration == 0) ? tc_resource_name : te_resource_name;
512 
513                 if (resource_name == DE_NULL)
514                 {
515                     /* Make sure the property has GL_FALSE value for any resources
516                      * reported for this interface. */
517                     glw::GLint n_active_resources = 0;
518 
519                     gl.getProgramInterfaceiv(m_po_id, interface, GL_ACTIVE_RESOURCES, &n_active_resources);
520                     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() failed.");
521 
522                     for (glw::GLint n_resource = 0; n_resource < n_active_resources; ++n_resource)
523                     {
524                         verifyPropertyValue(interface, property, n_resource, GL_FALSE);
525                     } /* for (all resource indices) */
526                 }
527                 else
528                 {
529                     glw::GLuint resource_index = gl.getProgramResourceIndex(m_po_id, interface, resource_name);
530                     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceIndex() failed");
531 
532                     if (resource_index == GL_INVALID_INDEX)
533                     {
534                         m_testCtx.getLog() << tcu::TestLog::Message << "Resource [" << resource_name
535                                            << "] was not recognized." << tcu::TestLog::EndMessage;
536 
537                         TCU_FAIL("Resource not recognized.");
538                     }
539 
540                     /* Now that we know the index, we can check the GL_REFERENCED_BY_...
541                      * property value */
542                     verifyPropertyValue(interface, property, resource_index, GL_TRUE);
543                 }
544             } /* (interface != GL_ATOMIC_COUNTER_BUFFER) */
545         }     /* for (both iterations) */
546     }         /* for (all interfaces) */
547 
548     /* All done */
549     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
550     return STOP;
551 }
552 
553 /** Checks if a property value reported for user-specified program object interface
554  *  at given index is as expected.
555  *
556  *  NOTE: This function throws TestError exception if retrieved value does not
557  *        match @param expected_value.
558  *
559  *  @param interface      Program object interface to use for the query;
560  *  @param property       Interface property to check;
561  *  @param index          Property index to use for the test;
562  *  @param expected_value Value that is expected to be reported by ES implementation.
563  **/
verifyPropertyValue(glw::GLenum interface,glw::GLenum property,glw::GLuint index,glw::GLint expected_value)564 void TessellationShaderProgramInterfaces::verifyPropertyValue(glw::GLenum interface, glw::GLenum property,
565                                                               glw::GLuint index, glw::GLint expected_value)
566 {
567     const glw::Functions &gl  = m_context.getRenderContext().getFunctions();
568     glw::GLint property_value = 0;
569 
570     gl.getProgramResourceiv(m_po_id, interface, index, 1, /* propCount */
571                             &property, 1,                 /* bufSize */
572                             NULL,                         /* length */
573                             &property_value);
574     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv() failed");
575 
576     if (property_value != expected_value)
577     {
578         TCU_FAIL("Invalid GL_REFERENCED_BY_... property value reported");
579     }
580 }
581 
582 } /* namespace glcts */
583