Merge remote-tracking branch 'khronos/vulkan-cts-1.0.2' into HEAD am: d502cf9784
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fProgramInterfaceQueryTestCase.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
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 Program interface query test case
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fProgramInterfaceQueryTestCase.hpp"
25 #include "es31fProgramInterfaceDefinitionUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "gluVarTypeUtil.hpp"
28 #include "gluStrUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "glwFunctions.hpp"
32 #include "glwEnums.hpp"
33 #include "deString.h"
34 #include "deStringUtil.hpp"
35 #include "deSTLUtil.hpp"
36
37 namespace deqp
38 {
39 namespace gles31
40 {
41 namespace Functional
42 {
43 namespace
44 {
45
46 using ProgramInterfaceDefinition::VariablePathComponent;
47 using ProgramInterfaceDefinition::VariableSearchFilter;
48
49 static glw::GLenum getProgramDefaultBlockInterfaceFromStorage (glu::Storage storage)
50 {
51         switch (storage)
52         {
53                 case glu::STORAGE_IN:
54                 case glu::STORAGE_PATCH_IN:
55                         return GL_PROGRAM_INPUT;
56
57                 case glu::STORAGE_OUT:
58                 case glu::STORAGE_PATCH_OUT:
59                         return GL_PROGRAM_OUTPUT;
60
61                 case glu::STORAGE_UNIFORM:
62                         return GL_UNIFORM;
63
64                 default:
65                         DE_ASSERT(false);
66                         return 0;
67         }
68 }
69
70 static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage)
71 {
72         return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM;
73 }
74
75 const char* getRequiredExtensionForStage (glu::ShaderType stage)
76 {
77         switch (stage)
78         {
79                 case glu::SHADERTYPE_COMPUTE:
80                 case glu::SHADERTYPE_VERTEX:
81                 case glu::SHADERTYPE_FRAGMENT:
82                         return DE_NULL;
83
84                 case glu::SHADERTYPE_GEOMETRY:
85                         return "GL_EXT_geometry_shader";
86
87                 case glu::SHADERTYPE_TESSELLATION_CONTROL:
88                 case glu::SHADERTYPE_TESSELLATION_EVALUATION:
89                         return "GL_EXT_tessellation_shader";
90
91                 default:
92                         DE_ASSERT(false);
93                         return DE_NULL;
94         }
95 }
96
97 static int getTypeSize (glu::DataType type)
98 {
99         if (type == glu::TYPE_FLOAT)
100                 return 4;
101         else if (type == glu::TYPE_INT || type == glu::TYPE_UINT)
102                 return 4;
103         else if (type == glu::TYPE_BOOL)
104                 return 4; // uint
105
106         DE_ASSERT(false);
107         return 0;
108 }
109
110 static int getVarTypeSize (const glu::VarType& type)
111 {
112         if (type.isBasicType())
113         {
114                 // return in basic machine units
115                 return glu::getDataTypeScalarSize(type.getBasicType()) * getTypeSize(glu::getDataTypeScalarType(type.getBasicType()));
116         }
117         else if (type.isStructType())
118         {
119                 int size = 0;
120                 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
121                         size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType());
122                 return size;
123         }
124         else if (type.isArrayType())
125         {
126                 // unsized arrays are handled as if they had only one element
127                 if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY)
128                         return getVarTypeSize(type.getElementType());
129                 else
130                         return type.getArraySize() * getVarTypeSize(type.getElementType());
131         }
132         else
133         {
134                 DE_ASSERT(false);
135                 return 0;
136         }
137 }
138
139 static glu::MatrixOrder getMatrixOrderFromPath (const std::vector<VariablePathComponent>& path)
140 {
141         glu::MatrixOrder order = glu::MATRIXORDER_LAST;
142
143         // inherit majority
144         for (int pathNdx = 0; pathNdx < (int)path.size(); ++pathNdx)
145         {
146                 glu::MatrixOrder matOrder;
147
148                 if (path[pathNdx].isInterfaceBlock())
149                         matOrder = path[pathNdx].getInterfaceBlock()->layout.matrixOrder;
150                 else if (path[pathNdx].isDeclaration())
151                         matOrder = path[pathNdx].getDeclaration()->layout.matrixOrder;
152                 else if (path[pathNdx].isVariableType())
153                         matOrder = glu::MATRIXORDER_LAST;
154                 else
155                 {
156                         DE_ASSERT(false);
157                         return glu::MATRIXORDER_LAST;
158                 }
159
160                 if (matOrder != glu::MATRIXORDER_LAST)
161                         order = matOrder;
162         }
163
164         return order;
165 }
166
167 class PropValidator
168 {
169 public:
170                                                                         PropValidator                                   (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension);
171
172         virtual std::string                             getHumanReadablePropertyString  (glw::GLint propVal) const;
173         virtual void                                    validate                                                (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
174
175         bool                                                    isSupported                                             (void) const;
176         bool                                                    isSelected                                              (deUint32 caseFlags) const;
177
178 protected:
179         void                                                    setError                                                (const std::string& err) const;
180
181         tcu::TestContext&                               m_testCtx;
182         const glu::RenderContext&               m_renderContext;
183
184 private:
185         const glu::ContextInfo&                 m_contextInfo;
186         const char*                                             m_extension;
187         const ProgramResourcePropFlags  m_validationProp;
188 };
189
190 PropValidator::PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension)
191         : m_testCtx                     (context.getTestContext())
192         , m_renderContext       (context.getRenderContext())
193         , m_contextInfo         (context.getContextInfo())
194         , m_extension           (requiredExtension)
195         , m_validationProp      (validationProp)
196 {
197 }
198
199 std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const
200 {
201         return de::toString(propVal);
202 }
203
204 bool PropValidator::isSupported (void) const
205 {
206         if(glu::contextSupports(m_renderContext.getType(), glu::ApiType::es(3, 2)))
207                 return true;
208         return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension);
209 }
210
211 bool PropValidator::isSelected (deUint32 caseFlags) const
212 {
213         return (caseFlags & (deUint32)m_validationProp) != 0;
214 }
215
216 void PropValidator::setError (const std::string& err) const
217 {
218         // don't overwrite earlier errors
219         if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
220                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, err.c_str());
221 }
222
223 class SingleVariableValidator : public PropValidator
224 {
225 public:
226                                         SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
227
228         void                    validate                                (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
229         virtual void    validateSingleVariable  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
230         virtual void    validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
231
232 protected:
233         const VariableSearchFilter      m_filter;
234         const glw::GLuint                       m_programID;
235 };
236
237 SingleVariableValidator::SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
238         : PropValidator (context, validationProp, requiredExtension)
239         , m_filter              (filter)
240         , m_programID   (programID)
241 {
242 }
243
244 void SingleVariableValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
245 {
246         std::vector<VariablePathComponent> path;
247
248         if (findProgramVariablePathByPathName(path, program, resource, m_filter))
249         {
250                 const glu::VarType* variable = (path.back().isVariableType()) ? (path.back().getVariableType()) : (DE_NULL);
251
252                 if (!variable || !variable->isBasicType())
253                 {
254                         m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource name \"" << resource << "\" refers to a non-basic type." << tcu::TestLog::EndMessage;
255                         setError("resource not basic type");
256                 }
257                 else
258                         validateSingleVariable(path, resource, propValue, implementationName);
259
260                 // finding matching variable in any shader is sufficient
261                 return;
262         }
263         else if (deStringBeginsWith(resource.c_str(), "gl_"))
264         {
265                 // special case for builtins
266                 validateBuiltinVariable(resource, propValue, implementationName);
267                 return;
268         }
269
270         // we are only supplied good names, generated by ourselves
271         DE_ASSERT(false);
272         throw tcu::InternalError("Resource name consistency error");
273 }
274
275 void SingleVariableValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
276 {
277         DE_UNREF(resource);
278         DE_UNREF(propValue);
279         DE_UNREF(implementationName);
280         DE_ASSERT(false);
281 }
282
283 class SingleBlockValidator : public PropValidator
284 {
285 public:
286                                                                 SingleBlockValidator    (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
287
288         void                                            validate                                (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
289         virtual void                            validateSingleBlock             (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
290
291 protected:
292         const VariableSearchFilter      m_filter;
293         const glw::GLuint                       m_programID;
294 };
295
296 SingleBlockValidator::SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
297         : PropValidator (context, validationProp, requiredExtension)
298         , m_filter              (filter)
299         , m_programID   (programID)
300 {
301 }
302
303 void SingleBlockValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
304 {
305         glu::VarTokenizer       tokenizer               (resource.c_str());
306         const std::string       blockName               = tokenizer.getIdentifier();
307         std::vector<int>        instanceIndex;
308
309         tokenizer.advance();
310
311         // array index
312         while (tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
313         {
314                 tokenizer.advance();
315                 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_NUMBER);
316
317                 instanceIndex.push_back(tokenizer.getNumber());
318
319                 tokenizer.advance();
320                 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_RIGHT_BRACKET);
321
322                 tokenizer.advance();
323         }
324
325         // no trailing garbage
326         DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_END);
327
328         for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
329         {
330                 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
331                 if (!m_filter.matchesFilter(shader))
332                         continue;
333
334                 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
335                 {
336                         const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
337
338                         if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
339                         {
340                                 // dimensions match
341                                 DE_ASSERT(instanceIndex.size() == block.dimensions.size());
342
343                                 validateSingleBlock(block, instanceIndex, resource, propValue, implementationName);
344                                 return;
345                         }
346                 }
347         }
348
349         // we are only supplied good names, generated by ourselves
350         DE_ASSERT(false);
351         throw tcu::InternalError("Resource name consistency error");
352 }
353
354 class TypeValidator : public SingleVariableValidator
355 {
356 public:
357                                 TypeValidator                                   (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
358
359         std::string     getHumanReadablePropertyString  (glw::GLint propVal) const;
360         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
361         void            validateBuiltinVariable                 (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
362 };
363
364 TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
365         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL)
366 {
367 }
368
369 std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const
370 {
371         return de::toString(glu::getShaderVarTypeStr(propVal));
372 }
373
374 void TypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
375 {
376         const glu::VarType* variable = path.back().getVariableType();
377
378         DE_UNREF(resource);
379         DE_UNREF(implementationName);
380
381         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(variable->getBasicType()) << tcu::TestLog::EndMessage;
382
383         if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue))
384         {
385                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
386                 setError("resource type invalid");
387         }
388 }
389
390 void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
391 {
392         DE_UNREF(implementationName);
393
394         static const struct
395         {
396                 const char*             name;
397                 glu::DataType   type;
398         } builtins[] =
399         {
400                 { "gl_Position",                                glu::TYPE_FLOAT_VEC4    },
401                 { "gl_FragCoord",                               glu::TYPE_FLOAT_VEC4    },
402                 { "gl_PerVertex.gl_Position",   glu::TYPE_FLOAT_VEC4    },
403                 { "gl_VertexID",                                glu::TYPE_INT                   },
404                 { "gl_InvocationID",                    glu::TYPE_INT                   },
405                 { "gl_NumWorkGroups",                   glu::TYPE_UINT_VEC3             },
406                 { "gl_FragDepth",                               glu::TYPE_FLOAT                 },
407                 { "gl_TessLevelOuter[0]",               glu::TYPE_FLOAT                 },
408                 { "gl_TessLevelInner[0]",               glu::TYPE_FLOAT                 },
409         };
410
411         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
412         {
413                 if (resource == builtins[ndx].name)
414                 {
415                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(builtins[ndx].type) << tcu::TestLog::EndMessage;
416
417                         if (glu::getDataTypeFromGLType(propValue) != builtins[ndx].type)
418                         {
419                                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
420                                 setError("resource type invalid");
421                         }
422                         return;
423                 }
424         }
425
426         DE_ASSERT(false);
427 }
428
429 class ArraySizeValidator : public SingleVariableValidator
430 {
431 public:
432                                 ArraySizeValidator                              (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter);
433
434         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
435         void            validateBuiltinVariable                 (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
436
437 private:
438         const int       m_unsizedArraySize;
439 };
440
441 ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter)
442         : SingleVariableValidator       (context, PROGRAMRESOURCEPROP_ARRAY_SIZE, programID, filter, DE_NULL)
443         , m_unsizedArraySize            (unsizedArraySize)
444 {
445 }
446
447 void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
448 {
449         const VariablePathComponent             nullComponent;
450         const VariablePathComponent&    enclosingcomponent      = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
451
452         const bool                                              isArray                         = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
453         const bool                                              inUnsizedArray          = isArray && (enclosingcomponent.getVariableType()->getArraySize() == glu::VarType::UNSIZED_ARRAY);
454         const int                                               arraySize                       = (!isArray) ? (1) : (inUnsizedArray) ? (m_unsizedArraySize) : (enclosingcomponent.getVariableType()->getArraySize());
455
456         DE_ASSERT(arraySize >= 0);
457         DE_UNREF(resource);
458         DE_UNREF(implementationName);
459
460         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
461
462         if (arraySize != propValue)
463         {
464                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
465                 setError("resource array size invalid");
466         }
467 }
468
469 void ArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
470 {
471         DE_UNREF(implementationName);
472
473         static const struct
474         {
475                 const char*             name;
476                 int                             arraySize;
477         } builtins[] =
478         {
479                 { "gl_Position",                                1       },
480                 { "gl_VertexID",                                1       },
481                 { "gl_FragCoord",                               1       },
482                 { "gl_PerVertex.gl_Position",   1       },
483                 { "gl_InvocationID",                    1       },
484                 { "gl_NumWorkGroups",                   1       },
485                 { "gl_FragDepth",                               1       },
486                 { "gl_TessLevelOuter[0]",               4       },
487                 { "gl_TessLevelInner[0]",               2       },
488         };
489
490         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
491         {
492                 if (resource == builtins[ndx].name)
493                 {
494                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << builtins[ndx].arraySize << tcu::TestLog::EndMessage;
495
496                         if (propValue != builtins[ndx].arraySize)
497                         {
498                                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
499                                 setError("resource array size invalid");
500                         }
501                         return;
502                 }
503         }
504
505         DE_ASSERT(false);
506 }
507
508 class ArrayStrideValidator : public SingleVariableValidator
509 {
510 public:
511                                 ArrayStrideValidator                    (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
512
513         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
514 };
515
516 ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
517         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL)
518 {
519 }
520
521 void ArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
522 {
523         const VariablePathComponent             nullComponent;
524         const VariablePathComponent&    component                       = path.back();
525         const VariablePathComponent&    enclosingcomponent      = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
526         const VariablePathComponent&    firstComponent          = path.front();
527
528         const bool                                              isBufferBlock           = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
529         const bool                                              isArray                         = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
530         const bool                                              isAtomicCounter         = glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType()); // atomic counters are buffer backed with a stride of 4 basic machine units
531
532         DE_UNREF(resource);
533         DE_UNREF(implementationName);
534
535         // Layout tests will verify layouts of buffer backed arrays properly. Here we just check values are greater or equal to the element size
536         if (isBufferBlock && isArray)
537         {
538                 const int elementSize = glu::getDataTypeScalarSize(component.getVariableType()->getBasicType()) * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
539                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting greater or equal to " << elementSize << tcu::TestLog::EndMessage;
540
541                 if (propValue < elementSize)
542                 {
543                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
544                         setError("resource array stride invalid");
545                 }
546         }
547         else
548         {
549                 // Atomics are buffer backed with stride of 4 even though they are not in an interface block
550                 const int arrayStride = (isAtomicCounter && isArray) ? (4) : (!isBufferBlock && !isAtomicCounter) ? (-1) : (0);
551
552                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting " << arrayStride << tcu::TestLog::EndMessage;
553
554                 if (arrayStride != propValue)
555                 {
556                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
557                         setError("resource array stride invalid");
558                 }
559         }
560 }
561
562 class BlockIndexValidator : public SingleVariableValidator
563 {
564 public:
565                                 BlockIndexValidator                             (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
566
567         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
568 };
569
570 BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
571         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL)
572 {
573 }
574
575 void BlockIndexValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
576 {
577         const VariablePathComponent& firstComponent = path.front();
578
579         DE_UNREF(resource);
580         DE_UNREF(implementationName);
581
582         if (!firstComponent.isInterfaceBlock())
583         {
584                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting -1" << tcu::TestLog::EndMessage;
585
586                 if (propValue != -1)
587                 {
588                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
589                         setError("resource block index invalid");
590                 }
591         }
592         else
593         {
594                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting a valid block index" << tcu::TestLog::EndMessage;
595
596                 if (propValue == -1)
597                 {
598                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
599                         setError("resource block index invalid");
600                 }
601                 else
602                 {
603                         const glw::Functions&   gl                      = m_renderContext.getFunctions();
604                         const glw::GLenum               interface       = (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM_BLOCK) :
605                                                                                                   (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_BUFFER) ? (GL_SHADER_STORAGE_BLOCK) :
606                                                                                                   (0);
607                         glw::GLint                              written         = 0;
608                         std::vector<char>               nameBuffer      (firstComponent.getInterfaceBlock()->interfaceName.size() + 3 * firstComponent.getInterfaceBlock()->dimensions.size() + 2, '\0'); // +3 for appended "[N]", +1 for '\0' and +1 just for safety
609
610                         gl.getProgramResourceName(m_programID, interface, propValue, (int)nameBuffer.size() - 1, &written, &nameBuffer[0]);
611                         GLU_EXPECT_NO_ERROR(gl.getError(), "query block name");
612                         TCU_CHECK(written < (int)nameBuffer.size());
613                         TCU_CHECK(nameBuffer.back() == '\0');
614
615                         {
616                                 const std::string       blockName               (&nameBuffer[0], written);
617                                 std::ostringstream      expectedName;
618
619                                 expectedName << firstComponent.getInterfaceBlock()->interfaceName;
620                                 for (int dimensionNdx = 0; dimensionNdx < (int)firstComponent.getInterfaceBlock()->dimensions.size(); ++dimensionNdx)
621                                         expectedName << "[0]";
622
623                                 m_testCtx.getLog() << tcu::TestLog::Message << "Block name with index " << propValue << " is \"" << blockName << "\"" << tcu::TestLog::EndMessage;
624                                 if (blockName != expectedName.str())
625                                 {
626                                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, expected " << expectedName.str() << tcu::TestLog::EndMessage;
627                                         setError("resource block index invalid");
628                                 }
629                         }
630                 }
631         }
632 }
633
634 class IsRowMajorValidator : public SingleVariableValidator
635 {
636 public:
637                                 IsRowMajorValidator                             (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
638
639         std::string getHumanReadablePropertyString      (glw::GLint propVal) const;
640         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
641 };
642
643 IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
644         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL)
645 {
646 }
647
648 std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const
649 {
650         return de::toString(glu::getBooleanStr(propVal));
651 }
652
653 void IsRowMajorValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
654 {
655         const VariablePathComponent&    component                       = path.back();
656         const VariablePathComponent&    firstComponent          = path.front();
657
658         const bool                                              isBufferBlock           = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
659         const bool                                              isMatrix                        = glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
660         const int                                               expected                        = (isBufferBlock && isMatrix && getMatrixOrderFromPath(path) == glu::MATRIXORDER_ROW_MAJOR) ? (1) : (0);
661
662         DE_UNREF(resource);
663         DE_UNREF(implementationName);
664
665         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix order, expecting IS_ROW_MAJOR = " << expected << tcu::TestLog::EndMessage;
666
667         if (propValue != expected)
668         {
669                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
670                 setError("resource matrix order invalid");
671         }
672 }
673
674 class MatrixStrideValidator : public SingleVariableValidator
675 {
676 public:
677                                 MatrixStrideValidator                   (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
678
679         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
680 };
681
682 MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
683         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL)
684 {
685 }
686
687 void MatrixStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
688 {
689         const VariablePathComponent&    component                       = path.back();
690         const VariablePathComponent&    firstComponent          = path.front();
691
692         const bool                                              isBufferBlock           = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
693         const bool                                              isMatrix                        = glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
694
695         DE_UNREF(resource);
696         DE_UNREF(implementationName);
697
698         // Layout tests will verify layouts of buffer backed arrays properly. Here we just check the stride is is greater or equal to the row/column size
699         if (isBufferBlock && isMatrix)
700         {
701                 const bool      columnMajor                     = getMatrixOrderFromPath(path) != glu::MATRIXORDER_ROW_MAJOR;
702                 const int       numMajorElements        = (columnMajor) ? (glu::getDataTypeMatrixNumRows(component.getVariableType()->getBasicType())) : (glu::getDataTypeMatrixNumColumns(component.getVariableType()->getBasicType()));
703                 const int       majorSize                       = numMajorElements * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
704
705                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting greater or equal to " << majorSize << tcu::TestLog::EndMessage;
706
707                 if (propValue < majorSize)
708                 {
709                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
710                         setError("resource matrix stride invalid");
711                 }
712         }
713         else
714         {
715                 const int matrixStride = (!isBufferBlock && !glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType())) ? (-1) : (0);
716
717                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting " << matrixStride << tcu::TestLog::EndMessage;
718
719                 if (matrixStride != propValue)
720                 {
721                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
722                         setError("resource matrix stride invalid");
723                 }
724         }
725 }
726
727 class AtomicCounterBufferIndexVerifier : public SingleVariableValidator
728 {
729 public:
730                                 AtomicCounterBufferIndexVerifier        (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
731
732         void            validateSingleVariable                          (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
733 };
734
735 AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
736         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL)
737 {
738 }
739
740 void AtomicCounterBufferIndexVerifier::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
741 {
742         DE_UNREF(resource);
743         DE_UNREF(implementationName);
744
745         if (!glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()))
746         {
747                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting -1" << tcu::TestLog::EndMessage;
748
749                 if (propValue != -1)
750                 {
751                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
752                         setError("resource atomic counter buffer index invalid");
753                 }
754         }
755         else
756         {
757                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting a valid index" << tcu::TestLog::EndMessage;
758
759                 if (propValue == -1)
760                 {
761                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
762                         setError("resource atomic counter buffer index invalid");
763                 }
764                 else
765                 {
766                         const glw::Functions&   gl                                      = m_renderContext.getFunctions();
767                         glw::GLint                              numActiveResources      = 0;
768
769                         gl.getProgramInterfaceiv(m_programID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numActiveResources);
770                         GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInterfaceiv(..., GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, ...)");
771
772                         if (propValue >= numActiveResources)
773                         {
774                                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << ", GL_ACTIVE_RESOURCES = " << numActiveResources << tcu::TestLog::EndMessage;
775                                 setError("resource atomic counter buffer index invalid");
776                         }
777                 }
778         }
779 }
780
781 class LocationValidator : public SingleVariableValidator
782 {
783 public:
784                                 LocationValidator               (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
785
786         void            validateSingleVariable  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
787         void            validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
788 };
789
790 LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
791         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL)
792 {
793 }
794
795 static int getVariableLocationLength (const glu::VarType& type)
796 {
797         if (type.isBasicType())
798         {
799                 if (glu::isDataTypeMatrix(type.getBasicType()))
800                         return glu::getDataTypeMatrixNumColumns(type.getBasicType());
801                 else
802                         return 1;
803         }
804         else if (type.isStructType())
805         {
806                 int size = 0;
807                 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
808                         size += getVariableLocationLength(type.getStructPtr()->getMember(ndx).getType());
809                 return size;
810         }
811         else if (type.isArrayType())
812                 return type.getArraySize() * getVariableLocationLength(type.getElementType());
813         else
814         {
815                 DE_ASSERT(false);
816                 return 0;
817         }
818 }
819
820 static int getIOSubVariableLocation (const std::vector<VariablePathComponent>& path, int startNdx, int currentLocation)
821 {
822         if (currentLocation == -1)
823                 return -1;
824
825         if (path[startNdx].getVariableType()->isBasicType())
826                 return currentLocation;
827         else if (path[startNdx].getVariableType()->isArrayType())
828                 return getIOSubVariableLocation(path, startNdx+1, currentLocation);
829         else if (path[startNdx].getVariableType()->isStructType())
830         {
831                 for (int ndx = 0; ndx < path[startNdx].getVariableType()->getStructPtr()->getNumMembers(); ++ndx)
832                 {
833                         if (&path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType() == path[startNdx + 1].getVariableType())
834                                 return getIOSubVariableLocation(path, startNdx + 1, currentLocation);
835
836                         if (currentLocation != -1)
837                                 currentLocation += getVariableLocationLength(path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType());
838                 }
839
840                 // could not find member, never happens
841                 DE_ASSERT(false);
842                 return -1;
843         }
844         else
845         {
846                 DE_ASSERT(false);
847                 return -1;
848         }
849 }
850
851 static int getIOBlockVariableLocation (const std::vector<VariablePathComponent>& path)
852 {
853         const glu::InterfaceBlock*      block                   = path.front().getInterfaceBlock();
854         int                                                     currentLocation = block->layout.location;
855
856         // Find the block member
857         for (int memberNdx = 0; memberNdx < (int)block->variables.size(); ++memberNdx)
858         {
859                 if (block->variables[memberNdx].layout.location != -1)
860                         currentLocation = block->variables[memberNdx].layout.location;
861
862                 if (&block->variables[memberNdx] == path[1].getDeclaration())
863                         break;
864
865                 // unspecified + unspecified = unspecified
866                 if (currentLocation != -1)
867                         currentLocation += getVariableLocationLength(block->variables[memberNdx].varType);
868         }
869
870         // Find subtype location in the complex type
871         return getIOSubVariableLocation(path, 2, currentLocation);
872 }
873
874 static int getExplicitLocationFromPath (const std::vector<VariablePathComponent>& path)
875 {
876         const glu::VariableDeclaration* varDecl = (path[0].isInterfaceBlock()) ? (path[1].getDeclaration()) : (path[0].getDeclaration());
877
878         if (path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM)
879         {
880                 // inside uniform block
881                 return -1;
882         }
883         else if (path.front().isInterfaceBlock() && (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN               ||
884                                                                                                  path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT          ||
885                                                                                                  path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_IN     ||
886                                                                                                  path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_OUT))
887         {
888                 // inside ioblock
889                 return getIOBlockVariableLocation(path);
890         }
891         else if (varDecl->storage == glu::STORAGE_UNIFORM)
892         {
893                 // default block uniform
894                 return varDecl->layout.location;
895         }
896         else if (varDecl->storage == glu::STORAGE_IN            ||
897                          varDecl->storage == glu::STORAGE_OUT           ||
898                          varDecl->storage == glu::STORAGE_PATCH_IN      ||
899                          varDecl->storage == glu::STORAGE_PATCH_OUT)
900         {
901                 // default block input/output
902                 return getIOSubVariableLocation(path, 1, varDecl->layout.location);
903         }
904         else
905         {
906                 DE_ASSERT(false);
907                 return -1;
908         }
909 }
910
911 void LocationValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
912 {
913         const bool                      isAtomicCounterUniform  = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
914         const bool                      isUniformBlockVariable  = path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM;
915         const bool                      isVertexShader                  = m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_VERTEX);
916         const bool                      isFragmentShader                = m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_FRAGMENT);
917         const glu::Storage      storage                                 = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
918         const bool                      isInputVariable                 = (storage == glu::STORAGE_IN || storage == glu::STORAGE_PATCH_IN);
919         const bool                      isOutputVariable                = (storage == glu::STORAGE_OUT || storage == glu::STORAGE_PATCH_OUT);
920         const int                       explicitLayoutLocation  = getExplicitLocationFromPath(path);
921
922         bool                            expectLocation;
923         std::string                     reasonStr;
924
925         DE_UNREF(resource);
926
927         if (isAtomicCounterUniform)
928         {
929                 expectLocation = false;
930                 reasonStr = "Atomic counter uniforms have effective location of -1";
931         }
932         else if (isUniformBlockVariable)
933         {
934                 expectLocation = false;
935                 reasonStr = "Uniform block variables have effective location of -1";
936         }
937         else if (isInputVariable && !isVertexShader && explicitLayoutLocation == -1)
938         {
939                 expectLocation = false;
940                 reasonStr = "Inputs (except for vertex shader inputs) not declared with a location layout qualifier have effective location of -1";
941         }
942         else if (isOutputVariable && !isFragmentShader && explicitLayoutLocation == -1)
943         {
944                 expectLocation = false;
945                 reasonStr = "Outputs (except for fragment shader outputs) not declared with a location layout qualifier have effective location of -1";
946         }
947         else
948         {
949                 expectLocation = true;
950         }
951
952         if (!expectLocation)
953         {
954                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform location, expecting -1. (" << reasonStr << ")" << tcu::TestLog::EndMessage;
955
956                 if (propValue != -1)
957                 {
958                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
959                         setError("resource location invalid");
960                 }
961         }
962         else
963         {
964                 bool locationOk;
965
966                 if (explicitLayoutLocation == -1)
967                 {
968                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting a valid location" << tcu::TestLog::EndMessage;
969                         locationOk = (propValue != -1);
970                 }
971                 else
972                 {
973                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting " << explicitLayoutLocation << tcu::TestLog::EndMessage;
974                         locationOk = (propValue == explicitLayoutLocation);
975                 }
976
977                 if (!locationOk)
978                 {
979                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
980                         setError("resource location invalid");
981                 }
982                 else
983                 {
984                         const VariablePathComponent             nullComponent;
985                         const VariablePathComponent&    enclosingcomponent      = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
986                         const bool                                              isArray                         = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
987
988                         const glw::Functions&                   gl                                      = m_renderContext.getFunctions();
989                         const glw::GLenum                               interface                       = getProgramDefaultBlockInterfaceFromStorage(storage);
990
991                         m_testCtx.getLog() << tcu::TestLog::Message << "Comparing location to the values returned by GetProgramResourceLocation" << tcu::TestLog::EndMessage;
992
993                         // Test all bottom-level array elements
994                         if (isArray)
995                         {
996                                 const std::string arrayResourceName = (implementationName.size() > 3) ? (implementationName.substr(0, implementationName.size() - 3)) : (""); // chop "[0]"
997
998                                 for (int arrayElementNdx = 0; arrayElementNdx < enclosingcomponent.getVariableType()->getArraySize(); ++arrayElementNdx)
999                                 {
1000                                         const std::string       elementResourceName     = arrayResourceName + "[" + de::toString(arrayElementNdx) + "]";
1001                                         const glw::GLint        location                        = gl.getProgramResourceLocation(m_programID, interface, elementResourceName.c_str());
1002
1003                                         if (location != propValue+arrayElementNdx)
1004                                         {
1005                                                 m_testCtx.getLog()
1006                                                         << tcu::TestLog::Message
1007                                                         << "\tError, getProgramResourceLocation (resource=\"" << elementResourceName << "\") returned location " << location
1008                                                         << ", expected " << (propValue+arrayElementNdx)
1009                                                         << tcu::TestLog::EndMessage;
1010                                                 setError("resource location invalid");
1011                                         }
1012                                         else
1013                                                 m_testCtx.getLog() << tcu::TestLog::Message << "\tLocation of \"" << elementResourceName << "\":\t" << location << tcu::TestLog::EndMessage;
1014                                 }
1015                         }
1016                         else
1017                         {
1018                                 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, implementationName.c_str());
1019
1020                                 if (location != propValue)
1021                                 {
1022                                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, getProgramResourceLocation returned location " << location << ", expected " << propValue << tcu::TestLog::EndMessage;
1023                                         setError("resource location invalid");
1024                                 }
1025                         }
1026
1027                 }
1028         }
1029 }
1030
1031 void LocationValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1032 {
1033         DE_UNREF(resource);
1034         DE_UNREF(implementationName);
1035
1036         // built-ins have no location
1037
1038         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting -1" << tcu::TestLog::EndMessage;
1039
1040         if (propValue != -1)
1041         {
1042                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1043                 setError("resource location invalid");
1044         }
1045 }
1046
1047 class VariableNameLengthValidator : public SingleVariableValidator
1048 {
1049 public:
1050                                 VariableNameLengthValidator     (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1051
1052         void            validateSingleVariable          (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1053         void            validateBuiltinVariable         (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1054         void            validateNameLength                      (const std::string& implementationName, glw::GLint propValue) const;
1055 };
1056
1057 VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1058         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
1059 {
1060 }
1061
1062 void VariableNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1063 {
1064         DE_UNREF(path);
1065         DE_UNREF(resource);
1066         validateNameLength(implementationName, propValue);
1067 }
1068
1069 void VariableNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1070 {
1071         DE_UNREF(resource);
1072         validateNameLength(implementationName, propValue);
1073 }
1074
1075 void VariableNameLengthValidator::validateNameLength (const std::string& implementationName, glw::GLint propValue) const
1076 {
1077         const int expected = (int)implementationName.length() + 1; // includes null byte
1078         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1079
1080         if (propValue != expected)
1081         {
1082                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1083                 setError("name length invalid");
1084         }
1085 }
1086
1087 class OffsetValidator : public SingleVariableValidator
1088 {
1089 public:
1090                                 OffsetValidator                 (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1091
1092         void            validateSingleVariable  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1093 };
1094
1095 OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1096         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL)
1097 {
1098 }
1099
1100 void OffsetValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1101 {
1102         const bool isAtomicCounterUniform               = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
1103         const bool isBufferBackedBlockStorage   = path.front().isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(path.front().getInterfaceBlock()->storage);
1104
1105         DE_UNREF(resource);
1106         DE_UNREF(implementationName);
1107
1108         if (!isAtomicCounterUniform && !isBufferBackedBlockStorage)
1109         {
1110                 // Not buffer backed
1111                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting -1" << tcu::TestLog::EndMessage;
1112
1113                 if (propValue != -1)
1114                 {
1115                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1116                         setError("offset invalid");
1117                 }
1118         }
1119         else
1120         {
1121                 // Expect a valid offset
1122                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting a valid offset" << tcu::TestLog::EndMessage;
1123
1124                 if (propValue < 0)
1125                 {
1126                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1127                         setError("offset invalid");
1128                 }
1129         }
1130 }
1131
1132 class VariableReferencedByShaderValidator : public PropValidator
1133 {
1134 public:
1135                                                                 VariableReferencedByShaderValidator     (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
1136
1137         std::string                                     getHumanReadablePropertyString          (glw::GLint propVal) const;
1138         void                                            validate                                                        (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1139
1140 private:
1141         const VariableSearchFilter      m_filter;
1142         const glu::ShaderType           m_shaderType;
1143 };
1144
1145 VariableReferencedByShaderValidator::VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1146         : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1147         , m_filter              (VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1148         , m_shaderType  (shaderType)
1149 {
1150         DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
1151 }
1152
1153 std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1154 {
1155         return de::toString(glu::getBooleanStr(propVal));
1156 }
1157
1158 void VariableReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1159 {
1160         DE_UNREF(implementationName);
1161
1162         std::vector<VariablePathComponent>      dummyPath;
1163         const bool                                                      referencedByShader = findProgramVariablePathByPathName(dummyPath, program, resource, m_filter);
1164
1165         m_testCtx.getLog()
1166                 << tcu::TestLog::Message
1167                 << "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
1168                 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1169                 << tcu::TestLog::EndMessage;
1170
1171         if (propValue != ((referencedByShader) ? (1) : (0)))
1172         {
1173                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1174                 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
1175         }
1176 }
1177
1178 class BlockNameLengthValidator : public SingleBlockValidator
1179 {
1180 public:
1181                         BlockNameLengthValidator        (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1182
1183         void    validateSingleBlock                     (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1184 };
1185
1186 BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1187         : SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
1188 {
1189 }
1190
1191 void BlockNameLengthValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1192 {
1193         DE_UNREF(instanceIndex);
1194         DE_UNREF(block);
1195         DE_UNREF(resource);
1196
1197         const int expected = (int)implementationName.length() + 1; // includes null byte
1198         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1199
1200         if (propValue != expected)
1201         {
1202                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1203                 setError("name length invalid");
1204         }
1205 }
1206
1207 class BufferBindingValidator : public SingleBlockValidator
1208 {
1209 public:
1210                         BufferBindingValidator  (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1211
1212         void    validateSingleBlock             (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1213 };
1214
1215 BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1216         : SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL)
1217 {
1218 }
1219
1220 void BufferBindingValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1221 {
1222         DE_UNREF(resource);
1223         DE_UNREF(implementationName);
1224
1225         if (block.layout.binding != -1)
1226         {
1227                 int flatIndex           = 0;
1228                 int dimensionSize       = 1;
1229
1230                 for (int dimensionNdx = (int)(block.dimensions.size()) - 1; dimensionNdx >= 0; --dimensionNdx)
1231                 {
1232                         flatIndex += dimensionSize * instanceIndex[dimensionNdx];
1233                         dimensionSize *= block.dimensions[dimensionNdx];
1234                 }
1235
1236                 const int expected = (block.dimensions.empty()) ? (block.layout.binding) : (block.layout.binding + flatIndex);
1237                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block binding, expecting " << expected << tcu::TestLog::EndMessage;
1238
1239                 if (propValue != expected)
1240                 {
1241                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1242                         setError("buffer binding invalid");
1243                 }
1244         }
1245         else
1246         {
1247                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying buffer binding, expecting a valid binding" << tcu::TestLog::EndMessage;
1248
1249                 if (propValue < 0)
1250                 {
1251                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1252                         setError("buffer binding invalid");
1253                 }
1254         }
1255 }
1256
1257 class BlockReferencedByShaderValidator : public PropValidator
1258 {
1259 public:
1260                                                                 BlockReferencedByShaderValidator        (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
1261
1262         std::string                                     getHumanReadablePropertyString          (glw::GLint propVal) const;
1263         void                                            validate                                                        (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1264
1265 private:
1266         const VariableSearchFilter      m_filter;
1267         const glu::ShaderType           m_shaderType;
1268 };
1269
1270 BlockReferencedByShaderValidator::BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1271         : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1272         , m_filter              (VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1273         , m_shaderType  (shaderType)
1274 {
1275         DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
1276 }
1277
1278 std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1279 {
1280         return de::toString(glu::getBooleanStr(propVal));
1281 }
1282
1283 void BlockReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1284 {
1285         const std::string       blockName                       = glu::parseVariableName(resource.c_str());
1286         bool                            referencedByShader      = false;
1287
1288         DE_UNREF(implementationName);
1289
1290         for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1291         {
1292                 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1293                 if (!m_filter.matchesFilter(shader))
1294                         continue;
1295
1296                 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1297                 {
1298                         const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1299
1300                         if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
1301                                 referencedByShader = true;
1302                 }
1303         }
1304
1305         m_testCtx.getLog()
1306                 << tcu::TestLog::Message
1307                 << "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
1308                 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1309                 << tcu::TestLog::EndMessage;
1310
1311         if (propValue != ((referencedByShader) ? (1) : (0)))
1312         {
1313                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1314                 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
1315         }
1316 }
1317
1318 class TopLevelArraySizeValidator : public SingleVariableValidator
1319 {
1320 public:
1321                                 TopLevelArraySizeValidator      (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1322
1323         void            validateSingleVariable          (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1324 };
1325
1326 TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1327         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL)
1328 {
1329 }
1330
1331 void TopLevelArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1332 {
1333         int                     expected;
1334         std::string     reason;
1335
1336         DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1337         DE_UNREF(resource);
1338         DE_UNREF(implementationName);
1339
1340         if (!path[1].getDeclaration()->varType.isArrayType())
1341         {
1342                 expected = 1;
1343                 reason = "Top-level block member is not an array";
1344         }
1345         else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1346         {
1347                 expected = 1;
1348                 reason = "Top-level block member is not an array of an aggregate type";
1349         }
1350         else if (path[1].getDeclaration()->varType.getArraySize() == glu::VarType::UNSIZED_ARRAY)
1351         {
1352                 expected = 0;
1353                 reason = "Top-level block member is an unsized top-level array";
1354         }
1355         else
1356         {
1357                 expected = path[1].getDeclaration()->varType.getArraySize();
1358                 reason = "Top-level block member is a sized top-level array";
1359         }
1360
1361         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array size, expecting " << expected << ". (" << reason << ")." << tcu::TestLog::EndMessage;
1362
1363         if (propValue != expected)
1364         {
1365                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array size, got " << propValue << tcu::TestLog::EndMessage;
1366                 setError("top level array size invalid");
1367         }
1368 }
1369
1370 class TopLevelArrayStrideValidator : public SingleVariableValidator
1371 {
1372 public:
1373                                 TopLevelArrayStrideValidator    (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1374
1375         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1376 };
1377
1378 TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1379         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL)
1380 {
1381 }
1382
1383 void TopLevelArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1384 {
1385         DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1386         DE_UNREF(resource);
1387         DE_UNREF(implementationName);
1388
1389         if (!path[1].getDeclaration()->varType.isArrayType())
1390         {
1391                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array)." << tcu::TestLog::EndMessage;
1392
1393                 if (propValue != 0)
1394                 {
1395                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1396                         setError("top level array stride invalid");
1397                 }
1398         }
1399         else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1400         {
1401                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array of an aggregate type)." << tcu::TestLog::EndMessage;
1402
1403                 if (propValue != 0)
1404                 {
1405                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1406                         setError("top level array stride invalid");
1407                 }
1408         }
1409         else
1410         {
1411                 const int minimumStride = getVarTypeSize(path[1].getDeclaration()->varType.getElementType());
1412
1413                 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting greater or equal to " << minimumStride << "." << tcu::TestLog::EndMessage;
1414
1415                 if (propValue < minimumStride)
1416                 {
1417                         m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1418                         setError("top level array stride invalid");
1419                 }
1420         }
1421 }
1422
1423 class TransformFeedbackResourceValidator : public PropValidator
1424 {
1425 public:
1426                                         TransformFeedbackResourceValidator      (Context& context, ProgramResourcePropFlags validationProp);
1427
1428         void                    validate                                                        (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1429
1430 private:
1431         virtual void    validateBuiltinVariable                         (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1432         virtual void    validateSingleVariable                          (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1433 };
1434
1435
1436 TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp)
1437         : PropValidator(context, validationProp, DE_NULL)
1438 {
1439 }
1440
1441 void TransformFeedbackResourceValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1442 {
1443         if (deStringBeginsWith(resource.c_str(), "gl_"))
1444         {
1445                 validateBuiltinVariable(resource, propValue, implementationName);
1446         }
1447         else
1448         {
1449                 // Check resource name is a xfb output. (sanity check)
1450 #if defined(DE_DEBUG)
1451                 bool generatorFound = false;
1452
1453                 // Check the resource name is a valid transform feedback resource and find the name generating resource
1454                 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1455                 {
1456                         const std::string                                       varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1457                         std::vector<VariablePathComponent>      path;
1458                         std::vector<std::string>                        resources;
1459
1460                         if (!findProgramVariablePathByPathName(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1461                         {
1462                                 // program does not contain feedback varying, not valid program
1463                                 DE_ASSERT(false);
1464                                 return;
1465                         }
1466
1467                         generateVariableTypeResourceNames(resources, varyingName, *path.back().getVariableType(), RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
1468
1469                         if (de::contains(resources.begin(), resources.end(), resource))
1470                         {
1471                                 generatorFound = true;
1472                                 break;
1473                         }
1474                 }
1475
1476                 // resource name was not found, should never happen
1477                 DE_ASSERT(generatorFound);
1478                 DE_UNREF(generatorFound);
1479 #endif
1480
1481                 // verify resource
1482                 {
1483                         std::vector<VariablePathComponent> path;
1484
1485                         if (!findProgramVariablePathByPathName(path, program, resource, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1486                                 DE_ASSERT(false);
1487
1488                         validateSingleVariable(path, resource, propValue, implementationName);
1489                 }
1490         }
1491 }
1492
1493 class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator
1494 {
1495 public:
1496                                 TransformFeedbackArraySizeValidator     (Context& context);
1497
1498         void            validateBuiltinVariable                         (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1499         void            validateSingleVariable                          (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1500 };
1501
1502 TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context)
1503         : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE)
1504 {
1505 }
1506
1507 void TransformFeedbackArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1508 {
1509         DE_UNREF(implementationName);
1510
1511         int arraySize = 0;
1512
1513         if (resource == "gl_Position")
1514                 arraySize = 1;
1515         else
1516                 DE_ASSERT(false);
1517
1518         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1519         if (arraySize != propValue)
1520         {
1521                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1522                 setError("resource array size invalid");
1523         }
1524 }
1525
1526 void TransformFeedbackArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1527 {
1528         DE_UNREF(resource);
1529         DE_UNREF(implementationName);
1530
1531         const int arraySize = (path.back().getVariableType()->isArrayType()) ? (path.back().getVariableType()->getArraySize()) : (1);
1532
1533         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1534         if (arraySize != propValue)
1535         {
1536                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1537                 setError("resource array size invalid");
1538         }
1539 }
1540
1541 class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator
1542 {
1543 public:
1544                                 TransformFeedbackNameLengthValidator    (Context& context);
1545
1546 private:
1547         void            validateBuiltinVariable                                 (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1548         void            validateSingleVariable                                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1549         void            validateVariable                                                (const std::string& implementationName, glw::GLint propValue) const;
1550 };
1551
1552 TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context)
1553         : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH)
1554 {
1555 }
1556
1557 void TransformFeedbackNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1558 {
1559         DE_UNREF(resource);
1560         validateVariable(implementationName, propValue);
1561 }
1562
1563 void TransformFeedbackNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1564 {
1565         DE_UNREF(path);
1566         DE_UNREF(resource);
1567         validateVariable(implementationName, propValue);
1568 }
1569
1570 void TransformFeedbackNameLengthValidator::validateVariable (const std::string& implementationName, glw::GLint propValue) const
1571 {
1572         const int expected = (int)implementationName.length() + 1; // includes null byte
1573         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1574
1575         if (propValue != expected)
1576         {
1577                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1578                 setError("name length invalid");
1579         }
1580 }
1581
1582 class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator
1583 {
1584 public:
1585                                 TransformFeedbackTypeValidator          (Context& context);
1586
1587         void            validateBuiltinVariable                         (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1588         void            validateSingleVariable                          (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1589 };
1590
1591 TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context)
1592         : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE)
1593 {
1594 }
1595
1596 void TransformFeedbackTypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1597 {
1598         DE_UNREF(implementationName);
1599
1600         glu::DataType varType = glu::TYPE_INVALID;
1601
1602         if (resource == "gl_Position")
1603                 varType = glu::TYPE_FLOAT_VEC4;
1604         else
1605                 DE_ASSERT(false);
1606
1607         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(varType) << tcu::TestLog::EndMessage;
1608         if (glu::getDataTypeFromGLType(propValue) != varType)
1609         {
1610                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1611                 setError("resource type invalid");
1612         }
1613         return;
1614 }
1615
1616 void TransformFeedbackTypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1617 {
1618         DE_UNREF(resource);
1619         DE_UNREF(implementationName);
1620
1621         // Unlike other interfaces, xfb program interface uses just variable name to refer to arrays of basic types. (Others use "variable[0]")
1622         // Thus we might end up querying a type for an array. In this case, return the type of an array element.
1623         const glu::VarType& variable    = *path.back().getVariableType();
1624         const glu::VarType& elementType = (variable.isArrayType()) ? (variable.getElementType()) : (variable);
1625
1626         DE_ASSERT(elementType.isBasicType());
1627
1628         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(elementType.getBasicType()) << tcu::TestLog::EndMessage;
1629         if (elementType.getBasicType() != glu::getDataTypeFromGLType(propValue))
1630         {
1631                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1632                 setError("resource type invalid");
1633         }
1634 }
1635
1636 class PerPatchValidator : public SingleVariableValidator
1637 {
1638 public:
1639                                 PerPatchValidator                               (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1640
1641         std::string getHumanReadablePropertyString      (glw::GLint propVal) const;
1642         void            validateSingleVariable                  (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1643         void            validateBuiltinVariable                 (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1644 };
1645
1646 PerPatchValidator::PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1647         : SingleVariableValidator(context, PROGRAMRESOURCEPROP_IS_PER_PATCH, programID, filter, "GL_EXT_tessellation_shader")
1648 {
1649 }
1650
1651 std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1652 {
1653         return de::toString(glu::getBooleanStr(propVal));
1654 }
1655
1656 void PerPatchValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1657 {
1658         const glu::Storage      storage         = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
1659         const int                       expected        = (storage == glu::STORAGE_PATCH_IN || storage == glu::STORAGE_PATCH_OUT) ? (1) : (0);
1660
1661         DE_UNREF(resource);
1662         DE_UNREF(implementationName);
1663
1664         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << expected << tcu::TestLog::EndMessage;
1665
1666         if (propValue != expected)
1667         {
1668                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1669                 setError("resource is per patch invalid");
1670         }
1671 }
1672
1673 void PerPatchValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1674 {
1675         DE_UNREF(implementationName);
1676
1677         static const struct
1678         {
1679                 const char*             name;
1680                 int                             isPerPatch;
1681         } builtins[] =
1682         {
1683                 { "gl_Position",                                0       },
1684                 { "gl_PerVertex.gl_Position",   0       },
1685                 { "gl_InvocationID",                    0       },
1686                 { "gl_TessLevelOuter[0]",               1       },
1687                 { "gl_TessLevelInner[0]",               1       },
1688         };
1689
1690         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
1691         {
1692                 if (resource == builtins[ndx].name)
1693                 {
1694                         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << builtins[ndx].isPerPatch << tcu::TestLog::EndMessage;
1695
1696                         if (propValue != builtins[ndx].isPerPatch)
1697                         {
1698                                 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1699                                 setError("resource is per patch invalid");
1700                         }
1701                         return;
1702                 }
1703         }
1704
1705         DE_ASSERT(false);
1706 }
1707
1708 } // anonymous
1709
1710 ProgramResourceQueryTestTarget::ProgramResourceQueryTestTarget (ProgramInterface interface_, deUint32 propFlags_)
1711         : interface(interface_)
1712         , propFlags(propFlags_)
1713 {
1714         switch (interface)
1715         {
1716                 case PROGRAMINTERFACE_UNIFORM:                                          DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK)                      == propFlags);  break;
1717                 case PROGRAMINTERFACE_UNIFORM_BLOCK:                            DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_BLOCK_INTERFACE_MASK)        == propFlags);  break;
1718                 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:                     DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_SHADER_STORAGE_BLOCK_MASK)           == propFlags);  break;
1719                 case PROGRAMINTERFACE_PROGRAM_INPUT:                            DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_INPUT_MASK)                          == propFlags);  break;
1720                 case PROGRAMINTERFACE_PROGRAM_OUTPUT:                           DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_OUTPUT_MASK)                         == propFlags);  break;
1721                 case PROGRAMINTERFACE_BUFFER_VARIABLE:                          DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK)                        == propFlags);  break;
1722                 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:       DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_TRANSFORM_FEEDBACK_VARYING_MASK)     == propFlags);  break;
1723
1724                 default:
1725                         DE_ASSERT(false);
1726         }
1727 }
1728
1729 ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget)
1730         : TestCase              (context, name, description)
1731         , m_queryTarget (queryTarget)
1732 {
1733 }
1734
1735 ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void)
1736 {
1737 }
1738
1739 ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const
1740 {
1741         return m_queryTarget.interface;
1742 }
1743
1744 static glw::GLenum getGLInterfaceEnumValue (ProgramInterface interface)
1745 {
1746         switch (interface)
1747         {
1748                 case PROGRAMINTERFACE_UNIFORM:                                          return GL_UNIFORM;
1749                 case PROGRAMINTERFACE_UNIFORM_BLOCK:                            return GL_UNIFORM_BLOCK;
1750                 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:            return GL_ATOMIC_COUNTER_BUFFER;
1751                 case PROGRAMINTERFACE_PROGRAM_INPUT:                            return GL_PROGRAM_INPUT;
1752                 case PROGRAMINTERFACE_PROGRAM_OUTPUT:                           return GL_PROGRAM_OUTPUT;
1753                 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:       return GL_TRANSFORM_FEEDBACK_VARYING;
1754                 case PROGRAMINTERFACE_BUFFER_VARIABLE:                          return GL_BUFFER_VARIABLE;
1755                 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:                     return GL_SHADER_STORAGE_BLOCK;
1756                 default:
1757                         DE_ASSERT(false);
1758                         return 0;
1759         };
1760 }
1761
1762 static bool isInterfaceBlockInterfaceName (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& blockInterfaceName)
1763 {
1764         deUint32 validStorageBits;
1765         deUint32 searchStageBits;
1766
1767         DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1768         DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1769
1770         switch (interface)
1771         {
1772                 case PROGRAMINTERFACE_UNIFORM_BLOCK:
1773                 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1774                 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1775                         return false;
1776
1777                 case PROGRAMINTERFACE_PROGRAM_INPUT:
1778                         validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1779                         searchStageBits = (1u << program->getFirstStage());
1780                         break;
1781
1782                 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1783                         validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1784                         searchStageBits = (1u << program->getLastStage());
1785                         break;
1786
1787                 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1788                         validStorageBits = (1u << glu::STORAGE_OUT);
1789                         searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1790                         break;
1791
1792                 case PROGRAMINTERFACE_UNIFORM:
1793                         validStorageBits = (1u << glu::STORAGE_UNIFORM);
1794                         searchStageBits = 0xFFFFFFFFu;
1795                         break;
1796
1797                 case PROGRAMINTERFACE_BUFFER_VARIABLE:
1798                         validStorageBits = (1u << glu::STORAGE_BUFFER);
1799                         searchStageBits = 0xFFFFFFFFu;
1800                         break;
1801
1802                 default:
1803                         DE_ASSERT(false);
1804                         return false;
1805         }
1806
1807         for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1808         {
1809                 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1810                 if (((1u << shader->getType()) & searchStageBits) == 0)
1811                         continue;
1812
1813                 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1814                 {
1815                         const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1816
1817                         if (((1u << block.storage) & validStorageBits) == 0)
1818                                 continue;
1819
1820                         if (block.interfaceName == blockInterfaceName)
1821                                 return true;
1822                 }
1823         }
1824         return false;
1825 }
1826
1827 static std::string getInterfaceBlockInteraceNameByMember (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& memberName)
1828 {
1829         deUint32 validStorageBits;
1830         deUint32 searchStageBits;
1831
1832         DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1833         DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1834
1835         switch (interface)
1836         {
1837                 case PROGRAMINTERFACE_UNIFORM_BLOCK:
1838                 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1839                 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1840                         return "";
1841
1842                 case PROGRAMINTERFACE_PROGRAM_INPUT:
1843                         validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1844                         searchStageBits = (1u << program->getFirstStage());
1845                         break;
1846
1847                 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1848                         validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1849                         searchStageBits = (1u << program->getLastStage());
1850                         break;
1851
1852                 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1853                         validStorageBits = (1u << glu::STORAGE_OUT);
1854                         searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1855                         break;
1856
1857                 case PROGRAMINTERFACE_UNIFORM:
1858                         validStorageBits = (1u << glu::STORAGE_UNIFORM);
1859                         searchStageBits = 0xFFFFFFFFu;
1860                         break;
1861
1862                 case PROGRAMINTERFACE_BUFFER_VARIABLE:
1863                         validStorageBits = (1u << glu::STORAGE_BUFFER);
1864                         searchStageBits = 0xFFFFFFFFu;
1865                         break;
1866
1867                 default:
1868                         DE_ASSERT(false);
1869                         return "";
1870         }
1871
1872         for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1873         {
1874                 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1875                 if (((1u << shader->getType()) & searchStageBits) == 0)
1876                         continue;
1877
1878                 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1879                 {
1880                         const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1881
1882                         if (((1u << block.storage) & validStorageBits) == 0)
1883                                 continue;
1884
1885                         for (int varNdx = 0; varNdx < (int)block.variables.size(); ++varNdx)
1886                         {
1887                                 if (block.variables[varNdx].name == memberName)
1888                                         return block.interfaceName;
1889                         }
1890                 }
1891         }
1892         return "";
1893 }
1894
1895 static void queryAndValidateProps (tcu::TestContext&                                                    testCtx,
1896                                                                    const glw::Functions&                                                gl,
1897                                                                    glw::GLuint                                                                  programID,
1898                                                                    ProgramInterface                                                             interface,
1899                                                                    const char*                                                                  targetResourceName,
1900                                                                    const ProgramInterfaceDefinition::Program*   programDefinition,
1901                                                                    const std::vector<glw::GLenum>&                              props,
1902                                                                    const std::vector<const PropValidator*>&             validators)
1903 {
1904         const glw::GLenum                       glInterface                                     = getGLInterfaceEnumValue(interface);
1905         std::string                                     implementationResourceName      = targetResourceName;
1906         glw::GLuint                                     resourceNdx;
1907         glw::GLint                                      written                                         = -1;
1908
1909         // prefill result buffer with an invalid value. -1 might be valid sometimes, avoid it. Make buffer one larger
1910         // to allow detection of too many return values
1911         std::vector<glw::GLint>         propValues              (props.size() + 1, -2);
1912
1913         DE_ASSERT(props.size() == validators.size());
1914
1915         // query
1916
1917         resourceNdx = gl.getProgramResourceIndex(programID, glInterface, targetResourceName);
1918         GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
1919
1920         if (resourceNdx == GL_INVALID_INDEX)
1921         {
1922                 static const struct
1923                 {
1924                         bool removeTrailingArray;       // convert from "target[0]" -> "target"
1925                         bool removeTrailingMember;      // convert from "target.member" -> "target"
1926                         bool removeIOBlock;                     // convert from "InterfaceName.target" -> "target"
1927                         bool addIOBlock;                        // convert from "target" -> "InterfaceName.target"
1928                         bool addIOBlockArray;           // convert from "target" -> "InterfaceName[0].target"
1929                 } recoveryStrategies[] =
1930                 {
1931                         // try one patch
1932                         { true,         false,  false,  false,  false   },
1933                         { false,        true,   false,  false,  false   },
1934                         { false,        false,  true,   false,  false   },
1935                         { false,        false,  false,  true,   false   },
1936                         { false,        false,  false,  false,  true    },
1937                         // patch both ends
1938                         { true,         false,  true,   false,  false   },
1939                         { true,         false,  false,  true,   false   },
1940                         { true,         false,  false,  false,  true    },
1941                         { false,        true,   true,   false,  false   },
1942                         { false,        true,   false,  true,   false   },
1943                         { false,        true,   false,  false,  true    },
1944                 };
1945
1946                 // The resource name generation in the GL implementations is very commonly broken. Try to
1947                 // keep the tests producing useful data even in these cases by attempting to recover from
1948                 // common naming bugs. Set test result to failure even if recovery succeeded to signal
1949                 // incorrect name generation.
1950
1951                 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceIndex returned GL_INVALID_INDEX for \"" << targetResourceName << "\"" << tcu::TestLog::EndMessage;
1952                 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource");
1953
1954                 for (int strategyNdx = 0; strategyNdx < DE_LENGTH_OF_ARRAY(recoveryStrategies); ++strategyNdx)
1955                 {
1956                         const std::string       resourceName                    = std::string(targetResourceName);
1957                         const size_t            rootNameEnd                             = resourceName.find_first_of(".[");
1958                         const std::string       rootName                                = resourceName.substr(0, rootNameEnd);
1959                         std::string                     simplifiedResourceName;
1960
1961                         if (recoveryStrategies[strategyNdx].removeTrailingArray)
1962                         {
1963                                 if (de::endsWith(resourceName, "[0]"))
1964                                         simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3);
1965                                 else
1966                                         continue;
1967                         }
1968
1969                         if (recoveryStrategies[strategyNdx].removeTrailingMember)
1970                         {
1971                                 const size_t lastMember = resourceName.find_last_of('.');
1972                                 if (lastMember != std::string::npos)
1973                                         simplifiedResourceName = resourceName.substr(0, lastMember);
1974                                 else
1975                                         continue;
1976                         }
1977
1978                         if (recoveryStrategies[strategyNdx].removeIOBlock)
1979                         {
1980                                 if (deStringBeginsWith(resourceName.c_str(), "gl_PerVertex."))
1981                                 {
1982                                         // builtin interface bock, remove block name
1983                                         simplifiedResourceName = resourceName.substr(13);
1984                                 }
1985                                 else if (isInterfaceBlockInterfaceName(programDefinition, interface, rootName))
1986                                 {
1987                                         // user-defined inteface block, remove name
1988                                         const size_t accessorEnd = resourceName.find('.'); // includes potential array accessor
1989
1990                                         if (accessorEnd != std::string::npos)
1991                                                 simplifiedResourceName = resourceName.substr(0, accessorEnd+1);
1992                                         else
1993                                                 continue;
1994                                 }
1995                                 else
1996                                 {
1997                                         // recovery not applicable
1998                                         continue;
1999                                 }
2000                         }
2001
2002                         if (recoveryStrategies[strategyNdx].addIOBlock || recoveryStrategies[strategyNdx].addIOBlockArray)
2003                         {
2004                                 const std::string arrayAccessor = (recoveryStrategies[strategyNdx].addIOBlockArray) ? ("[0]") : ("");
2005
2006                                 if (deStringBeginsWith(resourceName.c_str(), "gl_") && resourceName.find('.') == std::string::npos)
2007                                 {
2008                                         // free builtin variable, add block name
2009                                         simplifiedResourceName = "gl_PerVertex" + arrayAccessor + "." + resourceName;
2010                                 }
2011                                 else
2012                                 {
2013                                         const std::string interafaceName = getInterfaceBlockInteraceNameByMember(programDefinition, interface, rootName);
2014
2015                                         if (!interafaceName.empty())
2016                                         {
2017                                                 // free user variable, add block name
2018                                                 simplifiedResourceName = interafaceName + arrayAccessor + "." + resourceName;
2019                                         }
2020                                         else
2021                                         {
2022                                                 // recovery not applicable
2023                                                 continue;
2024                                         }
2025                                 }
2026                         }
2027
2028                         if (simplifiedResourceName.empty())
2029                                 continue;
2030
2031                         resourceNdx = gl.getProgramResourceIndex(programID, glInterface, simplifiedResourceName.c_str());
2032                         GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
2033
2034                         // recovery succeeded
2035                         if (resourceNdx != GL_INVALID_INDEX)
2036                         {
2037                                 implementationResourceName = simplifiedResourceName;
2038                                 testCtx.getLog() << tcu::TestLog::Message << "\tResource not found, continuing anyway using index obtained for resource \"" << simplifiedResourceName << "\"" << tcu::TestLog::EndMessage;
2039                                 break;
2040                         }
2041                 }
2042
2043                 if (resourceNdx == GL_INVALID_INDEX)
2044                         return;
2045         }
2046
2047         gl.getProgramResourceiv(programID, glInterface, resourceNdx, (int)props.size(), &props[0], (int)propValues.size(), &written, &propValues[0]);
2048         GLU_EXPECT_NO_ERROR(gl.getError(), "get props");
2049
2050         if (written != (int)props.size())
2051         {
2052                 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv returned unexpected number of values, expected " << (int)props.size() << ", got " << written << tcu::TestLog::EndMessage;
2053                 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2054                 return;
2055         }
2056
2057         if (propValues.back() != -2)
2058         {
2059                 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv post write buffer guard value was modified, too many return values" << tcu::TestLog::EndMessage;
2060                 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2061                 return;
2062         }
2063         propValues.pop_back();
2064         DE_ASSERT(validators.size() == propValues.size());
2065
2066         // log
2067
2068         {
2069                 tcu::MessageBuilder message(&testCtx.getLog());
2070                 message << "For resource index " << resourceNdx << " (\"" << targetResourceName << "\") got following properties:\n";
2071
2072                 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2073                         message << "\t" << glu::getProgramResourcePropertyName(props[propNdx]) << ":\t" << validators[propNdx]->getHumanReadablePropertyString(propValues[propNdx]) << "\n";
2074
2075                 message << tcu::TestLog::EndMessage;
2076         }
2077
2078         // validate
2079
2080         for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2081                 validators[propNdx]->validate(programDefinition, targetResourceName, propValues[propNdx], implementationResourceName);
2082 }
2083
2084 const ProgramInterfaceDefinition::Program* ProgramInterfaceQueryTestCase::getAndCheckProgramDefinition (void)
2085 {
2086         const ProgramInterfaceDefinition::Program* programDefinition = getProgramDefinition();
2087         DE_ASSERT(programDefinition->isValid());
2088
2089         const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
2090
2091         if (programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
2092                 programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
2093         {
2094                 if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2095                         throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2096         }
2097
2098         // Testing IS_PER_PATCH as a part of a larger set is ok, since the extension is checked
2099         // before query. However, we don't want IS_PER_PATCH-specific tests to become noop and pass.
2100         if (m_queryTarget.propFlags == PROGRAMRESOURCEPROP_IS_PER_PATCH)
2101         {
2102                 if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2103                         throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2104         }
2105
2106         if (programDefinition->hasStage(glu::SHADERTYPE_GEOMETRY))
2107         {
2108                 if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2109                         throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
2110         }
2111
2112         if (programContainsIOBlocks(programDefinition))
2113         {
2114                 if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_io_blocks"))
2115                         throw tcu::NotSupportedError("Test requires GL_EXT_shader_io_blocks extension");
2116         }
2117
2118         return programDefinition;
2119 }
2120
2121 int ProgramInterfaceQueryTestCase::getMaxPatchVertices (void)
2122 {
2123         const glw::Functions&   gl                                      = m_context.getRenderContext().getFunctions();
2124         glw::GLint                              maxPatchVertices        = 0;
2125
2126         gl.getIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
2127         GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_PATCH_VERTICES)");
2128         return maxPatchVertices;
2129 }
2130
2131 ProgramInterfaceQueryTestCase::IterateResult ProgramInterfaceQueryTestCase::iterate (void)
2132 {
2133         struct TestProperty
2134         {
2135                 glw::GLenum                             prop;
2136                 const PropValidator*    validator;
2137         };
2138
2139         const ProgramInterfaceDefinition::Program*      programDefinition       = getAndCheckProgramDefinition();
2140         const std::vector<std::string>                          targetResources         = getQueryTargetResources();
2141         glu::ShaderProgram                                                      program                         (m_context.getRenderContext(), generateProgramInterfaceProgramSources(programDefinition));
2142
2143         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2144
2145         // Log program
2146         {
2147                 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
2148
2149                 // Feedback varyings
2150                 if (!programDefinition->getTransformFeedbackVaryings().empty())
2151                 {
2152                         tcu::MessageBuilder builder(&m_testCtx.getLog());
2153                         builder << "Transform feedback varyings: {";
2154                         for (int ndx = 0; ndx < (int)programDefinition->getTransformFeedbackVaryings().size(); ++ndx)
2155                         {
2156                                 if (ndx)
2157                                         builder << ", ";
2158                                 builder << "\"" << programDefinition->getTransformFeedbackVaryings()[ndx] << "\"";
2159                         }
2160                         builder << "}" << tcu::TestLog::EndMessage;
2161                 }
2162
2163                 m_testCtx.getLog() << program;
2164                 if (!program.isOk())
2165                 {
2166                         m_testCtx.getLog() << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits" << tcu::TestLog::EndMessage;
2167                         checkProgramResourceUsage(programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2168
2169                         // within limits
2170                         throw tcu::TestError("could not build program");
2171                 }
2172         }
2173
2174         // Check interface props
2175
2176         switch (m_queryTarget.interface)
2177         {
2178                 case PROGRAMINTERFACE_UNIFORM:
2179                 {
2180                         const VariableSearchFilter                                      uniformFilter                                           = VariableSearchFilter::createStorageFilter(glu::STORAGE_UNIFORM);
2181
2182                         const TypeValidator                                                     typeValidator                                           (m_context, program.getProgram(),                                               uniformFilter);
2183                         const ArraySizeValidator                                        arraySizeValidator                                      (m_context, program.getProgram(),                                               -1,                                     uniformFilter);
2184                         const ArrayStrideValidator                                      arrayStrideValidator                            (m_context, program.getProgram(),                                               uniformFilter);
2185                         const BlockIndexValidator                                       blockIndexValidator                                     (m_context, program.getProgram(),                                               uniformFilter);
2186                         const IsRowMajorValidator                                       isRowMajorValidator                                     (m_context, program.getProgram(),                                               uniformFilter);
2187                         const MatrixStrideValidator                                     matrixStrideValidator                           (m_context, program.getProgram(),                                               uniformFilter);
2188                         const AtomicCounterBufferIndexVerifier          atomicCounterBufferIndexVerifier        (m_context, program.getProgram(),                                               uniformFilter);
2189                         const LocationValidator                                         locationValidator                                       (m_context, program.getProgram(),                                               uniformFilter);
2190                         const VariableNameLengthValidator                       nameLengthValidator                                     (m_context, program.getProgram(),                                               uniformFilter);
2191                         const OffsetValidator                                           offsetVerifier                                          (m_context, program.getProgram(),                                               uniformFilter);
2192                         const VariableReferencedByShaderValidator       referencedByVertexVerifier                      (m_context, glu::SHADERTYPE_VERTEX,                                             uniformFilter);
2193                         const VariableReferencedByShaderValidator       referencedByFragmentVerifier            (m_context, glu::SHADERTYPE_FRAGMENT,                                   uniformFilter);
2194                         const VariableReferencedByShaderValidator       referencedByComputeVerifier                     (m_context, glu::SHADERTYPE_COMPUTE,                                    uniformFilter);
2195                         const VariableReferencedByShaderValidator       referencedByGeometryVerifier            (m_context, glu::SHADERTYPE_GEOMETRY,                                   uniformFilter);
2196                         const VariableReferencedByShaderValidator       referencedByTessControlVerifier         (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,               uniformFilter);
2197                         const VariableReferencedByShaderValidator       referencedByTessEvaluationVerifier      (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,    uniformFilter);
2198
2199                         const TestProperty allProperties[] =
2200                         {
2201                                 { GL_ARRAY_SIZE,                                                        &arraySizeValidator                                     },
2202                                 { GL_ARRAY_STRIDE,                                                      &arrayStrideValidator                           },
2203                                 { GL_ATOMIC_COUNTER_BUFFER_INDEX,                       &atomicCounterBufferIndexVerifier       },
2204                                 { GL_BLOCK_INDEX,                                                       &blockIndexValidator                            },
2205                                 { GL_IS_ROW_MAJOR,                                                      &isRowMajorValidator                            },
2206                                 { GL_LOCATION,                                                          &locationValidator                                      },
2207                                 { GL_MATRIX_STRIDE,                                                     &matrixStrideValidator                          },
2208                                 { GL_NAME_LENGTH,                                                       &nameLengthValidator                            },
2209                                 { GL_OFFSET,                                                            &offsetVerifier                                         },
2210                                 { GL_REFERENCED_BY_VERTEX_SHADER,                       &referencedByVertexVerifier                     },
2211                                 { GL_REFERENCED_BY_FRAGMENT_SHADER,                     &referencedByFragmentVerifier           },
2212                                 { GL_REFERENCED_BY_COMPUTE_SHADER,                      &referencedByComputeVerifier            },
2213                                 { GL_REFERENCED_BY_GEOMETRY_SHADER,                     &referencedByGeometryVerifier           },
2214                                 { GL_REFERENCED_BY_TESS_CONTROL_SHADER,         &referencedByTessControlVerifier        },
2215                                 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER,      &referencedByTessEvaluationVerifier     },
2216                                 { GL_TYPE,                                                                      &typeValidator                                          },
2217                         };
2218
2219                         for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2220                         {
2221                                 const tcu::ScopedLogSection                     section                 (m_testCtx.getLog(), "UniformResource", "Uniform resource \"" +  targetResources[targetResourceNdx] + "\"");
2222                                 const glw::Functions&                           gl                              = m_context.getRenderContext().getFunctions();
2223                                 std::vector<glw::GLenum>                        props;
2224                                 std::vector<const PropValidator*>       validators;
2225
2226                                 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2227                                 {
2228                                         if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2229                                                 allProperties[propNdx].validator->isSupported())
2230                                         {
2231                                                 props.push_back(allProperties[propNdx].prop);
2232                                                 validators.push_back(allProperties[propNdx].validator);
2233                                         }
2234                                 }
2235
2236                                 DE_ASSERT(!props.empty());
2237
2238                                 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2239                         }
2240
2241                         break;
2242                 }
2243
2244                 case PROGRAMINTERFACE_UNIFORM_BLOCK:
2245                 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
2246                 {
2247                         const glu::Storage                                              storage                                                         = (m_queryTarget.interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
2248                         const VariableSearchFilter                              blockFilter                                                     = VariableSearchFilter::createStorageFilter(storage);
2249
2250                         const BlockNameLengthValidator                  nameLengthValidator                                     (m_context, program.getProgram(),                                               blockFilter);
2251                         const BlockReferencedByShaderValidator  referencedByVertexVerifier                      (m_context, glu::SHADERTYPE_VERTEX,                                             blockFilter);
2252                         const BlockReferencedByShaderValidator  referencedByFragmentVerifier            (m_context, glu::SHADERTYPE_FRAGMENT,                                   blockFilter);
2253                         const BlockReferencedByShaderValidator  referencedByComputeVerifier                     (m_context, glu::SHADERTYPE_COMPUTE,                                    blockFilter);
2254                         const BlockReferencedByShaderValidator  referencedByGeometryVerifier            (m_context, glu::SHADERTYPE_GEOMETRY,                                   blockFilter);
2255                         const BlockReferencedByShaderValidator  referencedByTessControlVerifier         (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,               blockFilter);
2256                         const BlockReferencedByShaderValidator  referencedByTessEvaluationVerifier      (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,    blockFilter);
2257                         const BufferBindingValidator                    bufferBindingValidator                          (m_context, program.getProgram(),                                               blockFilter);
2258
2259                         const TestProperty allProperties[] =
2260                         {
2261                                 { GL_NAME_LENGTH,                                                       &nameLengthValidator                            },
2262                                 { GL_REFERENCED_BY_VERTEX_SHADER,                       &referencedByVertexVerifier                     },
2263                                 { GL_REFERENCED_BY_FRAGMENT_SHADER,                     &referencedByFragmentVerifier           },
2264                                 { GL_REFERENCED_BY_COMPUTE_SHADER,                      &referencedByComputeVerifier            },
2265                                 { GL_REFERENCED_BY_GEOMETRY_SHADER,                     &referencedByGeometryVerifier           },
2266                                 { GL_REFERENCED_BY_TESS_CONTROL_SHADER,         &referencedByTessControlVerifier        },
2267                                 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER,      &referencedByTessEvaluationVerifier     },
2268                                 { GL_BUFFER_BINDING,                                            &bufferBindingValidator                         },
2269                         };
2270
2271                         for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2272                         {
2273                                 const tcu::ScopedLogSection                     section                 (m_testCtx.getLog(), "BlockResource", "Interface block \"" +  targetResources[targetResourceNdx] + "\"");
2274                                 const glw::Functions&                           gl                              = m_context.getRenderContext().getFunctions();
2275                                 std::vector<glw::GLenum>                        props;
2276                                 std::vector<const PropValidator*>       validators;
2277
2278                                 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2279                                 {
2280                                         if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2281                                                 allProperties[propNdx].validator->isSupported())
2282                                         {
2283                                                 props.push_back(allProperties[propNdx].prop);
2284                                                 validators.push_back(allProperties[propNdx].validator);
2285                                         }
2286                                 }
2287
2288                                 DE_ASSERT(!props.empty());
2289
2290                                 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2291                         }
2292
2293                         break;
2294                 }
2295
2296                 case PROGRAMINTERFACE_PROGRAM_INPUT:
2297                 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
2298                 {
2299                         const bool                                                                      isInputCase                                                     = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT);
2300                         const glu::Storage                                                      varyingStorage                                          = (isInputCase) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
2301                         const glu::Storage                                                      patchStorage                                            = (isInputCase) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT);
2302                         const glu::ShaderType                                           shaderType                                                      = (isInputCase) ? (programDefinition->getFirstStage()) : (programDefinition->getLastStage());
2303                         const int                                                                       unsizedArraySize                                        = (isInputCase && shaderType == glu::SHADERTYPE_GEOMETRY)                                       ? (1)                                                                                                                   // input points
2304                                                                                                                                                                                         : (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)           ? (getMaxPatchVertices())                                                                               // input batch size
2305                                                                                                                                                                                         : (!isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)          ? (programDefinition->getTessellationNumOutputPatchVertices())  // output batch size
2306                                                                                                                                                                                         : (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)        ? (getMaxPatchVertices())                                                                               // input batch size
2307                                                                                                                                                                                         : (-1);
2308                         const VariableSearchFilter                                      variableFilter                                          = VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType),
2309                                                                                                                                                                                                                                                            VariableSearchFilter::logicalOr(VariableSearchFilter::createStorageFilter(varyingStorage),
2310                                                                                                                                                                                                                                                                                                                            VariableSearchFilter::createStorageFilter(patchStorage)));
2311
2312                         const TypeValidator                                                     typeValidator                                           (m_context, program.getProgram(),                                               variableFilter);
2313                         const ArraySizeValidator                                        arraySizeValidator                                      (m_context, program.getProgram(),                                               unsizedArraySize,               variableFilter);
2314                         const LocationValidator                                         locationValidator                                       (m_context, program.getProgram(),                                               variableFilter);
2315                         const VariableNameLengthValidator                       nameLengthValidator                                     (m_context, program.getProgram(),                                               variableFilter);
2316                         const VariableReferencedByShaderValidator       referencedByVertexVerifier                      (m_context, glu::SHADERTYPE_VERTEX,                                             variableFilter);
2317                         const VariableReferencedByShaderValidator       referencedByFragmentVerifier            (m_context, glu::SHADERTYPE_FRAGMENT,                                   variableFilter);
2318                         const VariableReferencedByShaderValidator       referencedByComputeVerifier                     (m_context, glu::SHADERTYPE_COMPUTE,                                    variableFilter);
2319                         const VariableReferencedByShaderValidator       referencedByGeometryVerifier            (m_context, glu::SHADERTYPE_GEOMETRY,                                   variableFilter);
2320                         const VariableReferencedByShaderValidator       referencedByTessControlVerifier         (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,               variableFilter);
2321                         const VariableReferencedByShaderValidator       referencedByTessEvaluationVerifier      (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,    variableFilter);
2322                         const PerPatchValidator                                         perPatchValidator                                       (m_context, program.getProgram(),                                               variableFilter);
2323
2324                         const TestProperty allProperties[] =
2325                         {
2326                                 { GL_ARRAY_SIZE,                                                        &arraySizeValidator                                     },
2327                                 { GL_LOCATION,                                                          &locationValidator                                      },
2328                                 { GL_NAME_LENGTH,                                                       &nameLengthValidator                            },
2329                                 { GL_REFERENCED_BY_VERTEX_SHADER,                       &referencedByVertexVerifier                     },
2330                                 { GL_REFERENCED_BY_FRAGMENT_SHADER,                     &referencedByFragmentVerifier           },
2331                                 { GL_REFERENCED_BY_COMPUTE_SHADER,                      &referencedByComputeVerifier            },
2332                                 { GL_REFERENCED_BY_GEOMETRY_SHADER,                     &referencedByGeometryVerifier           },
2333                                 { GL_REFERENCED_BY_TESS_CONTROL_SHADER,         &referencedByTessControlVerifier        },
2334                                 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER,      &referencedByTessEvaluationVerifier     },
2335                                 { GL_TYPE,                                                                      &typeValidator                                          },
2336                                 { GL_IS_PER_PATCH,                                                      &perPatchValidator                                      },
2337                         };
2338
2339                         for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2340                         {
2341                                 const std::string                                       resourceInterfaceName   = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? ("Input") : ("Output");
2342                                 const tcu::ScopedLogSection                     section                                 (m_testCtx.getLog(), "BlockResource", resourceInterfaceName + " resource \"" +  targetResources[targetResourceNdx] + "\"");
2343                                 const glw::Functions&                           gl                                              = m_context.getRenderContext().getFunctions();
2344                                 std::vector<glw::GLenum>                        props;
2345                                 std::vector<const PropValidator*>       validators;
2346
2347                                 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2348                                 {
2349                                         if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2350                                                 allProperties[propNdx].validator->isSupported())
2351                                         {
2352                                                 props.push_back(allProperties[propNdx].prop);
2353                                                 validators.push_back(allProperties[propNdx].validator);
2354                                         }
2355                                 }
2356
2357                                 DE_ASSERT(!props.empty());
2358
2359                                 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2360                         }
2361
2362                         break;
2363                 }
2364
2365                 case PROGRAMINTERFACE_BUFFER_VARIABLE:
2366                 {
2367                         const VariableSearchFilter                                      variableFilter                                          = VariableSearchFilter::createStorageFilter(glu::STORAGE_BUFFER);
2368
2369                         const TypeValidator                                                     typeValidator                                           (m_context, program.getProgram(),                                               variableFilter);
2370                         const ArraySizeValidator                                        arraySizeValidator                                      (m_context, program.getProgram(),                                               0,                                      variableFilter);
2371                         const ArrayStrideValidator                                      arrayStrideValidator                            (m_context, program.getProgram(),                                               variableFilter);
2372                         const BlockIndexValidator                                       blockIndexValidator                                     (m_context, program.getProgram(),                                               variableFilter);
2373                         const IsRowMajorValidator                                       isRowMajorValidator                                     (m_context, program.getProgram(),                                               variableFilter);
2374                         const MatrixStrideValidator                                     matrixStrideValidator                           (m_context, program.getProgram(),                                               variableFilter);
2375                         const OffsetValidator                                           offsetValidator                                         (m_context, program.getProgram(),                                               variableFilter);
2376                         const VariableNameLengthValidator                       nameLengthValidator                                     (m_context, program.getProgram(),                                               variableFilter);
2377                         const VariableReferencedByShaderValidator       referencedByVertexVerifier                      (m_context, glu::SHADERTYPE_VERTEX,                                             variableFilter);
2378                         const VariableReferencedByShaderValidator       referencedByFragmentVerifier            (m_context, glu::SHADERTYPE_FRAGMENT,                                   variableFilter);
2379                         const VariableReferencedByShaderValidator       referencedByComputeVerifier                     (m_context, glu::SHADERTYPE_COMPUTE,                                    variableFilter);
2380                         const VariableReferencedByShaderValidator       referencedByGeometryVerifier            (m_context, glu::SHADERTYPE_GEOMETRY,                                   variableFilter);
2381                         const VariableReferencedByShaderValidator       referencedByTessControlVerifier         (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,               variableFilter);
2382                         const VariableReferencedByShaderValidator       referencedByTessEvaluationVerifier      (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,    variableFilter);
2383                         const TopLevelArraySizeValidator                        topLevelArraySizeValidator                      (m_context, program.getProgram(),                                               variableFilter);
2384                         const TopLevelArrayStrideValidator                      topLevelArrayStrideValidator            (m_context, program.getProgram(),                                               variableFilter);
2385
2386                         const TestProperty allProperties[] =
2387                         {
2388                                 { GL_ARRAY_SIZE,                                                        &arraySizeValidator                                     },
2389                                 { GL_ARRAY_STRIDE,                                                      &arrayStrideValidator                           },
2390                                 { GL_BLOCK_INDEX,                                                       &blockIndexValidator                            },
2391                                 { GL_IS_ROW_MAJOR,                                                      &isRowMajorValidator                            },
2392                                 { GL_MATRIX_STRIDE,                                                     &matrixStrideValidator                          },
2393                                 { GL_NAME_LENGTH,                                                       &nameLengthValidator                            },
2394                                 { GL_OFFSET,                                                            &offsetValidator                                        },
2395                                 { GL_REFERENCED_BY_VERTEX_SHADER,                       &referencedByVertexVerifier                     },
2396                                 { GL_REFERENCED_BY_FRAGMENT_SHADER,                     &referencedByFragmentVerifier           },
2397                                 { GL_REFERENCED_BY_COMPUTE_SHADER,                      &referencedByComputeVerifier            },
2398                                 { GL_REFERENCED_BY_GEOMETRY_SHADER,                     &referencedByGeometryVerifier           },
2399                                 { GL_REFERENCED_BY_TESS_CONTROL_SHADER,         &referencedByTessControlVerifier        },
2400                                 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER,      &referencedByTessEvaluationVerifier     },
2401                                 { GL_TOP_LEVEL_ARRAY_SIZE,                                      &topLevelArraySizeValidator                     },
2402                                 { GL_TOP_LEVEL_ARRAY_STRIDE,                            &topLevelArrayStrideValidator           },
2403                                 { GL_TYPE,                                                                      &typeValidator                                          },
2404                         };
2405
2406                         for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2407                         {
2408                                 const tcu::ScopedLogSection                     section                 (m_testCtx.getLog(), "BufferVariableResource", "Buffer variable \"" +  targetResources[targetResourceNdx] + "\"");
2409                                 const glw::Functions&                           gl                              = m_context.getRenderContext().getFunctions();
2410                                 std::vector<glw::GLenum>                        props;
2411                                 std::vector<const PropValidator*>       validators;
2412
2413                                 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2414                                 {
2415                                         if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2416                                                 allProperties[propNdx].validator->isSupported())
2417                                         {
2418                                                 props.push_back(allProperties[propNdx].prop);
2419                                                 validators.push_back(allProperties[propNdx].validator);
2420                                         }
2421                                 }
2422
2423                                 DE_ASSERT(!props.empty());
2424
2425                                 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2426                         }
2427
2428                         break;
2429                 }
2430
2431                 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
2432                 {
2433                         const TransformFeedbackTypeValidator            typeValidator                   (m_context);
2434                         const TransformFeedbackArraySizeValidator       arraySizeValidator              (m_context);
2435                         const TransformFeedbackNameLengthValidator      nameLengthValidator             (m_context);
2436
2437                         const TestProperty allProperties[] =
2438                         {
2439                                 { GL_ARRAY_SIZE,                                        &arraySizeValidator                             },
2440                                 { GL_NAME_LENGTH,                                       &nameLengthValidator                    },
2441                                 { GL_TYPE,                                                      &typeValidator                                  },
2442                         };
2443
2444                         for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2445                         {
2446                                 const tcu::ScopedLogSection                     section                 (m_testCtx.getLog(), "XFBVariableResource", "Transform feedback varying \"" +  targetResources[targetResourceNdx] + "\"");
2447                                 const glw::Functions&                           gl                              = m_context.getRenderContext().getFunctions();
2448                                 std::vector<glw::GLenum>                        props;
2449                                 std::vector<const PropValidator*>       validators;
2450
2451                                 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2452                                 {
2453                                         if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2454                                                 allProperties[propNdx].validator->isSupported())
2455                                         {
2456                                                 props.push_back(allProperties[propNdx].prop);
2457                                                 validators.push_back(allProperties[propNdx].validator);
2458                                         }
2459                                 }
2460
2461                                 DE_ASSERT(!props.empty());
2462
2463                                 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2464                         }
2465
2466                         break;
2467                 }
2468
2469                 default:
2470                         DE_ASSERT(false);
2471         }
2472
2473         return STOP;
2474 }
2475
2476 static bool checkLimit (glw::GLenum pname, int usage, const glw::Functions& gl, tcu::TestLog& log)
2477 {
2478         if (usage > 0)
2479         {
2480                 glw::GLint limit = 0;
2481                 gl.getIntegerv(pname, &limit);
2482                 GLU_EXPECT_NO_ERROR(gl.getError(), "query limits");
2483
2484                 log << tcu::TestLog::Message << "\t" << glu::getGettableStateStr(pname) << " = " << limit << ", test requires " << usage << tcu::TestLog::EndMessage;
2485
2486                 if (limit < usage)
2487                 {
2488                         log << tcu::TestLog::Message << "\t\tLimit exceeded" << tcu::TestLog::EndMessage;
2489                         return false;
2490                 }
2491         }
2492
2493         return true;
2494 }
2495
2496 static bool checkShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader, const glw::Functions& gl, tcu::TestLog& log)
2497 {
2498         const ProgramInterfaceDefinition::ShaderResourceUsage usage = getShaderResourceUsage(program, shader);
2499
2500         switch (shader->getType())
2501         {
2502                 case glu::SHADERTYPE_VERTEX:
2503                 {
2504                         const struct
2505                         {
2506                                 glw::GLenum     pname;
2507                                 int                     usage;
2508                         } restrictions[] =
2509                         {
2510                                 { GL_MAX_VERTEX_ATTRIBS,                                                usage.numInputVectors                                   },
2511                                 { GL_MAX_VERTEX_UNIFORM_COMPONENTS,                             usage.numDefaultBlockUniformComponents  },
2512                                 { GL_MAX_VERTEX_UNIFORM_VECTORS,                                usage.numUniformVectors                                 },
2513                                 { GL_MAX_VERTEX_UNIFORM_BLOCKS,                                 usage.numUniformBlocks                                  },
2514                                 { GL_MAX_VERTEX_OUTPUT_COMPONENTS,                              usage.numOutputComponents                               },
2515                                 { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,                    usage.numSamplers                                               },
2516                                 { GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,                 usage.numAtomicCounterBuffers                   },
2517                                 { GL_MAX_VERTEX_ATOMIC_COUNTERS,                                usage.numAtomicCounters                                 },
2518                                 { GL_MAX_VERTEX_IMAGE_UNIFORMS,                                 usage.numImages                                                 },
2519                                 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,    usage.numCombinedUniformComponents              },
2520                                 { GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,                  usage.numShaderStorageBlocks                    },
2521                         };
2522
2523                         bool allOk = true;
2524
2525                         log << tcu::TestLog::Message << "Vertex shader:" << tcu::TestLog::EndMessage;
2526                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2527                                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2528
2529                         return allOk;
2530                 }
2531
2532                 case glu::SHADERTYPE_FRAGMENT:
2533                 {
2534                         const struct
2535                         {
2536                                 glw::GLenum     pname;
2537                                 int                     usage;
2538                         } restrictions[] =
2539                         {
2540                                 { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS,                   usage.numDefaultBlockUniformComponents          },
2541                                 { GL_MAX_FRAGMENT_UNIFORM_VECTORS,                              usage.numUniformVectors                                         },
2542                                 { GL_MAX_FRAGMENT_UNIFORM_BLOCKS,                               usage.numUniformBlocks                                          },
2543                                 { GL_MAX_FRAGMENT_INPUT_COMPONENTS,                             usage.numInputComponents                                        },
2544                                 { GL_MAX_TEXTURE_IMAGE_UNITS,                                   usage.numSamplers                                                       },
2545                                 { GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,               usage.numAtomicCounterBuffers                           },
2546                                 { GL_MAX_FRAGMENT_ATOMIC_COUNTERS,                              usage.numAtomicCounters                                         },
2547                                 { GL_MAX_FRAGMENT_IMAGE_UNIFORMS,                               usage.numImages                                                         },
2548                                 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,  usage.numCombinedUniformComponents                      },
2549                                 { GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,                usage.numShaderStorageBlocks                            },
2550                         };
2551
2552                         bool allOk = true;
2553
2554                         log << tcu::TestLog::Message << "Fragment shader:" << tcu::TestLog::EndMessage;
2555                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2556                                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2557
2558                         return allOk;
2559                 }
2560
2561                 case glu::SHADERTYPE_COMPUTE:
2562                 {
2563                         const struct
2564                         {
2565                                 glw::GLenum     pname;
2566                                 int                     usage;
2567                         } restrictions[] =
2568                         {
2569                                 { GL_MAX_COMPUTE_UNIFORM_BLOCKS,                                usage.numUniformBlocks                                  },
2570                                 { GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS,                   usage.numSamplers                                               },
2571                                 { GL_MAX_COMPUTE_UNIFORM_COMPONENTS,                    usage.numDefaultBlockUniformComponents  },
2572                                 { GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS,                usage.numAtomicCounterBuffers                   },
2573                                 { GL_MAX_COMPUTE_ATOMIC_COUNTERS,                               usage.numAtomicCounters                                 },
2574                                 { GL_MAX_COMPUTE_IMAGE_UNIFORMS,                                usage.numImages                                                 },
2575                                 { GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS,   usage.numCombinedUniformComponents              },
2576                                 { GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS,                 usage.numShaderStorageBlocks                    },
2577                         };
2578
2579                         bool allOk = true;
2580
2581                         log << tcu::TestLog::Message << "Compute shader:" << tcu::TestLog::EndMessage;
2582                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2583                                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2584
2585                         return allOk;
2586                 }
2587
2588                 case glu::SHADERTYPE_GEOMETRY:
2589                 {
2590                         const int totalOutputComponents = program->getGeometryNumOutputVertices() * usage.numOutputComponents;
2591                         const struct
2592                         {
2593                                 glw::GLenum     pname;
2594                                 int                     usage;
2595                         } restrictions[] =
2596                         {
2597                                 { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS,                           usage.numDefaultBlockUniformComponents                  },
2598                                 { GL_MAX_GEOMETRY_UNIFORM_BLOCKS,                                       usage.numUniformBlocks                                                  },
2599                                 { GL_MAX_GEOMETRY_INPUT_COMPONENTS,                                     usage.numInputComponents                                                },
2600                                 { GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,                            usage.numOutputComponents                                               },
2601                                 { GL_MAX_GEOMETRY_OUTPUT_VERTICES,                                      (int)program->getGeometryNumOutputVertices()    },
2602                                 { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,                      totalOutputComponents                                                   },
2603                                 { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,                          usage.numSamplers                                                               },
2604                                 { GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,                       usage.numAtomicCounterBuffers                                   },
2605                                 { GL_MAX_GEOMETRY_ATOMIC_COUNTERS,                                      usage.numAtomicCounters                                                 },
2606                                 { GL_MAX_GEOMETRY_IMAGE_UNIFORMS,                                       usage.numImages                                                                 },
2607                                 { GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,                        usage.numShaderStorageBlocks                                    },
2608                         };
2609
2610                         bool allOk = true;
2611
2612                         log << tcu::TestLog::Message << "Geometry shader:" << tcu::TestLog::EndMessage;
2613                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2614                                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2615
2616                         return allOk;
2617                 }
2618
2619                 case glu::SHADERTYPE_TESSELLATION_CONTROL:
2620                 {
2621                         const int totalOutputComponents = program->getTessellationNumOutputPatchVertices() * usage.numOutputComponents + usage.numPatchOutputComponents;
2622                         const struct
2623                         {
2624                                 glw::GLenum     pname;
2625                                 int                     usage;
2626                         } restrictions[] =
2627                         {
2628                                 { GL_MAX_PATCH_VERTICES,                                                                (int)program->getTessellationNumOutputPatchVertices()   },
2629                                 { GL_MAX_TESS_PATCH_COMPONENTS,                                                 usage.numPatchOutputComponents                                                  },
2630                                 { GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS,                               usage.numDefaultBlockUniformComponents                                  },
2631                                 { GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,                                   usage.numUniformBlocks                                                                  },
2632                                 { GL_MAX_TESS_CONTROL_INPUT_COMPONENTS,                                 usage.numInputComponents                                                                },
2633                                 { GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS,                                usage.numOutputComponents                                                               },
2634                                 { GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS,                  totalOutputComponents                                                                   },
2635                                 { GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,                              usage.numSamplers                                                                               },
2636                                 { GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,                   usage.numAtomicCounterBuffers                                                   },
2637                                 { GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,                                  usage.numAtomicCounters                                                                 },
2638                                 { GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,                                   usage.numImages                                                                                 },
2639                                 { GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,                    usage.numShaderStorageBlocks                                                    },
2640                         };
2641
2642                         bool allOk = true;
2643
2644                         log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage;
2645                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2646                                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2647
2648                         return allOk;
2649                 }
2650
2651                 case glu::SHADERTYPE_TESSELLATION_EVALUATION:
2652                 {
2653                         const struct
2654                         {
2655                                 glw::GLenum     pname;
2656                                 int                     usage;
2657                         } restrictions[] =
2658                         {
2659                                 { GL_MAX_PATCH_VERTICES,                                                                (int)program->getTessellationNumOutputPatchVertices()   },
2660                                 { GL_MAX_TESS_PATCH_COMPONENTS,                                                 usage.numPatchInputComponents                                                   },
2661                                 { GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,                    usage.numDefaultBlockUniformComponents                                  },
2662                                 { GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,                                usage.numUniformBlocks                                                                  },
2663                                 { GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,                              usage.numInputComponents                                                                },
2664                                 { GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,                             usage.numOutputComponents                                                               },
2665                                 { GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,                   usage.numSamplers                                                                               },
2666                                 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,                usage.numAtomicCounterBuffers                                                   },
2667                                 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,                               usage.numAtomicCounters                                                                 },
2668                                 { GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,                                usage.numImages                                                                                 },
2669                                 { GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,                 usage.numShaderStorageBlocks                                                    },
2670                         };
2671
2672                         bool allOk = true;
2673
2674                         log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage;
2675                         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2676                                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2677
2678                         return allOk;
2679                 }
2680
2681                 default:
2682                         DE_ASSERT(false);
2683                         return false;
2684         }
2685 }
2686
2687 static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2688 {
2689         const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program);
2690
2691         const struct
2692         {
2693                 glw::GLenum     pname;
2694                 int                     usage;
2695         } restrictions[] =
2696         {
2697                 { GL_MAX_UNIFORM_BUFFER_BINDINGS,                                               usage.uniformBufferMaxBinding+1                                 },
2698                 { GL_MAX_UNIFORM_BLOCK_SIZE,                                                    usage.uniformBufferMaxSize                                              },
2699                 { GL_MAX_COMBINED_UNIFORM_BLOCKS,                                               usage.numUniformBlocks                                                  },
2700                 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,                    usage.numCombinedVertexUniformComponents                },
2701                 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,                  usage.numCombinedFragmentUniformComponents              },
2702                 { GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS,                  usage.numCombinedGeometryUniformComponents              },
2703                 { GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,              usage.numCombinedTessControlUniformComponents   },
2704                 { GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,   usage.numCombinedTessEvalUniformComponents              },
2705                 { GL_MAX_VARYING_COMPONENTS,                                                    usage.numVaryingComponents                                              },
2706                 { GL_MAX_VARYING_VECTORS,                                                               usage.numVaryingVectors                                                 },
2707                 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,                                  usage.numCombinedSamplers                                               },
2708                 { GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES,                              usage.numCombinedOutputResources                                },
2709                 { GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,                                usage.atomicCounterBufferMaxBinding+1                   },
2710                 { GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE,                                    usage.atomicCounterBufferMaxSize                                },
2711                 { GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,                               usage.numAtomicCounterBuffers                                   },
2712                 { GL_MAX_COMBINED_ATOMIC_COUNTERS,                                              usage.numAtomicCounters                                                 },
2713                 { GL_MAX_IMAGE_UNITS,                                                                   usage.maxImageBinding+1                                                 },
2714                 { GL_MAX_COMBINED_IMAGE_UNIFORMS,                                               usage.numCombinedImages                                                 },
2715                 { GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,                                usage.shaderStorageBufferMaxBinding+1                   },
2716                 { GL_MAX_SHADER_STORAGE_BLOCK_SIZE,                                             usage.shaderStorageBufferMaxSize                                },
2717                 { GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS,                                usage.numShaderStorageBlocks                                    },
2718                 { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,             usage.numXFBInterleavedComponents                               },
2719                 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,                   usage.numXFBSeparateAttribs                                             },
2720                 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,                usage.numXFBSeparateComponents                                  },
2721                 { GL_MAX_DRAW_BUFFERS,                                                                  usage.fragmentOutputMaxBinding+1                                },
2722         };
2723
2724         bool allOk = true;
2725
2726         log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage;
2727         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2728                 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2729
2730         return allOk;
2731 }
2732
2733 void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2734 {
2735         bool limitExceeded = false;
2736
2737         for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
2738                 limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log);
2739
2740         limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log);
2741
2742         if (limitExceeded)
2743         {
2744                 log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage;
2745                 throw tcu::NotSupportedError("one or more resource limits exceeded");
2746         }
2747 }
2748
2749 } // Functional
2750 } // gles31
2751 } // deqp