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