xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fProgramInterfaceQueryTests.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 tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fProgramInterfaceQueryTests.hpp"
25 #include "es31fProgramInterfaceQueryTestCase.hpp"
26 #include "es31fProgramInterfaceDefinition.hpp"
27 #include "es31fProgramInterfaceDefinitionUtil.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuStringTemplate.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "gluVarTypeUtil.hpp"
32 #include "gluStrUtil.hpp"
33 #include "gluContextInfo.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36 #include "deRandom.hpp"
37 #include "deString.h"
38 #include "deStringUtil.hpp"
39 #include "deSharedPtr.hpp"
40 #include "deUniquePtr.hpp"
41 #include "deSTLUtil.hpp"
42 #include "deArrayUtil.hpp"
43 
44 #include <set>
45 #include <map>
46 
47 namespace deqp
48 {
49 namespace gles31
50 {
51 namespace Functional
52 {
53 namespace
54 {
55 
getTypeSize(glu::DataType type)56 static int getTypeSize(glu::DataType type)
57 {
58     if (type == glu::TYPE_FLOAT)
59         return 4;
60     else if (type == glu::TYPE_INT || type == glu::TYPE_UINT)
61         return 4;
62     else if (type == glu::TYPE_BOOL)
63         return 4; // uint
64 
65     DE_ASSERT(false);
66     return 0;
67 }
68 
getVarTypeSize(const glu::VarType & type)69 static int getVarTypeSize(const glu::VarType &type)
70 {
71     if (type.isBasicType())
72         return glu::getDataTypeScalarSize(type.getBasicType()) *
73                getTypeSize(glu::getDataTypeScalarType(type.getBasicType()));
74     else if (type.isStructType())
75     {
76         int size = 0;
77         for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
78             size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType());
79         return size;
80     }
81     else if (type.isArrayType())
82     {
83         if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY)
84             return getVarTypeSize(type.getElementType());
85         else
86             return type.getArraySize() * getVarTypeSize(type.getElementType());
87     }
88     else
89     {
90         DE_ASSERT(false);
91         return 0;
92     }
93 }
94 
convertGLTypeNameToTestName(const char * glName)95 static std::string convertGLTypeNameToTestName(const char *glName)
96 {
97     // vectors and matrices are fine as is
98     {
99         if (deStringBeginsWith(glName, "vec") == true || deStringBeginsWith(glName, "ivec") == true ||
100             deStringBeginsWith(glName, "uvec") == true || deStringBeginsWith(glName, "bvec") == true ||
101             deStringBeginsWith(glName, "mat") == true)
102             return std::string(glName);
103     }
104 
105     // convert camel case to use underscore
106     {
107         std::ostringstream buf;
108         std::istringstream name(glName);
109         bool mergeNextToken        = false;
110         bool previousTokenWasDigit = false;
111 
112         while (!name.eof())
113         {
114             std::ostringstream token;
115 
116             while (name.peek() != EOF)
117             {
118                 if ((de::isDigit((char)name.peek()) || de::isUpper((char)name.peek())) && token.tellp())
119                     break;
120 
121                 token << de::toLower((char)name.get());
122             }
123 
124             if (buf.str().empty() || mergeNextToken)
125                 buf << token.str();
126             else
127                 buf << '_' << token.str();
128 
129             // Single char causes next char to be merged (don't split initialisms or acronyms) unless it is 'D' after a number (split to ..._2d_acronym_aa
130             mergeNextToken = false;
131             if (token.tellp() == (std::streamoff)1)
132             {
133                 if (!previousTokenWasDigit || token.str()[0] != 'd')
134                     mergeNextToken = true;
135 
136                 previousTokenWasDigit = de::isDigit(token.str()[0]);
137             }
138             else
139                 previousTokenWasDigit = false;
140         }
141 
142         return buf.str();
143     }
144 }
145 
getProgramInterfaceGLEnum(ProgramInterface interface)146 static glw::GLenum getProgramInterfaceGLEnum(ProgramInterface interface)
147 {
148     static const glw::GLenum s_enums[] = {
149         GL_UNIFORM,                    // PROGRAMINTERFACE_UNIFORM
150         GL_UNIFORM_BLOCK,              // PROGRAMINTERFACE_UNIFORM_BLOCK
151         GL_ATOMIC_COUNTER_BUFFER,      // PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER
152         GL_PROGRAM_INPUT,              // PROGRAMINTERFACE_PROGRAM_INPUT
153         GL_PROGRAM_OUTPUT,             // PROGRAMINTERFACE_PROGRAM_OUTPUT
154         GL_TRANSFORM_FEEDBACK_VARYING, // PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING
155         GL_BUFFER_VARIABLE,            // PROGRAMINTERFACE_BUFFER_VARIABLE
156         GL_SHADER_STORAGE_BLOCK,       // PROGRAMINTERFACE_SHADER_STORAGE_BLOCK
157     };
158 
159     return de::getSizedArrayElement<PROGRAMINTERFACE_LAST>(s_enums, interface);
160 }
161 
getShaderMaskFirstStage(uint32_t mask)162 static glu::ShaderType getShaderMaskFirstStage(uint32_t mask)
163 {
164     if (mask & (1u << glu::SHADERTYPE_COMPUTE))
165         return glu::SHADERTYPE_COMPUTE;
166 
167     if (mask & (1u << glu::SHADERTYPE_VERTEX))
168         return glu::SHADERTYPE_VERTEX;
169 
170     if (mask & (1u << glu::SHADERTYPE_TESSELLATION_CONTROL))
171         return glu::SHADERTYPE_TESSELLATION_CONTROL;
172 
173     if (mask & (1u << glu::SHADERTYPE_TESSELLATION_EVALUATION))
174         return glu::SHADERTYPE_TESSELLATION_EVALUATION;
175 
176     if (mask & (1u << glu::SHADERTYPE_GEOMETRY))
177         return glu::SHADERTYPE_GEOMETRY;
178 
179     if (mask & (1u << glu::SHADERTYPE_FRAGMENT))
180         return glu::SHADERTYPE_FRAGMENT;
181 
182     DE_ASSERT(false);
183     return glu::SHADERTYPE_LAST;
184 }
185 
getShaderMaskLastStage(uint32_t mask)186 static glu::ShaderType getShaderMaskLastStage(uint32_t mask)
187 {
188     if (mask & (1u << glu::SHADERTYPE_FRAGMENT))
189         return glu::SHADERTYPE_FRAGMENT;
190 
191     if (mask & (1u << glu::SHADERTYPE_GEOMETRY))
192         return glu::SHADERTYPE_GEOMETRY;
193 
194     if (mask & (1u << glu::SHADERTYPE_TESSELLATION_EVALUATION))
195         return glu::SHADERTYPE_TESSELLATION_EVALUATION;
196 
197     if (mask & (1u << glu::SHADERTYPE_TESSELLATION_CONTROL))
198         return glu::SHADERTYPE_TESSELLATION_CONTROL;
199 
200     if (mask & (1u << glu::SHADERTYPE_VERTEX))
201         return glu::SHADERTYPE_VERTEX;
202 
203     if (mask & (1u << glu::SHADERTYPE_COMPUTE))
204         return glu::SHADERTYPE_COMPUTE;
205 
206     DE_ASSERT(false);
207     return glu::SHADERTYPE_LAST;
208 }
209 
checkSupport(Context & ctx)210 static bool checkSupport(Context &ctx)
211 {
212     auto ctxType = ctx.getRenderContext().getType();
213     return contextSupports(ctxType, glu::ApiType::es(3, 2)) || contextSupports(ctxType, glu::ApiType::core(4, 5));
214 }
215 
specializeShader(Context & context,const char * code)216 static std::string specializeShader(Context &context, const char *code)
217 {
218     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(context.getRenderContext().getType());
219     std::map<std::string, std::string> specializationMap;
220 
221     specializationMap["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
222 
223     return tcu::StringTemplate(code).specialize(specializationMap);
224 }
225 
226 namespace ResourceDefinition
227 {
228 
229 class Node
230 {
231 public:
232     enum NodeType
233     {
234         TYPE_PROGRAM = 0,
235         TYPE_SHADER,
236         TYPE_DEFAULT_BLOCK,
237         TYPE_VARIABLE,
238         TYPE_INTERFACE_BLOCK,
239         TYPE_ARRAY_ELEMENT,
240         TYPE_STRUCT_MEMBER,
241         TYPE_STORAGE_QUALIFIER,
242         TYPE_LAYOUT_QUALIFIER,
243         TYPE_SHADER_SET,
244         TYPE_INTERPOLATION_QUALIFIER,
245         TYPE_TRANSFORM_FEEDBACK_TARGET,
246 
247         TYPE_LAST
248     };
249 
250     typedef de::SharedPtr<const Node> SharedPtr;
251 
Node(NodeType type,const SharedPtr & enclosingNode)252     Node(NodeType type, const SharedPtr &enclosingNode) : m_type(type), m_enclosingNode(enclosingNode)
253     {
254         DE_ASSERT(type < TYPE_LAST);
255     }
~Node(void)256     virtual ~Node(void)
257     {
258     }
259 
getEnclosingNode(void) const260     inline const Node *getEnclosingNode(void) const
261     {
262         return m_enclosingNode.get();
263     }
getType(void) const264     inline NodeType getType(void) const
265     {
266         return m_type;
267     }
268 
269 private:
270     const NodeType m_type;
271     const SharedPtr m_enclosingNode;
272 };
273 
274 class Program : public Node
275 {
276 public:
Program(bool separable=false)277     Program(bool separable = false) : Node(TYPE_PROGRAM, SharedPtr()), m_separable(separable)
278     {
279     }
280 
281     const bool m_separable;
282 };
283 
284 class Shader : public Node
285 {
286 public:
Shader(const SharedPtr & enclosingNode,glu::ShaderType type,glu::GLSLVersion version)287     Shader(const SharedPtr &enclosingNode, glu::ShaderType type, glu::GLSLVersion version)
288         : Node(TYPE_SHADER, enclosingNode)
289         , m_type(type)
290         , m_version(version)
291     {
292         DE_ASSERT(enclosingNode->getType() == TYPE_PROGRAM);
293         DE_ASSERT(type < glu::SHADERTYPE_LAST);
294     }
295 
296     const glu::ShaderType m_type;
297     const glu::GLSLVersion m_version;
298 };
299 
300 class DefaultBlock : public Node
301 {
302 public:
DefaultBlock(const SharedPtr & enclosing)303     DefaultBlock(const SharedPtr &enclosing) : Node(TYPE_DEFAULT_BLOCK, enclosing)
304     {
305         // enclosed by the shader
306         DE_ASSERT(enclosing->getType() == TYPE_SHADER || enclosing->getType() == TYPE_SHADER_SET);
307     }
308 };
309 
310 class StorageQualifier : public Node
311 {
312 public:
StorageQualifier(const SharedPtr & enclosing,glu::Storage storage)313     StorageQualifier(const SharedPtr &enclosing, glu::Storage storage)
314         : Node(TYPE_STORAGE_QUALIFIER, enclosing)
315         , m_storage(storage)
316     {
317         // not a part of any block
318         DE_ASSERT(enclosing->getType() == TYPE_DEFAULT_BLOCK);
319     }
320 
321     const glu::Storage m_storage;
322 };
323 
324 class Variable : public Node
325 {
326 public:
Variable(const SharedPtr & enclosing,glu::DataType dataType)327     Variable(const SharedPtr &enclosing, glu::DataType dataType) : Node(TYPE_VARIABLE, enclosing), m_dataType(dataType)
328     {
329         DE_ASSERT(enclosing->getType() == TYPE_STORAGE_QUALIFIER || enclosing->getType() == TYPE_LAYOUT_QUALIFIER ||
330                   enclosing->getType() == TYPE_INTERPOLATION_QUALIFIER ||
331                   enclosing->getType() == TYPE_INTERFACE_BLOCK || enclosing->getType() == TYPE_ARRAY_ELEMENT ||
332                   enclosing->getType() == TYPE_STRUCT_MEMBER || enclosing->getType() == TYPE_TRANSFORM_FEEDBACK_TARGET);
333     }
334 
335     const glu::DataType m_dataType;
336 };
337 
338 class InterfaceBlock : public Node
339 {
340 public:
InterfaceBlock(const SharedPtr & enclosing,bool named)341     InterfaceBlock(const SharedPtr &enclosing, bool named) : Node(TYPE_INTERFACE_BLOCK, enclosing), m_named(named)
342     {
343         // Must be storage qualified
344         const Node *storageNode = enclosing.get();
345         while (storageNode->getType() == TYPE_ARRAY_ELEMENT || storageNode->getType() == TYPE_LAYOUT_QUALIFIER)
346         {
347             storageNode = storageNode->getEnclosingNode();
348         }
349 
350         DE_ASSERT(storageNode->getType() == TYPE_STORAGE_QUALIFIER);
351         DE_UNREF(storageNode);
352     }
353 
354     const bool m_named;
355 };
356 
357 class ArrayElement : public Node
358 {
359 public:
ArrayElement(const SharedPtr & enclosing,int arraySize=DEFAULT_SIZE)360     ArrayElement(const SharedPtr &enclosing, int arraySize = DEFAULT_SIZE)
361         : Node(TYPE_ARRAY_ELEMENT, enclosing)
362         , m_arraySize(arraySize)
363     {
364         DE_ASSERT(enclosing->getType() == TYPE_STORAGE_QUALIFIER || enclosing->getType() == TYPE_LAYOUT_QUALIFIER ||
365                   enclosing->getType() == TYPE_INTERPOLATION_QUALIFIER ||
366                   enclosing->getType() == TYPE_INTERFACE_BLOCK || enclosing->getType() == TYPE_ARRAY_ELEMENT ||
367                   enclosing->getType() == TYPE_STRUCT_MEMBER || enclosing->getType() == TYPE_TRANSFORM_FEEDBACK_TARGET);
368     }
369 
370     const int m_arraySize;
371 
372     enum
373     {
374         DEFAULT_SIZE  = -1,
375         UNSIZED_ARRAY = -2,
376     };
377 };
378 
379 class StructMember : public Node
380 {
381 public:
StructMember(const SharedPtr & enclosing)382     StructMember(const SharedPtr &enclosing) : Node(TYPE_STRUCT_MEMBER, enclosing)
383     {
384         DE_ASSERT(enclosing->getType() == TYPE_STORAGE_QUALIFIER || enclosing->getType() == TYPE_LAYOUT_QUALIFIER ||
385                   enclosing->getType() == TYPE_INTERPOLATION_QUALIFIER ||
386                   enclosing->getType() == TYPE_INTERFACE_BLOCK || enclosing->getType() == TYPE_ARRAY_ELEMENT ||
387                   enclosing->getType() == TYPE_STRUCT_MEMBER || enclosing->getType() == TYPE_TRANSFORM_FEEDBACK_TARGET);
388     }
389 };
390 
391 class LayoutQualifier : public Node
392 {
393 public:
LayoutQualifier(const SharedPtr & enclosing,const glu::Layout & layout)394     LayoutQualifier(const SharedPtr &enclosing, const glu::Layout &layout)
395         : Node(TYPE_LAYOUT_QUALIFIER, enclosing)
396         , m_layout(layout)
397     {
398         DE_ASSERT(enclosing->getType() == TYPE_STORAGE_QUALIFIER || enclosing->getType() == TYPE_LAYOUT_QUALIFIER ||
399                   enclosing->getType() == TYPE_INTERPOLATION_QUALIFIER || enclosing->getType() == TYPE_DEFAULT_BLOCK ||
400                   enclosing->getType() == TYPE_INTERFACE_BLOCK);
401     }
402 
403     const glu::Layout m_layout;
404 };
405 
406 class InterpolationQualifier : public Node
407 {
408 public:
InterpolationQualifier(const SharedPtr & enclosing,const glu::Interpolation & interpolation)409     InterpolationQualifier(const SharedPtr &enclosing, const glu::Interpolation &interpolation)
410         : Node(TYPE_INTERPOLATION_QUALIFIER, enclosing)
411         , m_interpolation(interpolation)
412     {
413         DE_ASSERT(enclosing->getType() == TYPE_STORAGE_QUALIFIER || enclosing->getType() == TYPE_LAYOUT_QUALIFIER ||
414                   enclosing->getType() == TYPE_INTERPOLATION_QUALIFIER || enclosing->getType() == TYPE_DEFAULT_BLOCK ||
415                   enclosing->getType() == TYPE_INTERFACE_BLOCK);
416     }
417 
418     const glu::Interpolation m_interpolation;
419 };
420 
421 class ShaderSet : public Node
422 {
423 public:
424     ShaderSet(const SharedPtr &enclosing, glu::GLSLVersion version);
425     ShaderSet(const SharedPtr &enclosing, glu::GLSLVersion version, uint32_t stagesPresentBits,
426               uint32_t stagesReferencingBits);
427 
428     void setStage(glu::ShaderType type, bool referencing);
429     bool isStagePresent(glu::ShaderType stage) const;
430     bool isStageReferencing(glu::ShaderType stage) const;
431 
432     uint32_t getReferencingMask(void) const;
433 
434     const glu::GLSLVersion m_version;
435 
436 private:
437     bool m_stagePresent[glu::SHADERTYPE_LAST];
438     bool m_stageReferencing[glu::SHADERTYPE_LAST];
439 };
440 
ShaderSet(const SharedPtr & enclosing,glu::GLSLVersion version)441 ShaderSet::ShaderSet(const SharedPtr &enclosing, glu::GLSLVersion version)
442     : Node(TYPE_SHADER_SET, enclosing)
443     , m_version(version)
444 {
445     DE_ASSERT(enclosing->getType() == TYPE_PROGRAM);
446 
447     deMemset(m_stagePresent, 0, sizeof(m_stagePresent));
448     deMemset(m_stageReferencing, 0, sizeof(m_stageReferencing));
449 }
450 
ShaderSet(const SharedPtr & enclosing,glu::GLSLVersion version,uint32_t stagesPresentBits,uint32_t stagesReferencingBits)451 ShaderSet::ShaderSet(const SharedPtr &enclosing, glu::GLSLVersion version, uint32_t stagesPresentBits,
452                      uint32_t stagesReferencingBits)
453     : Node(TYPE_SHADER_SET, enclosing)
454     , m_version(version)
455 {
456     for (uint32_t stageNdx = 0; stageNdx < glu::SHADERTYPE_LAST; ++stageNdx)
457     {
458         const uint32_t stageMask    = (1u << stageNdx);
459         const bool stagePresent     = (stagesPresentBits & stageMask) != 0;
460         const bool stageReferencing = (stagesReferencingBits & stageMask) != 0;
461 
462         DE_ASSERT(stagePresent || !stageReferencing);
463 
464         m_stagePresent[stageNdx]     = stagePresent;
465         m_stageReferencing[stageNdx] = stageReferencing;
466     }
467 }
468 
setStage(glu::ShaderType type,bool referencing)469 void ShaderSet::setStage(glu::ShaderType type, bool referencing)
470 {
471     DE_ASSERT(type < glu::SHADERTYPE_LAST);
472     m_stagePresent[type]     = true;
473     m_stageReferencing[type] = referencing;
474 }
475 
isStagePresent(glu::ShaderType stage) const476 bool ShaderSet::isStagePresent(glu::ShaderType stage) const
477 {
478     DE_ASSERT(stage < glu::SHADERTYPE_LAST);
479     return m_stagePresent[stage];
480 }
481 
isStageReferencing(glu::ShaderType stage) const482 bool ShaderSet::isStageReferencing(glu::ShaderType stage) const
483 {
484     DE_ASSERT(stage < glu::SHADERTYPE_LAST);
485     return m_stageReferencing[stage];
486 }
487 
getReferencingMask(void) const488 uint32_t ShaderSet::getReferencingMask(void) const
489 {
490     uint32_t mask = 0;
491     for (uint32_t stage = 0; stage < glu::SHADERTYPE_LAST; ++stage)
492     {
493         if (m_stageReferencing[stage])
494             mask |= (1u << stage);
495     }
496     return mask;
497 }
498 
499 class TransformFeedbackTarget : public Node
500 {
501 public:
TransformFeedbackTarget(const SharedPtr & enclosing,const char * builtinVarName=DE_NULL)502     TransformFeedbackTarget(const SharedPtr &enclosing, const char *builtinVarName = DE_NULL)
503         : Node(TYPE_TRANSFORM_FEEDBACK_TARGET, enclosing)
504         , m_builtinVarName(builtinVarName)
505     {
506     }
507 
508     const char *const m_builtinVarName;
509 };
510 
511 } // namespace ResourceDefinition
512 
getDataTypeDefaultPrecision(const glu::DataType & type)513 static glu::Precision getDataTypeDefaultPrecision(const glu::DataType &type)
514 {
515     if (glu::isDataTypeBoolOrBVec(type))
516         return glu::PRECISION_LAST;
517     else if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type))
518         return glu::PRECISION_HIGHP;
519     else if (glu::isDataTypeSampler(type))
520         return glu::PRECISION_HIGHP;
521     else if (glu::isDataTypeImage(type))
522         return glu::PRECISION_HIGHP;
523     else if (type == glu::TYPE_UINT_ATOMIC_COUNTER)
524         return glu::PRECISION_HIGHP;
525 
526     DE_ASSERT(false);
527     return glu::PRECISION_LAST;
528 }
529 
generateProgramDefinitionFromResource(const ResourceDefinition::Node * resource)530 static de::MovePtr<ProgramInterfaceDefinition::Program> generateProgramDefinitionFromResource(
531     const ResourceDefinition::Node *resource)
532 {
533     de::MovePtr<ProgramInterfaceDefinition::Program> program(new ProgramInterfaceDefinition::Program());
534     const ResourceDefinition::Node *head = resource;
535 
536     if (head->getType() == ResourceDefinition::Node::TYPE_VARIABLE)
537     {
538         DE_ASSERT(dynamic_cast<const ResourceDefinition::Variable *>(resource));
539 
540         enum BindingType
541         {
542             BINDING_VARIABLE,
543             BINDING_INTERFACE_BLOCK,
544             BINDING_DEFAULT_BLOCK
545         };
546 
547         int structNdx                 = 0;
548         int autoAssignArraySize       = 0;
549         const glu::DataType basicType = static_cast<const ResourceDefinition::Variable *>(resource)->m_dataType;
550         BindingType boundObject       = BINDING_VARIABLE;
551         glu::VariableDeclaration variable(glu::VarType(basicType, getDataTypeDefaultPrecision(basicType)), "target");
552         glu::InterfaceBlock interfaceBlock;
553         ProgramInterfaceDefinition::DefaultBlock defaultBlock;
554         std::vector<std::string> feedbackTargetVaryingPath;
555         bool feedbackTargetSet = false;
556 
557         // image specific
558         if (glu::isDataTypeImage(basicType))
559         {
560             variable.memoryAccessQualifierBits |= glu::MEMORYACCESSQUALIFIER_READONLY_BIT;
561             variable.layout.binding = 1;
562 
563             if (basicType >= glu::TYPE_IMAGE_2D && basicType <= glu::TYPE_IMAGE_3D)
564                 variable.layout.format = glu::FORMATLAYOUT_RGBA8;
565             else if (basicType >= glu::TYPE_INT_IMAGE_2D && basicType <= glu::TYPE_INT_IMAGE_3D)
566                 variable.layout.format = glu::FORMATLAYOUT_RGBA8I;
567             else if (basicType >= glu::TYPE_UINT_IMAGE_2D && basicType <= glu::TYPE_UINT_IMAGE_3D)
568                 variable.layout.format = glu::FORMATLAYOUT_RGBA8UI;
569             else
570                 DE_ASSERT(false);
571         }
572 
573         // atomic counter specific
574         if (basicType == glu::TYPE_UINT_ATOMIC_COUNTER)
575             variable.layout.binding = 1;
576 
577         for (head = head->getEnclosingNode(); head; head = head->getEnclosingNode())
578         {
579             if (head->getType() == ResourceDefinition::Node::TYPE_STORAGE_QUALIFIER)
580             {
581                 const ResourceDefinition::StorageQualifier *qualifier =
582                     static_cast<const ResourceDefinition::StorageQualifier *>(head);
583 
584                 DE_ASSERT(dynamic_cast<const ResourceDefinition::StorageQualifier *>(head));
585 
586                 if (boundObject == BINDING_VARIABLE)
587                 {
588                     DE_ASSERT(variable.storage == glu::STORAGE_LAST);
589                     variable.storage = qualifier->m_storage;
590                 }
591                 else if (boundObject == BINDING_INTERFACE_BLOCK)
592                 {
593                     DE_ASSERT(interfaceBlock.storage == glu::STORAGE_LAST);
594                     interfaceBlock.storage = qualifier->m_storage;
595                 }
596                 else
597                     DE_ASSERT(false);
598             }
599             else if (head->getType() == ResourceDefinition::Node::TYPE_LAYOUT_QUALIFIER)
600             {
601                 const ResourceDefinition::LayoutQualifier *qualifier =
602                     static_cast<const ResourceDefinition::LayoutQualifier *>(head);
603                 glu::Layout *targetLayout = DE_NULL;
604 
605                 DE_ASSERT(dynamic_cast<const ResourceDefinition::LayoutQualifier *>(head));
606 
607                 if (boundObject == BINDING_VARIABLE)
608                     targetLayout = &variable.layout;
609                 else if (boundObject == BINDING_INTERFACE_BLOCK)
610                     targetLayout = &interfaceBlock.layout;
611                 else
612                     DE_ASSERT(false);
613 
614                 if (qualifier->m_layout.location != -1)
615                     targetLayout->location = qualifier->m_layout.location;
616 
617                 if (qualifier->m_layout.binding != -1)
618                     targetLayout->binding = qualifier->m_layout.binding;
619 
620                 if (qualifier->m_layout.offset != -1)
621                     targetLayout->offset = qualifier->m_layout.offset;
622 
623                 if (qualifier->m_layout.format != glu::FORMATLAYOUT_LAST)
624                     targetLayout->format = qualifier->m_layout.format;
625 
626                 if (qualifier->m_layout.matrixOrder != glu::MATRIXORDER_LAST)
627                     targetLayout->matrixOrder = qualifier->m_layout.matrixOrder;
628             }
629             else if (head->getType() == ResourceDefinition::Node::TYPE_INTERPOLATION_QUALIFIER)
630             {
631                 const ResourceDefinition::InterpolationQualifier *qualifier =
632                     static_cast<const ResourceDefinition::InterpolationQualifier *>(head);
633 
634                 DE_ASSERT(dynamic_cast<const ResourceDefinition::InterpolationQualifier *>(head));
635 
636                 if (boundObject == BINDING_VARIABLE)
637                     variable.interpolation = qualifier->m_interpolation;
638                 else
639                     DE_ASSERT(false);
640             }
641             else if (head->getType() == ResourceDefinition::Node::TYPE_ARRAY_ELEMENT)
642             {
643                 DE_ASSERT(dynamic_cast<const ResourceDefinition::ArrayElement *>(head));
644 
645                 const ResourceDefinition::ArrayElement *arrayElement =
646                     static_cast<const ResourceDefinition::ArrayElement *>(head);
647                 int arraySize;
648 
649                 // Vary array size per level
650                 if (arrayElement->m_arraySize == ResourceDefinition::ArrayElement::DEFAULT_SIZE)
651                 {
652                     if (--autoAssignArraySize <= 1)
653                         autoAssignArraySize = 3;
654 
655                     arraySize = autoAssignArraySize;
656                 }
657                 else if (arrayElement->m_arraySize == ResourceDefinition::ArrayElement::UNSIZED_ARRAY)
658                     arraySize = glu::VarType::UNSIZED_ARRAY;
659                 else
660                     arraySize = arrayElement->m_arraySize;
661 
662                 if (boundObject == BINDING_VARIABLE)
663                     variable.varType = glu::VarType(variable.varType, arraySize);
664                 else if (boundObject == BINDING_INTERFACE_BLOCK)
665                     interfaceBlock.dimensions.push_back(arraySize);
666                 else
667                     DE_ASSERT(false);
668 
669                 if (feedbackTargetSet)
670                     feedbackTargetVaryingPath.back().append("[0]");
671             }
672             else if (head->getType() == ResourceDefinition::Node::TYPE_STRUCT_MEMBER)
673             {
674                 DE_ASSERT(dynamic_cast<const ResourceDefinition::StructMember *>(head));
675                 DE_ASSERT(boundObject == BINDING_VARIABLE);
676 
677                 // Struct members cannot contain any qualifiers except precision
678                 DE_ASSERT(variable.interpolation == glu::INTERPOLATION_LAST);
679                 DE_ASSERT(variable.layout == glu::Layout());
680                 DE_ASSERT(variable.memoryAccessQualifierBits == 0);
681                 DE_ASSERT(variable.storage == glu::STORAGE_LAST);
682 
683                 {
684                     glu::StructType *structPtr =
685                         new glu::StructType(("StructType" + de::toString(structNdx++)).c_str());
686                     structPtr->addMember(variable.name.c_str(), variable.varType);
687 
688                     variable = glu::VariableDeclaration(glu::VarType(structPtr), "target");
689                 }
690 
691                 if (feedbackTargetSet)
692                     feedbackTargetVaryingPath.push_back("target");
693             }
694             else if (head->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK)
695             {
696                 DE_ASSERT(dynamic_cast<const ResourceDefinition::InterfaceBlock *>(head));
697                 DE_ASSERT(boundObject == BINDING_VARIABLE);
698 
699                 const bool named = static_cast<const ResourceDefinition::InterfaceBlock *>(head)->m_named;
700 
701                 boundObject = BINDING_INTERFACE_BLOCK;
702 
703                 interfaceBlock.interfaceName = "TargetInterface";
704                 interfaceBlock.instanceName  = (named) ? ("targetInstance") : ("");
705                 interfaceBlock.variables.push_back(variable);
706 
707                 if (feedbackTargetSet && !interfaceBlock.instanceName.empty())
708                     feedbackTargetVaryingPath.push_back(interfaceBlock.interfaceName);
709             }
710             else if (head->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK)
711             {
712                 DE_ASSERT(dynamic_cast<const ResourceDefinition::DefaultBlock *>(head));
713                 DE_ASSERT(boundObject == BINDING_VARIABLE || boundObject == BINDING_INTERFACE_BLOCK);
714 
715                 if (boundObject == BINDING_VARIABLE)
716                     defaultBlock.variables.push_back(variable);
717                 else if (boundObject == BINDING_INTERFACE_BLOCK)
718                     defaultBlock.interfaceBlocks.push_back(interfaceBlock);
719                 else
720                     DE_ASSERT(false);
721 
722                 boundObject = BINDING_DEFAULT_BLOCK;
723             }
724             else if (head->getType() == ResourceDefinition::Node::TYPE_SHADER)
725             {
726                 DE_ASSERT(dynamic_cast<const ResourceDefinition::Shader *>(head));
727 
728                 const ResourceDefinition::Shader *shaderDef = static_cast<const ResourceDefinition::Shader *>(head);
729                 ProgramInterfaceDefinition::Shader *shader =
730                     program->addShader(shaderDef->m_type, shaderDef->m_version);
731 
732                 shader->getDefaultBlock() = defaultBlock;
733             }
734             else if (head->getType() == ResourceDefinition::Node::TYPE_SHADER_SET)
735             {
736                 DE_ASSERT(dynamic_cast<const ResourceDefinition::ShaderSet *>(head));
737 
738                 const ResourceDefinition::ShaderSet *shaderDef =
739                     static_cast<const ResourceDefinition::ShaderSet *>(head);
740 
741                 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
742                 {
743                     if (shaderDef->isStagePresent((glu::ShaderType)shaderType))
744                     {
745                         ProgramInterfaceDefinition::Shader *shader =
746                             program->addShader((glu::ShaderType)shaderType, shaderDef->m_version);
747 
748                         if (shaderDef->isStageReferencing((glu::ShaderType)shaderType))
749                             shader->getDefaultBlock() = defaultBlock;
750                     }
751                 }
752             }
753             else if (head->getType() == ResourceDefinition::Node::TYPE_PROGRAM)
754             {
755                 DE_ASSERT(dynamic_cast<const ResourceDefinition::Program *>(head));
756 
757                 const ResourceDefinition::Program *programDef = static_cast<const ResourceDefinition::Program *>(head);
758 
759                 program->setSeparable(programDef->m_separable);
760 
761                 DE_ASSERT(feedbackTargetSet == !feedbackTargetVaryingPath.empty());
762                 if (!feedbackTargetVaryingPath.empty())
763                 {
764                     std::ostringstream buf;
765 
766                     for (std::vector<std::string>::reverse_iterator it = feedbackTargetVaryingPath.rbegin();
767                          it != feedbackTargetVaryingPath.rend(); ++it)
768                     {
769                         if (it != feedbackTargetVaryingPath.rbegin())
770                             buf << ".";
771                         buf << *it;
772                     }
773 
774                     program->addTransformFeedbackVarying(buf.str());
775                     program->setTransformFeedbackMode(GL_INTERLEAVED_ATTRIBS);
776                 }
777                 break;
778             }
779             else if (head->getType() == ResourceDefinition::Node::TYPE_TRANSFORM_FEEDBACK_TARGET)
780             {
781                 DE_ASSERT(dynamic_cast<const ResourceDefinition::TransformFeedbackTarget *>(head));
782 
783                 const ResourceDefinition::TransformFeedbackTarget *feedbackTarget =
784                     static_cast<const ResourceDefinition::TransformFeedbackTarget *>(head);
785 
786                 DE_ASSERT(feedbackTarget->m_builtinVarName == DE_NULL);
787                 DE_UNREF(feedbackTarget);
788 
789                 feedbackTargetSet = true;
790                 feedbackTargetVaryingPath.push_back(variable.name);
791             }
792             else
793             {
794                 DE_ASSERT(false);
795                 break;
796             }
797         }
798     }
799     else if (head->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK ||
800              head->getType() == ResourceDefinition::Node::TYPE_TRANSFORM_FEEDBACK_TARGET)
801     {
802         const char *feedbackTargetVaryingName = DE_NULL;
803 
804         // empty default block
805 
806         for (; head; head = head->getEnclosingNode())
807         {
808             if (head->getType() == ResourceDefinition::Node::TYPE_SHADER)
809             {
810                 DE_ASSERT(dynamic_cast<const ResourceDefinition::Shader *>(head));
811 
812                 const ResourceDefinition::Shader *shaderDef = static_cast<const ResourceDefinition::Shader *>(head);
813 
814                 program->addShader(shaderDef->m_type, shaderDef->m_version);
815             }
816             else if (head->getType() == ResourceDefinition::Node::TYPE_SHADER_SET)
817             {
818                 DE_ASSERT(dynamic_cast<const ResourceDefinition::ShaderSet *>(head));
819 
820                 const ResourceDefinition::ShaderSet *shaderDef =
821                     static_cast<const ResourceDefinition::ShaderSet *>(head);
822 
823                 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
824                     if (shaderDef->isStagePresent((glu::ShaderType)shaderType))
825                         program->addShader((glu::ShaderType)shaderType, shaderDef->m_version);
826             }
827             else if (head->getType() == ResourceDefinition::Node::TYPE_PROGRAM)
828             {
829                 DE_ASSERT(dynamic_cast<const ResourceDefinition::Program *>(head));
830 
831                 const ResourceDefinition::Program *programDef = static_cast<const ResourceDefinition::Program *>(head);
832 
833                 program->setSeparable(programDef->m_separable);
834                 if (feedbackTargetVaryingName)
835                 {
836                     program->addTransformFeedbackVarying(std::string(feedbackTargetVaryingName));
837                     program->setTransformFeedbackMode(GL_INTERLEAVED_ATTRIBS);
838                 }
839                 break;
840             }
841             else if (head->getType() == ResourceDefinition::Node::TYPE_TRANSFORM_FEEDBACK_TARGET)
842             {
843                 DE_ASSERT(dynamic_cast<const ResourceDefinition::TransformFeedbackTarget *>(head));
844 
845                 const ResourceDefinition::TransformFeedbackTarget *feedbackTarget =
846                     static_cast<const ResourceDefinition::TransformFeedbackTarget *>(head);
847 
848                 DE_ASSERT(feedbackTarget->m_builtinVarName != DE_NULL);
849 
850                 feedbackTargetVaryingName = feedbackTarget->m_builtinVarName;
851             }
852             else if (head->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK)
853             {
854             }
855             else
856             {
857                 DE_ASSERT(false);
858                 break;
859             }
860         }
861     }
862 
863     if (program->hasStage(glu::SHADERTYPE_GEOMETRY))
864         program->setGeometryNumOutputVertices(1);
865     if (program->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
866         program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
867         program->setTessellationNumOutputPatchVertices(1);
868 
869     return program;
870 }
871 
checkAndLogProgram(const glu::ShaderProgram & program,const ProgramInterfaceDefinition::Program * programDefinition,const glw::Functions & gl,tcu::TestLog & log)872 static void checkAndLogProgram(const glu::ShaderProgram &program,
873                                const ProgramInterfaceDefinition::Program *programDefinition, const glw::Functions &gl,
874                                tcu::TestLog &log)
875 {
876     const tcu::ScopedLogSection section(log, "Program", "Program");
877 
878     log << program;
879     if (!program.isOk())
880     {
881         log << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits"
882             << tcu::TestLog::EndMessage;
883         checkProgramResourceUsage(programDefinition, gl, log);
884 
885         // within limits
886         throw tcu::TestError("could not build program");
887     }
888 }
889 
890 // Resource list query case
891 
892 class ResourceListTestCase : public TestCase
893 {
894 public:
895     ResourceListTestCase(Context &context, const ResourceDefinition::Node::SharedPtr &targetResource,
896                          ProgramInterface interface, const char *name = DE_NULL);
897     ~ResourceListTestCase(void);
898 
899 protected:
900     void init(void);
901     void deinit(void);
902     IterateResult iterate(void);
903 
904     void queryResourceList(std::vector<std::string> &dst, glw::GLuint program);
905     bool verifyResourceList(const std::vector<std::string> &resourceList,
906                             const std::vector<std::string> &expectedResources);
907     bool verifyResourceIndexQuery(const std::vector<std::string> &resourceList,
908                                   const std::vector<std::string> &referenceResources, glw::GLuint program);
909     bool verifyMaxNameLength(const std::vector<std::string> &referenceResourceList, glw::GLuint program);
910 
911     static std::string genTestCaseName(ProgramInterface interface, const ResourceDefinition::Node *);
912     static bool isArrayedInterface(ProgramInterface interface, uint32_t stageBits);
913 
914     const ProgramInterface m_programInterface;
915     ResourceDefinition::Node::SharedPtr m_targetResource;
916     ProgramInterfaceDefinition::Program *m_programDefinition;
917 };
918 
ResourceListTestCase(Context & context,const ResourceDefinition::Node::SharedPtr & targetResource,ProgramInterface interface,const char * name)919 ResourceListTestCase::ResourceListTestCase(Context &context, const ResourceDefinition::Node::SharedPtr &targetResource,
920                                            ProgramInterface interface, const char *name)
921     : TestCase(context, (name == DE_NULL) ? (genTestCaseName(interface, targetResource.get()).c_str()) : (name), "")
922     , m_programInterface(interface)
923     , m_targetResource(targetResource)
924     , m_programDefinition(DE_NULL)
925 {
926     // GL_ATOMIC_COUNTER_BUFFER: no resource names
927     DE_ASSERT(m_programInterface != PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER);
928 }
929 
~ResourceListTestCase(void)930 ResourceListTestCase::~ResourceListTestCase(void)
931 {
932     deinit();
933 }
934 
init(void)935 void ResourceListTestCase::init(void)
936 {
937     m_programDefinition           = generateProgramDefinitionFromResource(m_targetResource.get()).release();
938     const bool supportsES32orGL45 = checkSupport(m_context);
939 
940     if ((m_programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
941          m_programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION)) &&
942         !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
943     {
944         throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
945     }
946     if (m_programDefinition->hasStage(glu::SHADERTYPE_GEOMETRY) && !supportsES32orGL45 &&
947         !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
948     {
949         throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
950     }
951     if (programContainsIOBlocks(m_programDefinition) && !supportsES32orGL45 &&
952         !m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_io_blocks"))
953     {
954         throw tcu::NotSupportedError("Test requires GL_EXT_shader_io_blocks extension");
955     }
956 }
957 
deinit(void)958 void ResourceListTestCase::deinit(void)
959 {
960     m_targetResource.clear();
961 
962     delete m_programDefinition;
963     m_programDefinition = DE_NULL;
964 }
965 
iterate(void)966 ResourceListTestCase::IterateResult ResourceListTestCase::iterate(void)
967 {
968     const glu::ShaderProgram program(m_context.getRenderContext(),
969                                      generateProgramInterfaceProgramSources(m_programDefinition));
970 
971     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
972     checkAndLogProgram(program, m_programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
973 
974     // Check resource list
975     {
976         const tcu::ScopedLogSection section(m_testCtx.getLog(), "ResourceList", "Resource list");
977         std::vector<std::string> resourceList;
978         std::vector<std::string> expectedResources;
979 
980         queryResourceList(resourceList, program.getProgram());
981         expectedResources = getProgramInterfaceResourceList(m_programDefinition, m_programInterface);
982 
983         // verify the list and the expected list match
984 
985         if (!verifyResourceList(resourceList, expectedResources))
986             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid resource list");
987 
988         // verify GetProgramResourceIndex() matches the indices of the list
989 
990         if (!verifyResourceIndexQuery(resourceList, expectedResources, program.getProgram()))
991             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "GetProgramResourceIndex returned unexpected values");
992 
993         // Verify MAX_NAME_LENGTH
994         if (!verifyMaxNameLength(resourceList, program.getProgram()))
995             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "MAX_NAME_LENGTH invalid");
996     }
997 
998     return STOP;
999 }
1000 
queryResourceList(std::vector<std::string> & dst,glw::GLuint program)1001 void ResourceListTestCase::queryResourceList(std::vector<std::string> &dst, glw::GLuint program)
1002 {
1003     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
1004     const glw::GLenum programInterface = getProgramInterfaceGLEnum(m_programInterface);
1005     glw::GLint numActiveResources      = 0;
1006     glw::GLint maxNameLength           = 0;
1007     std::vector<char> buffer;
1008 
1009     m_testCtx.getLog() << tcu::TestLog::Message << "Querying " << glu::getProgramInterfaceName(programInterface)
1010                        << " interface:" << tcu::TestLog::EndMessage;
1011 
1012     gl.getProgramInterfaceiv(program, programInterface, GL_ACTIVE_RESOURCES, &numActiveResources);
1013     gl.getProgramInterfaceiv(program, programInterface, GL_MAX_NAME_LENGTH, &maxNameLength);
1014     GLU_EXPECT_NO_ERROR(gl.getError(), "query interface");
1015 
1016     m_testCtx.getLog() << tcu::TestLog::Message << "\tGL_ACTIVE_RESOURCES = " << numActiveResources << "\n"
1017                        << "\tGL_MAX_NAME_LENGTH = " << maxNameLength << tcu::TestLog::EndMessage;
1018 
1019     m_testCtx.getLog() << tcu::TestLog::Message << "Querying all active resources" << tcu::TestLog::EndMessage;
1020 
1021     buffer.resize(maxNameLength + 1, '\0');
1022 
1023     for (int resourceNdx = 0; resourceNdx < numActiveResources; ++resourceNdx)
1024     {
1025         glw::GLint written = 0;
1026 
1027         gl.getProgramResourceName(program, programInterface, resourceNdx, maxNameLength, &written, &buffer[0]);
1028         GLU_EXPECT_NO_ERROR(gl.getError(), "query resource name");
1029 
1030         dst.push_back(std::string(&buffer[0], written));
1031     }
1032 }
1033 
verifyResourceList(const std::vector<std::string> & resourceList,const std::vector<std::string> & expectedResources)1034 bool ResourceListTestCase::verifyResourceList(const std::vector<std::string> &resourceList,
1035                                               const std::vector<std::string> &expectedResources)
1036 {
1037     bool error = false;
1038 
1039     // Log and compare resource lists
1040 
1041     m_testCtx.getLog() << tcu::TestLog::Message << "GL returned resources:" << tcu::TestLog::EndMessage;
1042 
1043     for (int ndx = 0; ndx < (int)resourceList.size(); ++ndx)
1044     {
1045         // unusedZero is a uniform that may be added by
1046         // generateProgramInterfaceProgramSources.  Omit it here to avoid
1047         // confusion about the output.
1048         if (resourceList[ndx] != getUnusedZeroUniformName())
1049             m_testCtx.getLog() << tcu::TestLog::Message << "\t" << ndx << ": " << resourceList[ndx]
1050                                << tcu::TestLog::EndMessage;
1051     }
1052 
1053     m_testCtx.getLog() << tcu::TestLog::Message << "Expected list of resources:" << tcu::TestLog::EndMessage;
1054 
1055     for (int ndx = 0; ndx < (int)expectedResources.size(); ++ndx)
1056         m_testCtx.getLog() << tcu::TestLog::Message << "\t" << ndx << ": " << expectedResources[ndx]
1057                            << tcu::TestLog::EndMessage;
1058 
1059     m_testCtx.getLog() << tcu::TestLog::Message << "Verifying resource list contents." << tcu::TestLog::EndMessage;
1060 
1061     for (int ndx = 0; ndx < (int)expectedResources.size(); ++ndx)
1062     {
1063         if (!de::contains(resourceList.begin(), resourceList.end(), expectedResources[ndx]))
1064         {
1065             m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource list did not contain active resource "
1066                                << expectedResources[ndx] << tcu::TestLog::EndMessage;
1067             error = true;
1068         }
1069     }
1070 
1071     for (int ndx = 0; ndx < (int)resourceList.size(); ++ndx)
1072     {
1073         if (!de::contains(expectedResources.begin(), expectedResources.end(), resourceList[ndx]))
1074         {
1075             // Ignore all builtin variables or the variable unusedZero,
1076             // mismatch causes errors otherwise.  unusedZero is a uniform that
1077             // may be added by generateProgramInterfaceProgramSources.
1078             if (deStringBeginsWith(resourceList[ndx].c_str(), "gl_") == false &&
1079                 resourceList[ndx] != getUnusedZeroUniformName())
1080             {
1081                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource list contains unexpected resource name "
1082                                    << resourceList[ndx] << tcu::TestLog::EndMessage;
1083                 error = true;
1084             }
1085             else
1086                 m_testCtx.getLog() << tcu::TestLog::Message << "Note, resource list contains unknown built-in "
1087                                    << resourceList[ndx] << ". This variable is ignored." << tcu::TestLog::EndMessage;
1088         }
1089     }
1090 
1091     return !error;
1092 }
1093 
verifyResourceIndexQuery(const std::vector<std::string> & resourceList,const std::vector<std::string> & referenceResources,glw::GLuint program)1094 bool ResourceListTestCase::verifyResourceIndexQuery(const std::vector<std::string> &resourceList,
1095                                                     const std::vector<std::string> &referenceResources,
1096                                                     glw::GLuint program)
1097 {
1098     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
1099     const glw::GLenum programInterface = getProgramInterfaceGLEnum(m_programInterface);
1100     bool error                         = false;
1101 
1102     m_testCtx.getLog() << tcu::TestLog::Message
1103                        << "Verifying GetProgramResourceIndex returns correct indices for resource names."
1104                        << tcu::TestLog::EndMessage;
1105 
1106     for (int ndx = 0; ndx < (int)referenceResources.size(); ++ndx)
1107     {
1108         const glw::GLuint index =
1109             gl.getProgramResourceIndex(program, programInterface, referenceResources[ndx].c_str());
1110         GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
1111 
1112         if (index == GL_INVALID_INDEX)
1113         {
1114             m_testCtx.getLog() << tcu::TestLog::Message << "Error, for active resource \"" << referenceResources[ndx]
1115                                << "\" got index GL_INVALID_INDEX." << tcu::TestLog::EndMessage;
1116             error = true;
1117         }
1118         else if ((int)index >= (int)resourceList.size())
1119         {
1120             m_testCtx.getLog() << tcu::TestLog::Message << "Error, for active resource \"" << referenceResources[ndx]
1121                                << "\" got index " << index << " (larger or equal to GL_ACTIVE_RESOURCES)."
1122                                << tcu::TestLog::EndMessage;
1123             error = true;
1124         }
1125         else if (resourceList[index] != referenceResources[ndx])
1126         {
1127             m_testCtx.getLog() << tcu::TestLog::Message << "Error, for active resource \"" << referenceResources[ndx]
1128                                << "\" got index (index = " << index << ") of another resource (" << resourceList[index]
1129                                << ")." << tcu::TestLog::EndMessage;
1130             error = true;
1131         }
1132     }
1133 
1134     // Query for "name" should match "name[0]" except for XFB
1135 
1136     if (m_programInterface != PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING)
1137     {
1138         for (int ndx = 0; ndx < (int)referenceResources.size(); ++ndx)
1139         {
1140             if (de::endsWith(referenceResources[ndx], "[0]"))
1141             {
1142                 const std::string queryString = referenceResources[ndx].substr(0, referenceResources[ndx].length() - 3);
1143                 const glw::GLuint index = gl.getProgramResourceIndex(program, programInterface, queryString.c_str());
1144                 GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
1145 
1146                 if (index == GL_INVALID_INDEX)
1147                 {
1148                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for \"" << queryString
1149                                        << "\" resulted in index GL_INVALID_INDEX." << tcu::TestLog::EndMessage;
1150                     error = true;
1151                 }
1152                 else if ((int)index >= (int)resourceList.size())
1153                 {
1154                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for \"" << queryString
1155                                        << "\" resulted in index " << index
1156                                        << " (larger or equal to GL_ACTIVE_RESOURCES)." << tcu::TestLog::EndMessage;
1157                     error = true;
1158                 }
1159                 else if (resourceList[index] != queryString + "[0]")
1160                 {
1161                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for \"" << queryString
1162                                        << "\" got index (index = " << index << ") of another resource (\""
1163                                        << resourceList[index] << "\")." << tcu::TestLog::EndMessage;
1164                     error = true;
1165                 }
1166             }
1167         }
1168     }
1169 
1170     return !error;
1171 }
1172 
verifyMaxNameLength(const std::vector<std::string> & resourceList,glw::GLuint program)1173 bool ResourceListTestCase::verifyMaxNameLength(const std::vector<std::string> &resourceList, glw::GLuint program)
1174 {
1175     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
1176     const glw::GLenum programInterface = getProgramInterfaceGLEnum(m_programInterface);
1177     glw::GLint maxNameLength           = 0;
1178     glw::GLint expectedMaxNameLength   = 0;
1179 
1180     gl.getProgramInterfaceiv(program, programInterface, GL_MAX_NAME_LENGTH, &maxNameLength);
1181     GLU_EXPECT_NO_ERROR(gl.getError(), "query interface");
1182 
1183     for (int ndx = 0; ndx < (int)resourceList.size(); ++ndx)
1184         expectedMaxNameLength = de::max(expectedMaxNameLength, (int)resourceList[ndx].size() + 1);
1185 
1186     m_testCtx.getLog() << tcu::TestLog::Message << "Verifying MAX_NAME_LENGTH, expecting " << expectedMaxNameLength
1187                        << " (i.e. consistent with the queried resource list)" << tcu::TestLog::EndMessage;
1188 
1189     if (expectedMaxNameLength != maxNameLength)
1190     {
1191         m_testCtx.getLog() << tcu::TestLog::Message << "Error, got " << maxNameLength << tcu::TestLog::EndMessage;
1192         return false;
1193     }
1194 
1195     return true;
1196 }
1197 
genTestCaseName(ProgramInterface interface,const ResourceDefinition::Node * root)1198 std::string ResourceListTestCase::genTestCaseName(ProgramInterface interface, const ResourceDefinition::Node *root)
1199 {
1200     bool isImplicitlySizedArray = false;
1201     bool hasVariable            = false;
1202     bool accumulateName         = true;
1203     std::string buf             = "var";
1204     std::string prefix;
1205 
1206     for (const ResourceDefinition::Node *node = root; node; node = node->getEnclosingNode())
1207     {
1208         switch (node->getType())
1209         {
1210         case ResourceDefinition::Node::TYPE_VARIABLE:
1211         {
1212             hasVariable = true;
1213             break;
1214         }
1215 
1216         case ResourceDefinition::Node::TYPE_STRUCT_MEMBER:
1217         {
1218             if (accumulateName)
1219                 buf += "_struct";
1220             break;
1221         }
1222 
1223         case ResourceDefinition::Node::TYPE_ARRAY_ELEMENT:
1224         {
1225             DE_ASSERT(dynamic_cast<const ResourceDefinition::ArrayElement *>(node));
1226             const ResourceDefinition::ArrayElement *arrayElement =
1227                 static_cast<const ResourceDefinition::ArrayElement *>(node);
1228 
1229             isImplicitlySizedArray = (arrayElement->m_arraySize == ResourceDefinition::ArrayElement::UNSIZED_ARRAY);
1230 
1231             if (accumulateName)
1232                 buf += "_array";
1233             break;
1234         }
1235 
1236         case ResourceDefinition::Node::TYPE_STORAGE_QUALIFIER:
1237         {
1238             DE_ASSERT(dynamic_cast<const ResourceDefinition::StorageQualifier *>(node));
1239             const ResourceDefinition::StorageQualifier *storageDef =
1240                 static_cast<const ResourceDefinition::StorageQualifier *>(node);
1241 
1242             if (storageDef->m_storage == glu::STORAGE_PATCH_IN || storageDef->m_storage == glu::STORAGE_PATCH_OUT)
1243             {
1244                 if (accumulateName)
1245                     prefix += "patch_";
1246             }
1247             break;
1248         }
1249 
1250         case ResourceDefinition::Node::TYPE_SHADER:
1251         case ResourceDefinition::Node::TYPE_SHADER_SET:
1252         {
1253             bool arrayedInterface;
1254 
1255             if (node->getType() == ResourceDefinition::Node::TYPE_SHADER)
1256             {
1257                 DE_ASSERT(dynamic_cast<const ResourceDefinition::Shader *>(node));
1258                 const ResourceDefinition::Shader *shaderDef = static_cast<const ResourceDefinition::Shader *>(node);
1259 
1260                 arrayedInterface = isArrayedInterface(interface, (1u << shaderDef->m_type));
1261             }
1262             else
1263             {
1264                 DE_ASSERT(node->getType() == ResourceDefinition::Node::TYPE_SHADER_SET);
1265                 DE_ASSERT(dynamic_cast<const ResourceDefinition::ShaderSet *>(node));
1266                 const ResourceDefinition::ShaderSet *shaderDef =
1267                     static_cast<const ResourceDefinition::ShaderSet *>(node);
1268 
1269                 arrayedInterface = isArrayedInterface(interface, shaderDef->getReferencingMask());
1270             }
1271 
1272             if (arrayedInterface && isImplicitlySizedArray)
1273             {
1274                 // omit implicit arrayness from name, i.e. remove trailing "_array"
1275                 DE_ASSERT(de::endsWith(buf, "_array"));
1276                 buf = buf.substr(0, buf.length() - 6);
1277             }
1278 
1279             break;
1280         }
1281 
1282         case ResourceDefinition::Node::TYPE_INTERFACE_BLOCK:
1283         {
1284             accumulateName = false;
1285             break;
1286         }
1287 
1288         default:
1289             break;
1290         }
1291     }
1292 
1293     if (!hasVariable)
1294         return prefix + "empty";
1295     else
1296         return prefix + buf;
1297 }
1298 
isArrayedInterface(ProgramInterface interface,uint32_t stageBits)1299 bool ResourceListTestCase::isArrayedInterface(ProgramInterface interface, uint32_t stageBits)
1300 {
1301     if (interface == PROGRAMINTERFACE_PROGRAM_INPUT)
1302     {
1303         const glu::ShaderType firstStage = getShaderMaskFirstStage(stageBits);
1304         return firstStage == glu::SHADERTYPE_TESSELLATION_CONTROL ||
1305                firstStage == glu::SHADERTYPE_TESSELLATION_EVALUATION || firstStage == glu::SHADERTYPE_GEOMETRY;
1306     }
1307     else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT)
1308     {
1309         const glu::ShaderType lastStage = getShaderMaskLastStage(stageBits);
1310         return lastStage == glu::SHADERTYPE_TESSELLATION_CONTROL;
1311     }
1312     return false;
1313 }
1314 
1315 // Resouce property query case
1316 
1317 class ResourceTestCase : public ProgramInterfaceQueryTestCase
1318 {
1319 public:
1320     ResourceTestCase(Context &context, const ResourceDefinition::Node::SharedPtr &targetResource,
1321                      const ProgramResourceQueryTestTarget &queryTarget, const char *name = DE_NULL);
1322     ~ResourceTestCase(void);
1323 
1324 private:
1325     void init(void);
1326     void deinit(void);
1327     const ProgramInterfaceDefinition::Program *getProgramDefinition(void) const;
1328     std::vector<std::string> getQueryTargetResources(void) const;
1329 
1330     static std::string genTestCaseName(const ResourceDefinition::Node *);
1331     static std::string genMultilineDescription(const ResourceDefinition::Node *);
1332 
1333     ResourceDefinition::Node::SharedPtr m_targetResource;
1334     ProgramInterfaceDefinition::Program *m_program;
1335     std::vector<std::string> m_targetResources;
1336 };
1337 
ResourceTestCase(Context & context,const ResourceDefinition::Node::SharedPtr & targetResource,const ProgramResourceQueryTestTarget & queryTarget,const char * name)1338 ResourceTestCase::ResourceTestCase(Context &context, const ResourceDefinition::Node::SharedPtr &targetResource,
1339                                    const ProgramResourceQueryTestTarget &queryTarget, const char *name)
1340     : ProgramInterfaceQueryTestCase(
1341           context, (name == DE_NULL) ? (genTestCaseName(targetResource.get()).c_str()) : (name), "", queryTarget)
1342     , m_targetResource(targetResource)
1343     , m_program(DE_NULL)
1344 {
1345 }
1346 
~ResourceTestCase(void)1347 ResourceTestCase::~ResourceTestCase(void)
1348 {
1349     deinit();
1350 }
1351 
init(void)1352 void ResourceTestCase::init(void)
1353 {
1354     m_testCtx.getLog() << tcu::TestLog::Message << genMultilineDescription(m_targetResource.get())
1355                        << tcu::TestLog::EndMessage;
1356 
1357     // Program
1358     {
1359         // Generate interface with target resource
1360         m_program         = generateProgramDefinitionFromResource(m_targetResource.get()).release();
1361         m_targetResources = getProgramInterfaceResourceList(m_program, getTargetInterface());
1362     }
1363 }
1364 
deinit(void)1365 void ResourceTestCase::deinit(void)
1366 {
1367     m_targetResource.clear();
1368 
1369     delete m_program;
1370     m_program = DE_NULL;
1371 
1372     m_targetResources = std::vector<std::string>();
1373 }
1374 
getProgramDefinition(void) const1375 const ProgramInterfaceDefinition::Program *ResourceTestCase::getProgramDefinition(void) const
1376 {
1377     return m_program;
1378 }
1379 
getQueryTargetResources(void) const1380 std::vector<std::string> ResourceTestCase::getQueryTargetResources(void) const
1381 {
1382     return m_targetResources;
1383 }
1384 
genTestCaseName(const ResourceDefinition::Node * resource)1385 std::string ResourceTestCase::genTestCaseName(const ResourceDefinition::Node *resource)
1386 {
1387     if (resource->getType() == ResourceDefinition::Node::TYPE_VARIABLE)
1388     {
1389         DE_ASSERT(dynamic_cast<const ResourceDefinition::Variable *>(resource));
1390 
1391         const ResourceDefinition::Variable *variable = static_cast<const ResourceDefinition::Variable *>(resource);
1392 
1393         return convertGLTypeNameToTestName(glu::getDataTypeName(variable->m_dataType));
1394     }
1395 
1396     DE_ASSERT(false);
1397     return "";
1398 }
1399 
genMultilineDescription(const ResourceDefinition::Node * resource)1400 std::string ResourceTestCase::genMultilineDescription(const ResourceDefinition::Node *resource)
1401 {
1402     if (resource->getType() == ResourceDefinition::Node::TYPE_VARIABLE)
1403     {
1404         DE_ASSERT(dynamic_cast<const ResourceDefinition::Variable *>(resource));
1405 
1406         const ResourceDefinition::Variable *varDef = static_cast<const ResourceDefinition::Variable *>(resource);
1407         std::ostringstream buf;
1408         std::ostringstream structureDescriptor;
1409         std::string uniformType;
1410 
1411         for (const ResourceDefinition::Node *node = resource; node; node = node->getEnclosingNode())
1412         {
1413             if (node->getType() == ResourceDefinition::Node::TYPE_STORAGE_QUALIFIER)
1414             {
1415                 DE_ASSERT(dynamic_cast<const ResourceDefinition::StorageQualifier *>(node));
1416 
1417                 const ResourceDefinition::StorageQualifier *storageDef =
1418                     static_cast<const ResourceDefinition::StorageQualifier *>(node);
1419 
1420                 uniformType = std::string(" ") + glu::getStorageName(storageDef->m_storage);
1421                 structureDescriptor << "\n\tdeclared as \"" << glu::getStorageName(storageDef->m_storage) << "\"";
1422             }
1423 
1424             if (node->getType() == ResourceDefinition::Node::TYPE_ARRAY_ELEMENT)
1425                 structureDescriptor << "\n\tarray";
1426 
1427             if (node->getType() == ResourceDefinition::Node::TYPE_STRUCT_MEMBER)
1428                 structureDescriptor << "\n\tin a struct";
1429 
1430             if (node->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK)
1431                 structureDescriptor << "\n\tin the default block";
1432 
1433             if (node->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK)
1434                 structureDescriptor << "\n\tin an interface block";
1435         }
1436 
1437         buf << "Querying properties of " << glu::getDataTypeName(varDef->m_dataType) << uniformType << " variable.\n"
1438             << "Variable is:\n"
1439             << "\t" << glu::getDataTypeName(varDef->m_dataType) << structureDescriptor.str();
1440 
1441         return buf.str();
1442     }
1443     else if (resource->getType() == ResourceDefinition::Node::TYPE_TRANSFORM_FEEDBACK_TARGET)
1444     {
1445         DE_ASSERT(dynamic_cast<const ResourceDefinition::TransformFeedbackTarget *>(resource));
1446 
1447         const ResourceDefinition::TransformFeedbackTarget *xfbDef =
1448             static_cast<const ResourceDefinition::TransformFeedbackTarget *>(resource);
1449 
1450         DE_ASSERT(xfbDef->m_builtinVarName);
1451 
1452         return std::string("Querying properties of a builtin variable ") + xfbDef->m_builtinVarName;
1453     }
1454 
1455     DE_ASSERT(false);
1456     return "";
1457 }
1458 
1459 class ResourceNameBufferLimitCase : public TestCase
1460 {
1461 public:
1462     ResourceNameBufferLimitCase(Context &context, const char *name, const char *description);
1463     ~ResourceNameBufferLimitCase(void);
1464 
1465 private:
1466     IterateResult iterate(void);
1467 };
1468 
ResourceNameBufferLimitCase(Context & context,const char * name,const char * description)1469 ResourceNameBufferLimitCase::ResourceNameBufferLimitCase(Context &context, const char *name, const char *description)
1470     : TestCase(context, name, description)
1471 {
1472 }
1473 
~ResourceNameBufferLimitCase(void)1474 ResourceNameBufferLimitCase::~ResourceNameBufferLimitCase(void)
1475 {
1476 }
1477 
iterate(void)1478 ResourceNameBufferLimitCase::IterateResult ResourceNameBufferLimitCase::iterate(void)
1479 {
1480     static const char *const computeSource = "${GLSL_VERSION_DECL}\n"
1481                                              "layout(local_size_x = 1) in;\n"
1482                                              "uniform highp int u_uniformWithALongName;\n"
1483                                              "writeonly buffer OutputBufferBlock { highp int b_output_int; };\n"
1484                                              "void main ()\n"
1485                                              "{\n"
1486                                              "    b_output_int = u_uniformWithALongName;\n"
1487                                              "}\n";
1488 
1489     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1490     const glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(
1491                                                                        specializeShader(m_context, computeSource)));
1492     glw::GLuint uniformIndex;
1493 
1494     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1495 
1496     // Log program
1497     {
1498         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
1499 
1500         m_testCtx.getLog() << program;
1501         if (!program.isOk())
1502             throw tcu::TestError("could not build program");
1503     }
1504 
1505     uniformIndex = gl.getProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_uniformWithALongName");
1506     GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
1507 
1508     if (uniformIndex == GL_INVALID_INDEX)
1509         throw tcu::TestError("Uniform u_uniformWithALongName resource index was GL_INVALID_INDEX");
1510 
1511     // Query with different sized buffers, len("u_uniformWithALongName") == 22
1512 
1513     {
1514         static const struct
1515         {
1516             const char *description;
1517             int querySize;
1518             bool returnLength;
1519         } querySizes[] = {
1520             {"Query to larger buffer", 24, true},
1521             {"Query to buffer the same size", 23, true},
1522             {"Query to one byte too small buffer", 22, true},
1523             {"Query to one byte buffer", 1, true},
1524             {"Query to zero sized buffer", 0, true},
1525             {"Query to one byte too small buffer, null length argument", 22, false},
1526             {"Query to one byte buffer, null length argument", 1, false},
1527             {"Query to zero sized buffer, null length argument", 0, false},
1528         };
1529 
1530         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(querySizes); ++ndx)
1531         {
1532             const tcu::ScopedLogSection section(m_testCtx.getLog(), "Query", querySizes[ndx].description);
1533             const int uniformNameLen = 22;
1534             const int expectedWriteLen =
1535                 (querySizes[ndx].querySize != 0) ? (de::min(uniformNameLen, (querySizes[ndx].querySize - 1))) : (0);
1536             char buffer[26];
1537             glw::GLsizei written = -1;
1538 
1539             // One byte for guard
1540             DE_ASSERT((int)sizeof(buffer) > querySizes[ndx].querySize);
1541 
1542             deMemset(buffer, 'x', sizeof(buffer));
1543 
1544             if (querySizes[ndx].querySize)
1545                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying uniform name to a buffer of size "
1546                                    << querySizes[ndx].querySize << ", expecting query to write " << expectedWriteLen
1547                                    << " bytes followed by a null terminator" << tcu::TestLog::EndMessage;
1548             else
1549                 m_testCtx.getLog() << tcu::TestLog::Message << "Querying uniform name to a buffer of size "
1550                                    << querySizes[ndx].querySize << ", expecting query to write 0 bytes"
1551                                    << tcu::TestLog::EndMessage;
1552 
1553             gl.getProgramResourceName(program.getProgram(), GL_UNIFORM, uniformIndex, querySizes[ndx].querySize,
1554                                       (querySizes[ndx].returnLength) ? (&written) : (DE_NULL), buffer);
1555             GLU_EXPECT_NO_ERROR(gl.getError(), "query resource name");
1556 
1557             if (querySizes[ndx].returnLength && written != expectedWriteLen)
1558             {
1559                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected write length of " << expectedWriteLen
1560                                    << ", got " << written << tcu::TestLog::EndMessage;
1561                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected write lenght");
1562             }
1563             else if (querySizes[ndx].querySize != 0 && buffer[expectedWriteLen] != 0)
1564             {
1565                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected null terminator at " << expectedWriteLen
1566                                    << ", got dec=" << (int)buffer[expectedWriteLen] << tcu::TestLog::EndMessage;
1567                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Missing null terminator");
1568             }
1569             else if (querySizes[ndx].querySize != 0 && buffer[expectedWriteLen + 1] != 'x')
1570             {
1571                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, guard at index " << (expectedWriteLen + 1)
1572                                    << " was modified, got dec=" << (int)buffer[expectedWriteLen + 1]
1573                                    << tcu::TestLog::EndMessage;
1574                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Wrote over buffer size");
1575             }
1576             else if (querySizes[ndx].querySize == 0 && buffer[0] != 'x')
1577             {
1578                 m_testCtx.getLog() << tcu::TestLog::Message
1579                                    << "Error, buffer size was 0 but buffer contents were modified. At index 0 got dec="
1580                                    << (int)buffer[0] << tcu::TestLog::EndMessage;
1581                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer contents were modified");
1582             }
1583         }
1584     }
1585 
1586     return STOP;
1587 }
1588 
1589 class ResourceQueryBufferLimitCase : public TestCase
1590 {
1591 public:
1592     ResourceQueryBufferLimitCase(Context &context, const char *name, const char *description);
1593     ~ResourceQueryBufferLimitCase(void);
1594 
1595 private:
1596     IterateResult iterate(void);
1597 };
1598 
ResourceQueryBufferLimitCase(Context & context,const char * name,const char * description)1599 ResourceQueryBufferLimitCase::ResourceQueryBufferLimitCase(Context &context, const char *name, const char *description)
1600     : TestCase(context, name, description)
1601 {
1602 }
1603 
~ResourceQueryBufferLimitCase(void)1604 ResourceQueryBufferLimitCase::~ResourceQueryBufferLimitCase(void)
1605 {
1606 }
1607 
iterate(void)1608 ResourceQueryBufferLimitCase::IterateResult ResourceQueryBufferLimitCase::iterate(void)
1609 {
1610     static const char *const computeSource = "${GLSL_VERSION_DECL}\n"
1611                                              "layout(local_size_x = 1) in;\n"
1612                                              "uniform highp int u_uniform;\n"
1613                                              "writeonly buffer OutputBufferBlock { highp int b_output_int; };\n"
1614                                              "void main ()\n"
1615                                              "{\n"
1616                                              "    b_output_int = u_uniform;\n"
1617                                              "}\n";
1618 
1619     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1620     const glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources() << glu::ComputeSource(
1621                                                                        specializeShader(m_context, computeSource)));
1622     glw::GLuint uniformIndex;
1623 
1624     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1625 
1626     // Log program
1627     {
1628         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
1629 
1630         m_testCtx.getLog() << program;
1631         if (!program.isOk())
1632             throw tcu::TestError("could not build program");
1633     }
1634 
1635     uniformIndex = gl.getProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_uniform");
1636     GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
1637 
1638     if (uniformIndex == GL_INVALID_INDEX)
1639         throw tcu::TestError("Uniform u_uniform resource index was GL_INVALID_INDEX");
1640 
1641     // Query uniform properties
1642 
1643     {
1644         static const struct
1645         {
1646             const char *description;
1647             int numProps;
1648             int bufferSize;
1649             bool returnLength;
1650         } querySizes[] = {
1651             {"Query to a larger buffer", 2, 3, true},
1652             {"Query to too small a buffer", 3, 2, true},
1653             {"Query to zero sized buffer", 3, 0, true},
1654             {"Query to a larger buffer, null length argument", 2, 3, false},
1655             {"Query to too small a buffer, null length argument", 3, 2, false},
1656             {"Query to zero sized buffer, null length argument", 3, 0, false},
1657         };
1658 
1659         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(querySizes); ++ndx)
1660         {
1661             const tcu::ScopedLogSection section(m_testCtx.getLog(), "QueryToLarger", querySizes[ndx].description);
1662             const glw::GLenum props[]  = {GL_LOCATION, GL_LOCATION, GL_LOCATION};
1663             const int expectedWriteLen = de::min(querySizes[ndx].bufferSize, querySizes[ndx].numProps);
1664             int params[]               = {255, 255, 255, 255};
1665             glw::GLsizei written       = -1;
1666 
1667             DE_ASSERT(querySizes[ndx].numProps <= DE_LENGTH_OF_ARRAY(props));
1668             DE_ASSERT(querySizes[ndx].bufferSize <
1669                       DE_LENGTH_OF_ARRAY(params)); // leave at least one element for overflow detection
1670 
1671             m_testCtx.getLog() << tcu::TestLog::Message << "Querying " << querySizes[ndx].numProps
1672                                << " uniform prop(s) to a buffer with size " << querySizes[ndx].bufferSize
1673                                << ". Expecting query to return " << expectedWriteLen << " prop(s)"
1674                                << tcu::TestLog::EndMessage;
1675 
1676             gl.getProgramResourceiv(program.getProgram(), GL_UNIFORM, uniformIndex, querySizes[ndx].numProps, props,
1677                                     querySizes[ndx].bufferSize, (querySizes[ndx].returnLength) ? (&written) : (DE_NULL),
1678                                     params);
1679             GLU_EXPECT_NO_ERROR(gl.getError(), "query program resources");
1680 
1681             if (querySizes[ndx].returnLength && written != expectedWriteLen)
1682             {
1683                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected write length of " << expectedWriteLen
1684                                    << ", got " << written << tcu::TestLog::EndMessage;
1685                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected write lenght");
1686             }
1687             else if (params[expectedWriteLen] != 255)
1688             {
1689                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, guard at index " << (expectedWriteLen)
1690                                    << " was modified. Was 255 before call, got dec=" << params[expectedWriteLen]
1691                                    << tcu::TestLog::EndMessage;
1692                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Wrote over buffer size");
1693             }
1694         }
1695     }
1696 
1697     return STOP;
1698 }
1699 
1700 class InterfaceBlockBaseCase : public TestCase
1701 {
1702 public:
1703     enum CaseType
1704     {
1705         CASE_NAMED_BLOCK = 0,
1706         CASE_UNNAMED_BLOCK,
1707         CASE_BLOCK_ARRAY,
1708 
1709         CASE_LAST
1710     };
1711 
1712     InterfaceBlockBaseCase(Context &context, const char *name, const char *description, glu::Storage storage,
1713                            CaseType caseType);
1714     ~InterfaceBlockBaseCase(void);
1715 
1716 private:
1717     void init(void);
1718     void deinit(void);
1719 
1720 protected:
1721     const glu::Storage m_storage;
1722     const CaseType m_caseType;
1723     ProgramInterfaceDefinition::Program *m_program;
1724 };
1725 
InterfaceBlockBaseCase(Context & context,const char * name,const char * description,glu::Storage storage,CaseType caseType)1726 InterfaceBlockBaseCase::InterfaceBlockBaseCase(Context &context, const char *name, const char *description,
1727                                                glu::Storage storage, CaseType caseType)
1728     : TestCase(context, name, description)
1729     , m_storage(storage)
1730     , m_caseType(caseType)
1731     , m_program(DE_NULL)
1732 {
1733     DE_ASSERT(storage == glu::STORAGE_UNIFORM || storage == glu::STORAGE_BUFFER);
1734 }
1735 
~InterfaceBlockBaseCase(void)1736 InterfaceBlockBaseCase::~InterfaceBlockBaseCase(void)
1737 {
1738     deinit();
1739 }
1740 
init(void)1741 void InterfaceBlockBaseCase::init(void)
1742 {
1743     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1744     ProgramInterfaceDefinition::Shader *shader;
1745 
1746     m_program = new ProgramInterfaceDefinition::Program();
1747     shader    = m_program->addShader(glu::SHADERTYPE_COMPUTE, glslVersion);
1748 
1749     // PrecedingInterface
1750     {
1751         glu::InterfaceBlock precedingInterfaceBlock;
1752 
1753         precedingInterfaceBlock.interfaceName  = "PrecedingInterface";
1754         precedingInterfaceBlock.layout.binding = 0;
1755         precedingInterfaceBlock.storage        = m_storage;
1756         precedingInterfaceBlock.instanceName   = "precedingInstance";
1757 
1758         precedingInterfaceBlock.variables.push_back(
1759             glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "precedingMember"));
1760 
1761         // Unsized array type
1762         if (m_storage == glu::STORAGE_BUFFER)
1763             precedingInterfaceBlock.variables.push_back(glu::VariableDeclaration(
1764                 glu::VarType(glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), glu::VarType::UNSIZED_ARRAY),
1765                 "precedingMemberUnsizedArray"));
1766         else
1767             precedingInterfaceBlock.variables.push_back(glu::VariableDeclaration(
1768                 glu::VarType(glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), 2), "precedingMemberArray"));
1769 
1770         shader->getDefaultBlock().interfaceBlocks.push_back(precedingInterfaceBlock);
1771     }
1772 
1773     // TargetInterface
1774     {
1775         glu::InterfaceBlock targetInterfaceBlock;
1776 
1777         targetInterfaceBlock.interfaceName  = "TargetInterface";
1778         targetInterfaceBlock.layout.binding = 1;
1779         targetInterfaceBlock.storage        = m_storage;
1780 
1781         if (m_caseType == CASE_UNNAMED_BLOCK)
1782             targetInterfaceBlock.instanceName = "";
1783         else
1784             targetInterfaceBlock.instanceName = "targetInstance";
1785 
1786         if (m_caseType == CASE_BLOCK_ARRAY)
1787             targetInterfaceBlock.dimensions.push_back(2);
1788 
1789         // Basic type
1790         {
1791             targetInterfaceBlock.variables.push_back(
1792                 glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "blockMemberBasic"));
1793         }
1794 
1795         // Array type
1796         {
1797             targetInterfaceBlock.variables.push_back(glu::VariableDeclaration(
1798                 glu::VarType(glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), 3), "blockMemberArray"));
1799         }
1800 
1801         // Struct type
1802         {
1803             glu::StructType *structPtr = new glu::StructType("StructType");
1804             structPtr->addMember("structMemberBasic", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
1805             structPtr->addMember("structMemberArray",
1806                                  glu::VarType(glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), 2));
1807 
1808             targetInterfaceBlock.variables.push_back(
1809                 glu::VariableDeclaration(glu::VarType(glu::VarType(structPtr), 2), "blockMemberStruct"));
1810         }
1811 
1812         // Unsized array type
1813         if (m_storage == glu::STORAGE_BUFFER)
1814             targetInterfaceBlock.variables.push_back(glu::VariableDeclaration(
1815                 glu::VarType(glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), glu::VarType::UNSIZED_ARRAY),
1816                 "blockMemberUnsizedArray"));
1817 
1818         shader->getDefaultBlock().interfaceBlocks.push_back(targetInterfaceBlock);
1819     }
1820 
1821     // TrailingInterface
1822     {
1823         glu::InterfaceBlock trailingInterfaceBlock;
1824 
1825         trailingInterfaceBlock.interfaceName  = "TrailingInterface";
1826         trailingInterfaceBlock.layout.binding = 3;
1827         trailingInterfaceBlock.storage        = m_storage;
1828         trailingInterfaceBlock.instanceName   = "trailingInstance";
1829         trailingInterfaceBlock.variables.push_back(
1830             glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "trailingMember"));
1831 
1832         shader->getDefaultBlock().interfaceBlocks.push_back(trailingInterfaceBlock);
1833     }
1834 
1835     DE_ASSERT(m_program->isValid());
1836 }
1837 
deinit(void)1838 void InterfaceBlockBaseCase::deinit(void)
1839 {
1840     delete m_program;
1841     m_program = DE_NULL;
1842 }
1843 
1844 class InterfaceBlockActiveVariablesTestCase : public InterfaceBlockBaseCase
1845 {
1846 public:
1847     InterfaceBlockActiveVariablesTestCase(Context &context, const char *name, const char *description,
1848                                           glu::Storage storage, CaseType caseType);
1849 
1850 private:
1851     IterateResult iterate(void);
1852 };
1853 
InterfaceBlockActiveVariablesTestCase(Context & context,const char * name,const char * description,glu::Storage storage,CaseType caseType)1854 InterfaceBlockActiveVariablesTestCase::InterfaceBlockActiveVariablesTestCase(Context &context, const char *name,
1855                                                                              const char *description,
1856                                                                              glu::Storage storage, CaseType caseType)
1857     : InterfaceBlockBaseCase(context, name, description, storage, caseType)
1858 {
1859 }
1860 
iterate(void)1861 InterfaceBlockActiveVariablesTestCase::IterateResult InterfaceBlockActiveVariablesTestCase::iterate(void)
1862 {
1863     const ProgramInterface programInterface =
1864         (m_storage == glu::STORAGE_UNIFORM) ? (PROGRAMINTERFACE_UNIFORM_BLOCK) :
1865         (m_storage == glu::STORAGE_BUFFER)  ? (PROGRAMINTERFACE_SHADER_STORAGE_BLOCK) :
1866                                               (PROGRAMINTERFACE_LAST);
1867     const glw::GLenum programGLInterfaceValue     = getProgramInterfaceGLEnum(programInterface);
1868     const glw::GLenum programMemberInterfaceValue = (m_storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM) :
1869                                                     (m_storage == glu::STORAGE_BUFFER)  ? (GL_BUFFER_VARIABLE) :
1870                                                                                           (0);
1871     const std::vector<std::string> blockNames     = getProgramInterfaceResourceList(m_program, programInterface);
1872     glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
1873     int expectedMaxNumActiveVariables = 0;
1874 
1875     DE_ASSERT(programInterface != PROGRAMINTERFACE_LAST);
1876 
1877     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1878     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1879 
1880     // Verify all blocks
1881 
1882     for (int blockNdx = 0; blockNdx < (int)blockNames.size(); ++blockNdx)
1883     {
1884         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Block", "Block \"" + blockNames[blockNdx] + "\"");
1885         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1886         const glw::GLuint resourceNdx =
1887             gl.getProgramResourceIndex(program.getProgram(), programGLInterfaceValue, blockNames[blockNdx].c_str());
1888         glw::GLint numActiveResources;
1889         std::vector<std::string> activeResourceNames;
1890 
1891         GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
1892 
1893         if (resourceNdx == GL_INVALID_INDEX)
1894         {
1895             m_testCtx.getLog() << tcu::TestLog::Message
1896                                << "Error, getProgramResourceIndex returned GL_INVALID_INDEX for \""
1897                                << blockNames[blockNdx] << "\"" << tcu::TestLog::EndMessage;
1898             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Resource not found");
1899             continue;
1900         }
1901 
1902         // query block information
1903 
1904         {
1905             const glw::GLenum props[] = {GL_NUM_ACTIVE_VARIABLES};
1906             glw::GLint retBuffer[2]   = {-1, -1};
1907             glw::GLint written        = -1;
1908 
1909             gl.getProgramResourceiv(program.getProgram(), programGLInterfaceValue, resourceNdx,
1910                                     DE_LENGTH_OF_ARRAY(props), props, 1, &written, retBuffer);
1911             GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_NUM_ACTIVE_VARIABLES");
1912 
1913             numActiveResources            = retBuffer[0];
1914             expectedMaxNumActiveVariables = de::max(expectedMaxNumActiveVariables, numActiveResources);
1915             m_testCtx.getLog() << tcu::TestLog::Message << "NUM_ACTIVE_VARIABLES = " << numActiveResources
1916                                << tcu::TestLog::EndMessage;
1917 
1918             if (written == -1 || retBuffer[0] == -1)
1919             {
1920                 m_testCtx.getLog() << tcu::TestLog::Message
1921                                    << "Error, Query for NUM_ACTIVE_VARIABLES did not return a value"
1922                                    << tcu::TestLog::EndMessage;
1923                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query for NUM_ACTIVE_VARIABLES failed");
1924                 continue;
1925             }
1926             else if (retBuffer[1] != -1)
1927             {
1928                 m_testCtx.getLog() << tcu::TestLog::Message
1929                                    << "Error, Query for NUM_ACTIVE_VARIABLES returned too many values"
1930                                    << tcu::TestLog::EndMessage;
1931                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query for NUM_ACTIVE_VARIABLES returned too many values");
1932                 continue;
1933             }
1934             else if (retBuffer[0] < 0)
1935             {
1936                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, NUM_ACTIVE_VARIABLES < 0"
1937                                    << tcu::TestLog::EndMessage;
1938                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "NUM_ACTIVE_VARIABLES < 0");
1939                 continue;
1940             }
1941         }
1942 
1943         // query block variable information
1944 
1945         {
1946             const glw::GLenum props[] = {GL_ACTIVE_VARIABLES};
1947             std::vector<glw::GLint> activeVariableIndices(
1948                 numActiveResources + 1, -1); // Allocate one extra trailing to detect wrong write lengths
1949             glw::GLint written = -1;
1950 
1951             gl.getProgramResourceiv(program.getProgram(), programGLInterfaceValue, resourceNdx,
1952                                     DE_LENGTH_OF_ARRAY(props), props, (glw::GLsizei)activeVariableIndices.size(),
1953                                     &written, &activeVariableIndices[0]);
1954             GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_ACTIVE_VARIABLES");
1955 
1956             if (written == -1)
1957             {
1958                 m_testCtx.getLog() << tcu::TestLog::Message
1959                                    << "Error, Query for GL_ACTIVE_VARIABLES did not return any values"
1960                                    << tcu::TestLog::EndMessage;
1961                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query for GL_ACTIVE_VARIABLES failed");
1962                 continue;
1963             }
1964             else if (written != numActiveResources)
1965             {
1966                 m_testCtx.getLog() << tcu::TestLog::Message
1967                                    << "Error, Query for GL_ACTIVE_VARIABLES did not return NUM_ACTIVE_VARIABLES values"
1968                                    << tcu::TestLog::EndMessage;
1969                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
1970                                         "Query for GL_ACTIVE_VARIABLES returned invalid number of values");
1971                 continue;
1972             }
1973             else if (activeVariableIndices.back() != -1)
1974             {
1975                 m_testCtx.getLog() << tcu::TestLog::Message
1976                                    << "Error, GL_ACTIVE_VARIABLES query return buffer trailing guard value was "
1977                                       "modified, getProgramResourceiv returned more than NUM_ACTIVE_VARIABLES values"
1978                                    << tcu::TestLog::EndMessage;
1979                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Query for GL_ACTIVE_VARIABLES returned too many values");
1980                 continue;
1981             }
1982 
1983             // log indices
1984             {
1985                 tcu::MessageBuilder builder(&m_testCtx.getLog());
1986 
1987                 builder << "Active variable indices: {";
1988                 for (int varNdx = 0; varNdx < numActiveResources; ++varNdx)
1989                 {
1990                     if (varNdx)
1991                         builder << ", ";
1992                     builder << activeVariableIndices[varNdx];
1993                 }
1994                 builder << "}" << tcu::TestLog::EndMessage;
1995             }
1996 
1997             // collect names
1998 
1999             activeResourceNames.resize(numActiveResources);
2000 
2001             for (int varNdx = 0; varNdx < numActiveResources; ++varNdx)
2002             {
2003                 const glw::GLenum nameProp = GL_NAME_LENGTH;
2004                 glw::GLint nameLength      = -1;
2005                 std::vector<char> nameBuffer;
2006 
2007                 written = -1;
2008                 gl.getProgramResourceiv(program.getProgram(), programMemberInterfaceValue,
2009                                         activeVariableIndices[varNdx], 1, &nameProp, 1, &written, &nameLength);
2010                 GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_NAME_LENGTH");
2011 
2012                 if (nameLength <= 0 || written <= 0)
2013                 {
2014                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, GL_NAME_LENGTH query failed"
2015                                        << tcu::TestLog::EndMessage;
2016                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "GL_NAME_LENGTH query failed");
2017                     continue;
2018                 }
2019 
2020                 nameBuffer.resize(nameLength + 2, 'X'); // allocate more than required
2021                 written = -1;
2022                 gl.getProgramResourceName(program.getProgram(), programMemberInterfaceValue,
2023                                           activeVariableIndices[varNdx], nameLength + 1, &written, &nameBuffer[0]);
2024                 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceName");
2025 
2026                 if (written <= 0)
2027                 {
2028                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, name query failed, no data written"
2029                                        << tcu::TestLog::EndMessage;
2030                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "name query failed");
2031                     continue;
2032                 }
2033                 else if (written > nameLength)
2034                 {
2035                     m_testCtx.getLog() << tcu::TestLog::Message
2036                                        << "Error, name query failed, query returned too much data"
2037                                        << tcu::TestLog::EndMessage;
2038                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "name query failed");
2039                     continue;
2040                 }
2041 
2042                 activeResourceNames[varNdx] = std::string(&nameBuffer[0], written);
2043             }
2044 
2045             // log collected names
2046             {
2047                 tcu::MessageBuilder builder(&m_testCtx.getLog());
2048 
2049                 builder << "Active variables:\n";
2050                 for (int varNdx = 0; varNdx < numActiveResources; ++varNdx)
2051                     builder << "\t" << activeResourceNames[varNdx] << "\n";
2052                 builder << tcu::TestLog::EndMessage;
2053             }
2054         }
2055 
2056         // verify names
2057         {
2058             glu::InterfaceBlock *block  = DE_NULL;
2059             const std::string blockName = glu::parseVariableName(blockNames[blockNdx].c_str());
2060             std::vector<std::string> referenceList;
2061 
2062             for (int interfaceNdx = 0;
2063                  interfaceNdx < (int)m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks.size();
2064                  ++interfaceNdx)
2065             {
2066                 if (m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName ==
2067                     blockName)
2068                 {
2069                     block = &m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks[interfaceNdx];
2070                     break;
2071                 }
2072             }
2073 
2074             if (!block)
2075                 throw tcu::InternalError("could not find block referenced in the reference resource list");
2076 
2077             // generate reference list
2078 
2079             referenceList = getProgramInterfaceBlockMemberResourceList(*block);
2080             {
2081                 tcu::MessageBuilder builder(&m_testCtx.getLog());
2082 
2083                 builder << "Expected variable names:\n";
2084                 for (int varNdx = 0; varNdx < (int)referenceList.size(); ++varNdx)
2085                     builder << "\t" << referenceList[varNdx] << "\n";
2086                 builder << tcu::TestLog::EndMessage;
2087             }
2088 
2089             // compare lists
2090             {
2091                 bool listsIdentical = true;
2092 
2093                 for (int ndx = 0; ndx < (int)referenceList.size(); ++ndx)
2094                 {
2095                     if (!de::contains(activeResourceNames.begin(), activeResourceNames.end(), referenceList[ndx]))
2096                     {
2097                         m_testCtx.getLog()
2098                             << tcu::TestLog::Message << "Error, variable name list did not contain active variable "
2099                             << referenceList[ndx] << tcu::TestLog::EndMessage;
2100                         listsIdentical = false;
2101                     }
2102                 }
2103 
2104                 for (int ndx = 0; ndx < (int)activeResourceNames.size(); ++ndx)
2105                 {
2106                     if (!de::contains(referenceList.begin(), referenceList.end(), activeResourceNames[ndx]))
2107                     {
2108                         m_testCtx.getLog()
2109                             << tcu::TestLog::Message << "Error, variable name list contains unexpected resource \""
2110                             << activeResourceNames[ndx] << "\"" << tcu::TestLog::EndMessage;
2111                         listsIdentical = false;
2112                     }
2113                 }
2114 
2115                 if (listsIdentical)
2116                     m_testCtx.getLog() << tcu::TestLog::Message << "Lists identical" << tcu::TestLog::EndMessage;
2117                 else
2118                 {
2119                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, invalid active variable list"
2120                                        << tcu::TestLog::EndMessage;
2121                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid active variable list");
2122                     continue;
2123                 }
2124             }
2125         }
2126     }
2127 
2128     // Max num active variables
2129     {
2130         const tcu::ScopedLogSection section(m_testCtx.getLog(), "MaxNumActiveVariables", "MAX_NUM_ACTIVE_VARIABLES");
2131         const glw::Functions &gl         = m_context.getRenderContext().getFunctions();
2132         glw::GLint maxNumActiveVariables = -1;
2133 
2134         gl.getProgramInterfaceiv(program.getProgram(), programGLInterfaceValue, GL_MAX_NUM_ACTIVE_VARIABLES,
2135                                  &maxNumActiveVariables);
2136         GLU_EXPECT_NO_ERROR(gl.getError(), "query MAX_NUM_ACTIVE_VARIABLES");
2137 
2138         m_testCtx.getLog() << tcu::TestLog::Message << "MAX_NUM_ACTIVE_VARIABLES = " << maxNumActiveVariables
2139                            << tcu::TestLog::EndMessage;
2140 
2141         if (expectedMaxNumActiveVariables != maxNumActiveVariables)
2142         {
2143             m_testCtx.getLog() << tcu::TestLog::Message << "Error, got unexpected MAX_NUM_ACTIVE_VARIABLES"
2144                                << tcu::TestLog::EndMessage;
2145             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "unexpected MAX_NUM_ACTIVE_VARIABLES");
2146         }
2147         else
2148             m_testCtx.getLog() << tcu::TestLog::Message << "MAX_NUM_ACTIVE_VARIABLES valid" << tcu::TestLog::EndMessage;
2149     }
2150 
2151     return STOP;
2152 }
2153 
2154 class InterfaceBlockDataSizeTestCase : public InterfaceBlockBaseCase
2155 {
2156 public:
2157     InterfaceBlockDataSizeTestCase(Context &context, const char *name, const char *description, glu::Storage storage,
2158                                    CaseType caseType);
2159 
2160 private:
2161     IterateResult iterate(void);
2162     int getBlockMinDataSize(const std::string &blockName) const;
2163     int getBlockMinDataSize(const glu::InterfaceBlock &block) const;
2164 };
2165 
InterfaceBlockDataSizeTestCase(Context & context,const char * name,const char * description,glu::Storage storage,CaseType caseType)2166 InterfaceBlockDataSizeTestCase::InterfaceBlockDataSizeTestCase(Context &context, const char *name,
2167                                                                const char *description, glu::Storage storage,
2168                                                                CaseType caseType)
2169     : InterfaceBlockBaseCase(context, name, description, storage, caseType)
2170 {
2171 }
2172 
iterate(void)2173 InterfaceBlockDataSizeTestCase::IterateResult InterfaceBlockDataSizeTestCase::iterate(void)
2174 {
2175     const ProgramInterface programInterface =
2176         (m_storage == glu::STORAGE_UNIFORM) ? (PROGRAMINTERFACE_UNIFORM_BLOCK) :
2177         (m_storage == glu::STORAGE_BUFFER)  ? (PROGRAMINTERFACE_SHADER_STORAGE_BLOCK) :
2178                                               (PROGRAMINTERFACE_LAST);
2179     const glw::GLenum programGLInterfaceValue = getProgramInterfaceGLEnum(programInterface);
2180     const std::vector<std::string> blockNames = getProgramInterfaceResourceList(m_program, programInterface);
2181     glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
2182 
2183     DE_ASSERT(programInterface != PROGRAMINTERFACE_LAST);
2184 
2185     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2186     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2187 
2188     // Verify all blocks
2189     for (int blockNdx = 0; blockNdx < (int)blockNames.size(); ++blockNdx)
2190     {
2191         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Block", "Block \"" + blockNames[blockNdx] + "\"");
2192         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2193         const glw::GLuint resourceNdx =
2194             gl.getProgramResourceIndex(program.getProgram(), programGLInterfaceValue, blockNames[blockNdx].c_str());
2195         const int expectedMinDataSize = getBlockMinDataSize(blockNames[blockNdx]);
2196         glw::GLint queryDataSize      = -1;
2197 
2198         GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
2199 
2200         if (resourceNdx == GL_INVALID_INDEX)
2201         {
2202             m_testCtx.getLog() << tcu::TestLog::Message
2203                                << "Error, getProgramResourceIndex returned GL_INVALID_INDEX for \""
2204                                << blockNames[blockNdx] << "\"" << tcu::TestLog::EndMessage;
2205             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Resource not found");
2206             continue;
2207         }
2208 
2209         // query
2210         {
2211             const glw::GLenum prop = GL_BUFFER_DATA_SIZE;
2212 
2213             gl.getProgramResourceiv(program.getProgram(), programGLInterfaceValue, resourceNdx, 1, &prop, 1, DE_NULL,
2214                                     &queryDataSize);
2215             GLU_EXPECT_NO_ERROR(gl.getError(), "query resource BUFFER_DATA_SIZE");
2216         }
2217 
2218         m_testCtx.getLog() << tcu::TestLog::Message << "BUFFER_DATA_SIZE = " << queryDataSize << "\n"
2219                            << "Buffer data size with tight packing: " << expectedMinDataSize
2220                            << tcu::TestLog::EndMessage;
2221 
2222         if (queryDataSize < expectedMinDataSize)
2223         {
2224             m_testCtx.getLog() << tcu::TestLog::Message << "Error, buffer size was less than minimum buffer data size"
2225                                << tcu::TestLog::EndMessage;
2226             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer data size invalid");
2227             continue;
2228         }
2229         else
2230             m_testCtx.getLog() << tcu::TestLog::Message << "Buffer size valid" << tcu::TestLog::EndMessage;
2231     }
2232 
2233     return STOP;
2234 }
2235 
getBlockMinDataSize(const std::string & blockFullName) const2236 int InterfaceBlockDataSizeTestCase::getBlockMinDataSize(const std::string &blockFullName) const
2237 {
2238     const std::string blockName = glu::parseVariableName(blockFullName.c_str());
2239 
2240     for (int interfaceNdx = 0; interfaceNdx < (int)m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks.size();
2241          ++interfaceNdx)
2242     {
2243         if (m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName &&
2244             m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks[interfaceNdx].storage == m_storage)
2245             return getBlockMinDataSize(m_program->getShaders()[0]->getDefaultBlock().interfaceBlocks[interfaceNdx]);
2246     }
2247 
2248     DE_ASSERT(false);
2249     return -1;
2250 }
2251 
2252 class AtomicCounterCase : public TestCase
2253 {
2254 public:
2255     AtomicCounterCase(Context &context, const char *name, const char *description);
2256     ~AtomicCounterCase(void);
2257 
2258 private:
2259     void init(void);
2260     void deinit(void);
2261 
2262 protected:
2263     int getNumAtomicCounterBuffers(void) const;
2264     int getMaxNumActiveVariables(void) const;
2265     int getBufferVariableCount(int binding) const;
2266     int getBufferMinimumDataSize(int binding) const;
2267 
2268     ProgramInterfaceDefinition::Program *m_program;
2269 };
2270 
AtomicCounterCase(Context & context,const char * name,const char * description)2271 AtomicCounterCase::AtomicCounterCase(Context &context, const char *name, const char *description)
2272     : TestCase(context, name, description)
2273     , m_program(DE_NULL)
2274 {
2275 }
2276 
~AtomicCounterCase(void)2277 AtomicCounterCase::~AtomicCounterCase(void)
2278 {
2279     deinit();
2280 }
2281 
init(void)2282 void AtomicCounterCase::init(void)
2283 {
2284     ProgramInterfaceDefinition::Shader *shader;
2285     glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
2286 
2287     m_program = new ProgramInterfaceDefinition::Program();
2288     shader    = m_program->addShader(glu::SHADERTYPE_COMPUTE, glslVersion);
2289 
2290     {
2291         glu::VariableDeclaration decl(glu::VarType(glu::TYPE_UINT_ATOMIC_COUNTER, glu::PRECISION_LAST),
2292                                       "binding1_counter1", glu::STORAGE_UNIFORM);
2293         decl.layout.binding = 1;
2294         shader->getDefaultBlock().variables.push_back(decl);
2295     }
2296     {
2297         glu::VariableDeclaration decl(glu::VarType(glu::TYPE_UINT_ATOMIC_COUNTER, glu::PRECISION_LAST),
2298                                       "binding1_counter2", glu::STORAGE_UNIFORM);
2299         decl.layout.binding = 1;
2300         decl.layout.offset  = 8;
2301 
2302         shader->getDefaultBlock().variables.push_back(decl);
2303     }
2304     {
2305         glu::VariableDeclaration decl(glu::VarType(glu::TYPE_UINT_ATOMIC_COUNTER, glu::PRECISION_LAST),
2306                                       "binding2_counter1", glu::STORAGE_UNIFORM);
2307         decl.layout.binding = 2;
2308         shader->getDefaultBlock().variables.push_back(decl);
2309     }
2310 
2311     DE_ASSERT(m_program->isValid());
2312 }
2313 
deinit(void)2314 void AtomicCounterCase::deinit(void)
2315 {
2316     delete m_program;
2317     m_program = DE_NULL;
2318 }
2319 
getNumAtomicCounterBuffers(void) const2320 int AtomicCounterCase::getNumAtomicCounterBuffers(void) const
2321 {
2322     std::set<int> buffers;
2323 
2324     for (int ndx = 0; ndx < (int)m_program->getShaders()[0]->getDefaultBlock().variables.size(); ++ndx)
2325     {
2326         if (m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.isBasicType() &&
2327             glu::isDataTypeAtomicCounter(
2328                 m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.getBasicType()))
2329         {
2330             buffers.insert(m_program->getShaders()[0]->getDefaultBlock().variables[ndx].layout.binding);
2331         }
2332     }
2333 
2334     return (int)buffers.size();
2335 }
2336 
getMaxNumActiveVariables(void) const2337 int AtomicCounterCase::getMaxNumActiveVariables(void) const
2338 {
2339     int maxVars = 0;
2340     std::map<int, int> numBufferVars;
2341 
2342     for (int ndx = 0; ndx < (int)m_program->getShaders()[0]->getDefaultBlock().variables.size(); ++ndx)
2343     {
2344         if (m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.isBasicType() &&
2345             glu::isDataTypeAtomicCounter(
2346                 m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.getBasicType()))
2347         {
2348             const int binding = m_program->getShaders()[0]->getDefaultBlock().variables[ndx].layout.binding;
2349 
2350             if (numBufferVars.find(binding) == numBufferVars.end())
2351                 numBufferVars[binding] = 1;
2352             else
2353                 ++numBufferVars[binding];
2354         }
2355     }
2356 
2357     for (std::map<int, int>::const_iterator it = numBufferVars.begin(); it != numBufferVars.end(); ++it)
2358         maxVars = de::max(maxVars, it->second);
2359 
2360     return maxVars;
2361 }
2362 
getBufferVariableCount(int binding) const2363 int AtomicCounterCase::getBufferVariableCount(int binding) const
2364 {
2365     int numVars = 0;
2366 
2367     for (int ndx = 0; ndx < (int)m_program->getShaders()[0]->getDefaultBlock().variables.size(); ++ndx)
2368     {
2369         if (m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.isBasicType() &&
2370             glu::isDataTypeAtomicCounter(
2371                 m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.getBasicType()) &&
2372             m_program->getShaders()[0]->getDefaultBlock().variables[ndx].layout.binding == binding)
2373             ++numVars;
2374     }
2375 
2376     return numVars;
2377 }
2378 
getBufferMinimumDataSize(int binding) const2379 int AtomicCounterCase::getBufferMinimumDataSize(int binding) const
2380 {
2381     int minSize       = -1;
2382     int currentOffset = 0;
2383 
2384     for (int ndx = 0; ndx < (int)m_program->getShaders()[0]->getDefaultBlock().variables.size(); ++ndx)
2385     {
2386         if (m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.isBasicType() &&
2387             glu::isDataTypeAtomicCounter(
2388                 m_program->getShaders()[0]->getDefaultBlock().variables[ndx].varType.getBasicType()) &&
2389             m_program->getShaders()[0]->getDefaultBlock().variables[ndx].layout.binding == binding)
2390         {
2391             const int thisOffset = (m_program->getShaders()[0]->getDefaultBlock().variables[ndx].layout.offset != -1) ?
2392                                        (m_program->getShaders()[0]->getDefaultBlock().variables[ndx].layout.offset) :
2393                                        (currentOffset);
2394             currentOffset        = thisOffset + 4;
2395 
2396             minSize = de::max(minSize, thisOffset + 4);
2397         }
2398     }
2399 
2400     return minSize;
2401 }
2402 
2403 class AtomicCounterResourceListCase : public AtomicCounterCase
2404 {
2405 public:
2406     AtomicCounterResourceListCase(Context &context, const char *name, const char *description);
2407 
2408 private:
2409     IterateResult iterate(void);
2410 };
2411 
AtomicCounterResourceListCase(Context & context,const char * name,const char * description)2412 AtomicCounterResourceListCase::AtomicCounterResourceListCase(Context &context, const char *name,
2413                                                              const char *description)
2414     : AtomicCounterCase(context, name, description)
2415 {
2416 }
2417 
iterate(void)2418 AtomicCounterResourceListCase::IterateResult AtomicCounterResourceListCase::iterate(void)
2419 {
2420     const glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
2421 
2422     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2423     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2424 
2425     {
2426         const tcu::ScopedLogSection section(m_testCtx.getLog(), "ActiveResources", "ACTIVE_RESOURCES");
2427         const glw::Functions &gl             = m_context.getRenderContext().getFunctions();
2428         glw::GLint numActiveResources        = -1;
2429         const int numExpectedActiveResources = 2; // 2 buffer bindings
2430 
2431         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying ACTIVE_RESOURCES, expecting "
2432                            << numExpectedActiveResources << tcu::TestLog::EndMessage;
2433 
2434         gl.getProgramInterfaceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES,
2435                                  &numActiveResources);
2436         GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_ACTIVE_RESOURCES");
2437 
2438         m_testCtx.getLog() << tcu::TestLog::Message << "ACTIVE_RESOURCES = " << numActiveResources
2439                            << tcu::TestLog::EndMessage;
2440 
2441         if (numActiveResources != numExpectedActiveResources)
2442         {
2443             m_testCtx.getLog() << tcu::TestLog::Message << "Error, got unexpected ACTIVE_RESOURCES"
2444                                << tcu::TestLog::EndMessage;
2445             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected ACTIVE_RESOURCES");
2446         }
2447         else
2448             m_testCtx.getLog() << tcu::TestLog::Message << "ACTIVE_RESOURCES valid" << tcu::TestLog::EndMessage;
2449     }
2450 
2451     return STOP;
2452 }
2453 
2454 class AtomicCounterActiveVariablesCase : public AtomicCounterCase
2455 {
2456 public:
2457     AtomicCounterActiveVariablesCase(Context &context, const char *name, const char *description);
2458 
2459 private:
2460     IterateResult iterate(void);
2461 };
2462 
AtomicCounterActiveVariablesCase(Context & context,const char * name,const char * description)2463 AtomicCounterActiveVariablesCase::AtomicCounterActiveVariablesCase(Context &context, const char *name,
2464                                                                    const char *description)
2465     : AtomicCounterCase(context, name, description)
2466 {
2467 }
2468 
iterate(void)2469 AtomicCounterActiveVariablesCase::IterateResult AtomicCounterActiveVariablesCase::iterate(void)
2470 {
2471     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2472     const glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
2473     const int numAtomicBuffers              = getNumAtomicCounterBuffers();
2474     const int expectedMaxNumActiveVariables = getMaxNumActiveVariables();
2475 
2476     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2477     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2478 
2479     // check active variables
2480     {
2481         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Interface", "ATOMIC_COUNTER_BUFFER interface");
2482         glw::GLint queryActiveResources       = -1;
2483         glw::GLint queryMaxNumActiveVariables = -1;
2484 
2485         gl.getProgramInterfaceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES,
2486                                  &queryActiveResources);
2487         gl.getProgramInterfaceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, GL_MAX_NUM_ACTIVE_VARIABLES,
2488                                  &queryMaxNumActiveVariables);
2489         GLU_EXPECT_NO_ERROR(gl.getError(), "query interface");
2490 
2491         m_testCtx.getLog() << tcu::TestLog::Message << "GL_ACTIVE_RESOURCES = " << queryActiveResources << "\n"
2492                            << "GL_MAX_NUM_ACTIVE_VARIABLES = " << queryMaxNumActiveVariables << "\n"
2493                            << tcu::TestLog::EndMessage;
2494 
2495         if (queryActiveResources != numAtomicBuffers)
2496         {
2497             m_testCtx.getLog() << tcu::TestLog::Message << "Error, got unexpected GL_ACTIVE_RESOURCES, expected "
2498                                << numAtomicBuffers << tcu::TestLog::EndMessage;
2499             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected GL_ACTIVE_RESOURCES");
2500         }
2501 
2502         if (queryMaxNumActiveVariables != expectedMaxNumActiveVariables)
2503         {
2504             m_testCtx.getLog() << tcu::TestLog::Message
2505                                << "Error, got unexpected GL_MAX_NUM_ACTIVE_VARIABLES, expected "
2506                                << expectedMaxNumActiveVariables << tcu::TestLog::EndMessage;
2507             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected GL_MAX_NUM_ACTIVE_VARIABLES");
2508         }
2509     }
2510 
2511     // Check each buffer
2512     for (int bufferNdx = 0; bufferNdx < numAtomicBuffers; ++bufferNdx)
2513     {
2514         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Resource",
2515                                             "Resource index " + de::toString(bufferNdx));
2516         std::vector<glw::GLint> activeVariables;
2517         std::vector<std::string> memberNames;
2518 
2519         // Find active variables
2520         {
2521             const glw::GLenum numActiveVariablesProp = GL_NUM_ACTIVE_VARIABLES;
2522             const glw::GLenum activeVariablesProp    = GL_ACTIVE_VARIABLES;
2523             glw::GLint numActiveVariables            = -2;
2524             glw::GLint written                       = -1;
2525 
2526             gl.getProgramResourceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, bufferNdx, 1,
2527                                     &numActiveVariablesProp, 1, &written, &numActiveVariables);
2528             GLU_EXPECT_NO_ERROR(gl.getError(), "query num active variables");
2529 
2530             if (numActiveVariables <= 0)
2531             {
2532                 m_testCtx.getLog() << tcu::TestLog::Message
2533                                    << "Error, got unexpected NUM_ACTIVE_VARIABLES: " << numActiveVariables
2534                                    << tcu::TestLog::EndMessage;
2535                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected NUM_ACTIVE_VARIABLES");
2536                 continue;
2537             }
2538 
2539             if (written <= 0)
2540             {
2541                 m_testCtx.getLog() << tcu::TestLog::Message
2542                                    << "Error, query for NUM_ACTIVE_VARIABLES returned no values"
2543                                    << tcu::TestLog::EndMessage;
2544                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "NUM_ACTIVE_VARIABLES query failed");
2545                 continue;
2546             }
2547 
2548             m_testCtx.getLog() << tcu::TestLog::Message << "GL_NUM_ACTIVE_VARIABLES = " << numActiveVariables
2549                                << tcu::TestLog::EndMessage;
2550 
2551             written = -1;
2552             activeVariables.resize(numActiveVariables + 1, -2);
2553 
2554             gl.getProgramResourceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, bufferNdx, 1, &activeVariablesProp,
2555                                     numActiveVariables, &written, &activeVariables[0]);
2556             GLU_EXPECT_NO_ERROR(gl.getError(), "query active variables");
2557 
2558             if (written != numActiveVariables)
2559             {
2560                 m_testCtx.getLog() << tcu::TestLog::Message
2561                                    << "Error, unexpected number of ACTIVE_VARIABLES, NUM_ACTIVE_VARIABLES = "
2562                                    << numActiveVariables << ", query returned " << written << " values"
2563                                    << tcu::TestLog::EndMessage;
2564                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected ACTIVE_VARIABLES");
2565                 continue;
2566             }
2567 
2568             if (activeVariables.back() != -2)
2569             {
2570                 m_testCtx.getLog() << tcu::TestLog::Message
2571                                    << "Error, query for ACTIVE_VARIABLES wrote over target buffer bounds"
2572                                    << tcu::TestLog::EndMessage;
2573                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "ACTIVE_VARIABLES query failed");
2574                 continue;
2575             }
2576 
2577             activeVariables.pop_back();
2578         }
2579 
2580         // log indices
2581         {
2582             tcu::MessageBuilder builder(&m_testCtx.getLog());
2583 
2584             builder << "Active variable indices: {";
2585             for (int varNdx = 0; varNdx < (int)activeVariables.size(); ++varNdx)
2586             {
2587                 if (varNdx)
2588                     builder << ", ";
2589                 builder << activeVariables[varNdx];
2590             }
2591             builder << "}" << tcu::TestLog::EndMessage;
2592         }
2593 
2594         // collect member names
2595         for (int ndx = 0; ndx < (int)activeVariables.size(); ++ndx)
2596         {
2597             const glw::GLenum nameLengthProp = GL_NAME_LENGTH;
2598             glw::GLint nameLength            = -1;
2599             glw::GLint written               = -1;
2600             std::vector<char> nameBuf;
2601 
2602             gl.getProgramResourceiv(program.getProgram(), GL_UNIFORM, activeVariables[ndx], 1, &nameLengthProp, 1,
2603                                     &written, &nameLength);
2604             GLU_EXPECT_NO_ERROR(gl.getError(), "query buffer variable name length");
2605 
2606             if (written <= 0 || nameLength == -1)
2607             {
2608                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for GL_NAME_LENGTH returned no values"
2609                                    << tcu::TestLog::EndMessage;
2610                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "GL_NAME_LENGTH query failed");
2611                 continue;
2612             }
2613 
2614             nameBuf.resize(
2615                 nameLength + 2,
2616                 'X'); // +2 to tolerate potential off-by-ones in some implementations, name queries will check these cases better
2617             written = -1;
2618 
2619             gl.getProgramResourceName(program.getProgram(), GL_UNIFORM, activeVariables[ndx], (int)nameBuf.size(),
2620                                       &written, &nameBuf[0]);
2621             GLU_EXPECT_NO_ERROR(gl.getError(), "query buffer variable name");
2622 
2623             if (written <= 0)
2624             {
2625                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for resource name returned no name"
2626                                    << tcu::TestLog::EndMessage;
2627                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Name query failed");
2628                 continue;
2629             }
2630 
2631             memberNames.push_back(std::string(&nameBuf[0], written));
2632         }
2633 
2634         // log names
2635         {
2636             tcu::MessageBuilder builder(&m_testCtx.getLog());
2637 
2638             builder << "Active variables:\n";
2639             for (int varNdx = 0; varNdx < (int)memberNames.size(); ++varNdx)
2640             {
2641                 builder << "\t" << memberNames[varNdx] << "\n";
2642             }
2643             builder << tcu::TestLog::EndMessage;
2644         }
2645 
2646         // check names are all in the same buffer
2647         {
2648             bool bindingsValid = true;
2649 
2650             m_testCtx.getLog() << tcu::TestLog::Message << "Verifying names" << tcu::TestLog::EndMessage;
2651 
2652             for (int nameNdx = 0; nameNdx < (int)memberNames.size(); ++nameNdx)
2653             {
2654                 int prevBinding = -1;
2655 
2656                 for (int varNdx = 0; varNdx < (int)m_program->getShaders()[0]->getDefaultBlock().variables.size();
2657                      ++varNdx)
2658                 {
2659                     if (m_program->getShaders()[0]->getDefaultBlock().variables[varNdx].name == memberNames[nameNdx])
2660                     {
2661                         const int varBinding =
2662                             m_program->getShaders()[0]->getDefaultBlock().variables[varNdx].layout.binding;
2663 
2664                         if (prevBinding == -1 || prevBinding == varBinding)
2665                             prevBinding = varBinding;
2666                         else
2667                             bindingsValid = false;
2668                     }
2669                 }
2670 
2671                 if (prevBinding == -1)
2672                 {
2673                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, could not find variable with name \""
2674                                        << memberNames[nameNdx] << "\"" << tcu::TestLog::EndMessage;
2675                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Variable name invalid");
2676                 }
2677                 else if (getBufferVariableCount(prevBinding) != (int)memberNames.size())
2678                 {
2679                     m_testCtx.getLog() << tcu::TestLog::Message << "Error, unexpected variable count for binding "
2680                                        << prevBinding << ". Expected " << getBufferVariableCount(prevBinding)
2681                                        << ", got " << (int)memberNames.size() << tcu::TestLog::EndMessage;
2682                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Variable names invalid");
2683                 }
2684             }
2685 
2686             if (!bindingsValid)
2687             {
2688                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, all resource do not share the same buffer"
2689                                    << tcu::TestLog::EndMessage;
2690                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Active variables invalid");
2691                 continue;
2692             }
2693         }
2694     }
2695 
2696     return STOP;
2697 }
2698 
2699 class AtomicCounterBufferBindingCase : public AtomicCounterCase
2700 {
2701 public:
2702     AtomicCounterBufferBindingCase(Context &context, const char *name, const char *description);
2703 
2704 private:
2705     IterateResult iterate(void);
2706 };
2707 
AtomicCounterBufferBindingCase(Context & context,const char * name,const char * description)2708 AtomicCounterBufferBindingCase::AtomicCounterBufferBindingCase(Context &context, const char *name,
2709                                                                const char *description)
2710     : AtomicCounterCase(context, name, description)
2711 {
2712 }
2713 
iterate(void)2714 AtomicCounterBufferBindingCase::IterateResult AtomicCounterBufferBindingCase::iterate(void)
2715 {
2716     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2717     const glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
2718     const int numAtomicBuffers = getNumAtomicCounterBuffers();
2719 
2720     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2721     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2722 
2723     // check every buffer
2724     for (int bufferNdx = 0; bufferNdx < numAtomicBuffers; ++bufferNdx)
2725     {
2726         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Resource",
2727                                             "Resource index " + de::toString(bufferNdx));
2728         const glw::GLenum bufferBindingProp = GL_BUFFER_BINDING;
2729         glw::GLint bufferBinding            = -1;
2730         glw::GLint written                  = -1;
2731 
2732         gl.getProgramResourceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, bufferNdx, 1, &bufferBindingProp, 1,
2733                                 &written, &bufferBinding);
2734         GLU_EXPECT_NO_ERROR(gl.getError(), "query buffer binding");
2735 
2736         if (written <= 0)
2737         {
2738             m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for BUFFER_BINDING returned no values."
2739                                << tcu::TestLog::EndMessage;
2740             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "BUFFER_BINDING query failed");
2741         }
2742 
2743         m_testCtx.getLog() << tcu::TestLog::Message << "GL_BUFFER_BINDING = " << bufferBinding
2744                            << tcu::TestLog::EndMessage;
2745 
2746         // no such buffer binding?
2747         if (getBufferVariableCount(bufferBinding) == 0)
2748         {
2749             m_testCtx.getLog() << tcu::TestLog::Message << "Error, got buffer with BUFFER_BINDING = " << bufferBinding
2750                                << ", but such buffer does not exist." << tcu::TestLog::EndMessage;
2751             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected BUFFER_BINDING");
2752         }
2753     }
2754 
2755     return STOP;
2756 }
2757 
2758 class AtomicCounterBufferDataSizeCase : public AtomicCounterCase
2759 {
2760 public:
2761     AtomicCounterBufferDataSizeCase(Context &context, const char *name, const char *description);
2762 
2763 private:
2764     IterateResult iterate(void);
2765 };
2766 
AtomicCounterBufferDataSizeCase(Context & context,const char * name,const char * description)2767 AtomicCounterBufferDataSizeCase::AtomicCounterBufferDataSizeCase(Context &context, const char *name,
2768                                                                  const char *description)
2769     : AtomicCounterCase(context, name, description)
2770 {
2771 }
2772 
iterate(void)2773 AtomicCounterBufferDataSizeCase::IterateResult AtomicCounterBufferDataSizeCase::iterate(void)
2774 {
2775     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2776     const glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
2777     const int numAtomicBuffers = getNumAtomicCounterBuffers();
2778 
2779     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2780     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2781 
2782     // check every buffer
2783     for (int bufferNdx = 0; bufferNdx < numAtomicBuffers; ++bufferNdx)
2784     {
2785         const tcu::ScopedLogSection section(m_testCtx.getLog(), "Resource",
2786                                             "Resource index " + de::toString(bufferNdx));
2787         const glw::GLenum props[] = {GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE};
2788         glw::GLint values[]       = {-1, -1};
2789         glw::GLint written        = -1;
2790         int bufferMinDataSize;
2791 
2792         gl.getProgramResourceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, bufferNdx, DE_LENGTH_OF_ARRAY(props),
2793                                 props, DE_LENGTH_OF_ARRAY(values), &written, values);
2794         GLU_EXPECT_NO_ERROR(gl.getError(), "query buffer binding");
2795 
2796         if (written != 2)
2797         {
2798             m_testCtx.getLog() << tcu::TestLog::Message
2799                                << "Error, query for (BUFFER_BINDING, BUFFER_DATA_SIZE) returned " << written
2800                                << " value(s)." << tcu::TestLog::EndMessage;
2801             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "property query failed");
2802             continue;
2803         }
2804 
2805         m_testCtx.getLog() << tcu::TestLog::Message << "GL_BUFFER_BINDING = " << values[0] << "\n"
2806                            << "GL_BUFFER_DATA_SIZE = " << values[1] << tcu::TestLog::EndMessage;
2807 
2808         bufferMinDataSize = getBufferMinimumDataSize(values[0]);
2809         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying data size, expected greater than or equal to "
2810                            << bufferMinDataSize << tcu::TestLog::EndMessage;
2811 
2812         // no such buffer binding?
2813         if (bufferMinDataSize == -1)
2814         {
2815             m_testCtx.getLog() << tcu::TestLog::Message << "Error, got buffer with BUFFER_BINDING = " << values[0]
2816                                << ", but such buffer does not exist." << tcu::TestLog::EndMessage;
2817             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected BUFFER_BINDING");
2818         }
2819         else if (values[1] < bufferMinDataSize)
2820         {
2821             m_testCtx.getLog() << tcu::TestLog::Message << "Error, got buffer with BUFFER_DATA_SIZE = " << values[1]
2822                                << ", expected greater than or equal to " << bufferMinDataSize
2823                                << tcu::TestLog::EndMessage;
2824             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected BUFFER_BINDING");
2825         }
2826         else
2827             m_testCtx.getLog() << tcu::TestLog::Message << "Data size valid" << tcu::TestLog::EndMessage;
2828     }
2829 
2830     return STOP;
2831 }
2832 
2833 class AtomicCounterReferencedByCase : public TestCase
2834 {
2835 public:
2836     AtomicCounterReferencedByCase(Context &context, const char *name, const char *description, bool separable,
2837                                   uint32_t presentStagesMask, uint32_t activeStagesMask);
2838     ~AtomicCounterReferencedByCase(void);
2839 
2840 private:
2841     void init(void);
2842     void deinit(void);
2843     IterateResult iterate(void);
2844 
2845     const bool m_separable;
2846     const uint32_t m_presentStagesMask;
2847     const uint32_t m_activeStagesMask;
2848     ProgramInterfaceDefinition::Program *m_program;
2849 };
2850 
AtomicCounterReferencedByCase(Context & context,const char * name,const char * description,bool separable,uint32_t presentStagesMask,uint32_t activeStagesMask)2851 AtomicCounterReferencedByCase::AtomicCounterReferencedByCase(Context &context, const char *name,
2852                                                              const char *description, bool separable,
2853                                                              uint32_t presentStagesMask, uint32_t activeStagesMask)
2854     : TestCase(context, name, description)
2855     , m_separable(separable)
2856     , m_presentStagesMask(presentStagesMask)
2857     , m_activeStagesMask(activeStagesMask)
2858     , m_program(DE_NULL)
2859 {
2860     DE_ASSERT((activeStagesMask & presentStagesMask) == activeStagesMask);
2861 }
2862 
~AtomicCounterReferencedByCase(void)2863 AtomicCounterReferencedByCase::~AtomicCounterReferencedByCase(void)
2864 {
2865     deinit();
2866 }
2867 
init(void)2868 void AtomicCounterReferencedByCase::init(void)
2869 {
2870     const uint32_t geometryMask = (1 << glu::SHADERTYPE_GEOMETRY);
2871     const uint32_t tessellationMask =
2872         (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) | (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
2873     glu::VariableDeclaration atomicVar(glu::VarType(glu::TYPE_UINT_ATOMIC_COUNTER, glu::PRECISION_LAST),
2874                                        "targetCounter", glu::STORAGE_UNIFORM);
2875     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
2876     const bool supportsES32orGL45      = checkSupport(m_context);
2877 
2878     if ((m_presentStagesMask & tessellationMask) != 0 && !supportsES32orGL45 &&
2879         !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2880         throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2881     if ((m_presentStagesMask & geometryMask) != 0 && !supportsES32orGL45 &&
2882         !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2883         throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
2884 
2885     atomicVar.layout.binding = 1;
2886 
2887     m_program = new ProgramInterfaceDefinition::Program();
2888     m_program->setSeparable(m_separable);
2889 
2890     for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
2891     {
2892         if (m_activeStagesMask & (1 << shaderType))
2893             m_program->addShader((glu::ShaderType)shaderType, glslVersion)
2894                 ->getDefaultBlock()
2895                 .variables.push_back(atomicVar);
2896         else if (m_presentStagesMask & (1 << shaderType))
2897             m_program->addShader((glu::ShaderType)shaderType, glslVersion);
2898     }
2899 
2900     if (m_program->hasStage(glu::SHADERTYPE_GEOMETRY))
2901         m_program->setGeometryNumOutputVertices(1);
2902     if (m_program->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
2903         m_program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
2904         m_program->setTessellationNumOutputPatchVertices(1);
2905 
2906     DE_ASSERT(m_program->isValid());
2907 }
2908 
deinit(void)2909 void AtomicCounterReferencedByCase::deinit(void)
2910 {
2911     delete m_program;
2912     m_program = DE_NULL;
2913 }
2914 
iterate(void)2915 AtomicCounterReferencedByCase::IterateResult AtomicCounterReferencedByCase::iterate(void)
2916 {
2917     const glu::RenderContext &rc = m_context.getRenderContext();
2918     const bool isES32orGL45      = glu::contextSupports(rc.getType(), glu::ApiType::es(3, 2)) ||
2919                               glu::contextSupports(rc.getType(), glu::ApiType::core(4, 5));
2920 
2921     const struct
2922     {
2923         glw::GLenum propName;
2924         glu::ShaderType shaderType;
2925         const char *extension;
2926     } targetProps[] = {
2927         {GL_REFERENCED_BY_VERTEX_SHADER, glu::SHADERTYPE_VERTEX, DE_NULL},
2928         {GL_REFERENCED_BY_FRAGMENT_SHADER, glu::SHADERTYPE_FRAGMENT, DE_NULL},
2929         {GL_REFERENCED_BY_COMPUTE_SHADER, glu::SHADERTYPE_COMPUTE, DE_NULL},
2930         {GL_REFERENCED_BY_TESS_CONTROL_SHADER, glu::SHADERTYPE_TESSELLATION_CONTROL,
2931          (isES32orGL45 ? DE_NULL : "GL_EXT_tessellation_shader")},
2932         {GL_REFERENCED_BY_TESS_EVALUATION_SHADER, glu::SHADERTYPE_TESSELLATION_EVALUATION,
2933          (isES32orGL45 ? DE_NULL : "GL_EXT_tessellation_shader")},
2934         {GL_REFERENCED_BY_GEOMETRY_SHADER, glu::SHADERTYPE_GEOMETRY,
2935          (isES32orGL45 ? DE_NULL : "GL_EXT_geometry_shader")},
2936     };
2937 
2938     const glw::Functions &gl = rc.getFunctions();
2939     const glu::ShaderProgram program(rc, generateProgramInterfaceProgramSources(m_program));
2940 
2941     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2942     checkAndLogProgram(program, m_program, rc.getFunctions(), m_testCtx.getLog());
2943 
2944     // check props
2945     for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(targetProps); ++propNdx)
2946     {
2947         if (targetProps[propNdx].extension == DE_NULL ||
2948             m_context.getContextInfo().isExtensionSupported(targetProps[propNdx].extension))
2949         {
2950             const glw::GLenum prop = targetProps[propNdx].propName;
2951             const glw::GLint expected =
2952                 ((m_activeStagesMask & (1 << targetProps[propNdx].shaderType)) != 0) ? (GL_TRUE) : (GL_FALSE);
2953             glw::GLint value   = -1;
2954             glw::GLint written = -1;
2955 
2956             m_testCtx.getLog() << tcu::TestLog::Message << "Verifying " << glu::getProgramResourcePropertyName(prop)
2957                                << ", expecting " << glu::getBooleanName(expected) << tcu::TestLog::EndMessage;
2958 
2959             gl.getProgramResourceiv(program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, 0, 1, &prop, 1, &written, &value);
2960             GLU_EXPECT_NO_ERROR(gl.getError(), "query buffer binding");
2961 
2962             if (written != 1)
2963             {
2964                 m_testCtx.getLog() << tcu::TestLog::Message
2965                                    << "Error, query for referenced_by_* returned invalid number of values."
2966                                    << tcu::TestLog::EndMessage;
2967                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "property query failed");
2968                 continue;
2969             }
2970 
2971             m_testCtx.getLog() << tcu::TestLog::Message << glu::getProgramResourcePropertyName(prop) << " = "
2972                                << glu::getBooleanStr(value) << tcu::TestLog::EndMessage;
2973 
2974             if (value != expected)
2975             {
2976                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, got unexpected value"
2977                                    << tcu::TestLog::EndMessage;
2978                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "unexpected property value");
2979                 continue;
2980             }
2981         }
2982     }
2983 
2984     return STOP;
2985 }
2986 
2987 class ProgramInputOutputReferencedByCase : public TestCase
2988 {
2989 public:
2990     enum CaseType
2991     {
2992         CASE_VERTEX_FRAGMENT = 0,
2993         CASE_VERTEX_GEO_FRAGMENT,
2994         CASE_VERTEX_TESS_FRAGMENT,
2995         CASE_VERTEX_TESS_GEO_FRAGMENT,
2996 
2997         CASE_SEPARABLE_VERTEX,
2998         CASE_SEPARABLE_FRAGMENT,
2999         CASE_SEPARABLE_GEOMETRY,
3000         CASE_SEPARABLE_TESS_CTRL,
3001         CASE_SEPARABLE_TESS_EVAL,
3002 
3003         CASE_LAST
3004     };
3005     ProgramInputOutputReferencedByCase(Context &context, const char *name, const char *description,
3006                                        glu::Storage targetStorage, CaseType caseType);
3007     ~ProgramInputOutputReferencedByCase(void);
3008 
3009 private:
3010     void init(void);
3011     void deinit(void);
3012     IterateResult iterate(void);
3013 
3014     const CaseType m_caseType;
3015     const glu::Storage m_targetStorage;
3016     ProgramInterfaceDefinition::Program *m_program;
3017 };
3018 
ProgramInputOutputReferencedByCase(Context & context,const char * name,const char * description,glu::Storage targetStorage,CaseType caseType)3019 ProgramInputOutputReferencedByCase::ProgramInputOutputReferencedByCase(Context &context, const char *name,
3020                                                                        const char *description,
3021                                                                        glu::Storage targetStorage, CaseType caseType)
3022     : TestCase(context, name, description)
3023     , m_caseType(caseType)
3024     , m_targetStorage(targetStorage)
3025     , m_program(DE_NULL)
3026 {
3027     DE_ASSERT(caseType < CASE_LAST);
3028 }
3029 
~ProgramInputOutputReferencedByCase(void)3030 ProgramInputOutputReferencedByCase::~ProgramInputOutputReferencedByCase(void)
3031 {
3032     deinit();
3033 }
3034 
init(void)3035 void ProgramInputOutputReferencedByCase::init(void)
3036 {
3037     const bool hasTessellationShader =
3038         (m_caseType == CASE_VERTEX_TESS_FRAGMENT) || (m_caseType == CASE_VERTEX_TESS_GEO_FRAGMENT) ||
3039         (m_caseType == CASE_SEPARABLE_TESS_CTRL) || (m_caseType == CASE_SEPARABLE_TESS_EVAL);
3040     const bool hasGeometryShader = (m_caseType == CASE_VERTEX_GEO_FRAGMENT) ||
3041                                    (m_caseType == CASE_VERTEX_TESS_GEO_FRAGMENT) ||
3042                                    (m_caseType == CASE_SEPARABLE_GEOMETRY);
3043     const bool supportsES32orGL45 = checkSupport(m_context);
3044 
3045     if (hasTessellationShader && !supportsES32orGL45 &&
3046         !m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
3047         throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
3048     if (hasGeometryShader && !supportsES32orGL45 &&
3049         !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
3050         throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
3051 
3052     glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
3053     m_program                    = new ProgramInterfaceDefinition::Program();
3054 
3055     if (m_caseType == CASE_SEPARABLE_VERTEX || m_caseType == CASE_SEPARABLE_FRAGMENT ||
3056         m_caseType == CASE_SEPARABLE_GEOMETRY || m_caseType == CASE_SEPARABLE_TESS_CTRL ||
3057         m_caseType == CASE_SEPARABLE_TESS_EVAL)
3058     {
3059         const bool isInputCase = (m_targetStorage == glu::STORAGE_IN || m_targetStorage == glu::STORAGE_PATCH_IN);
3060         const bool perPatchStorage =
3061             (m_targetStorage == glu::STORAGE_PATCH_IN || m_targetStorage == glu::STORAGE_PATCH_OUT);
3062         const char *varName = (isInputCase) ? ("shaderInput") : ("shaderOutput");
3063         const glu::VariableDeclaration targetDecl(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), varName,
3064                                                   m_targetStorage);
3065         const glu::ShaderType shaderType =
3066             (m_caseType == CASE_SEPARABLE_VERTEX)    ? (glu::SHADERTYPE_VERTEX) :
3067             (m_caseType == CASE_SEPARABLE_FRAGMENT)  ? (glu::SHADERTYPE_FRAGMENT) :
3068             (m_caseType == CASE_SEPARABLE_GEOMETRY)  ? (glu::SHADERTYPE_GEOMETRY) :
3069             (m_caseType == CASE_SEPARABLE_TESS_CTRL) ? (glu::SHADERTYPE_TESSELLATION_CONTROL) :
3070             (m_caseType == CASE_SEPARABLE_TESS_EVAL) ? (glu::SHADERTYPE_TESSELLATION_EVALUATION) :
3071                                                        (glu::SHADERTYPE_LAST);
3072         const bool arrayedInterface = (isInputCase) ? ((shaderType == glu::SHADERTYPE_GEOMETRY) ||
3073                                                        (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) ||
3074                                                        (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)) :
3075                                                       (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL);
3076 
3077         m_program->setSeparable(true);
3078 
3079         if (arrayedInterface && !perPatchStorage)
3080         {
3081             const glu::VariableDeclaration targetDeclArr(glu::VarType(targetDecl.varType, glu::VarType::UNSIZED_ARRAY),
3082                                                          varName, m_targetStorage);
3083             m_program->addShader(shaderType, glslVersion)->getDefaultBlock().variables.push_back(targetDeclArr);
3084         }
3085         else
3086         {
3087             m_program->addShader(shaderType, glslVersion)->getDefaultBlock().variables.push_back(targetDecl);
3088         }
3089     }
3090     else if (m_caseType == CASE_VERTEX_FRAGMENT || m_caseType == CASE_VERTEX_GEO_FRAGMENT ||
3091              m_caseType == CASE_VERTEX_TESS_FRAGMENT || m_caseType == CASE_VERTEX_TESS_GEO_FRAGMENT)
3092     {
3093         ProgramInterfaceDefinition::Shader *vertex   = m_program->addShader(glu::SHADERTYPE_VERTEX, glslVersion);
3094         ProgramInterfaceDefinition::Shader *fragment = m_program->addShader(glu::SHADERTYPE_FRAGMENT, glslVersion);
3095 
3096         m_program->setSeparable(false);
3097 
3098         vertex->getDefaultBlock().variables.push_back(glu::VariableDeclaration(
3099             glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "shaderInput", glu::STORAGE_IN));
3100         vertex->getDefaultBlock().variables.push_back(
3101             glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "shaderOutput",
3102                                      glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(1)));
3103 
3104         fragment->getDefaultBlock().variables.push_back(
3105             glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "shaderOutput",
3106                                      glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(0)));
3107         fragment->getDefaultBlock().variables.push_back(
3108             glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "shaderInput",
3109                                      glu::STORAGE_IN, glu::INTERPOLATION_LAST, glu::Layout(1)));
3110 
3111         if (m_caseType == CASE_VERTEX_TESS_FRAGMENT || m_caseType == CASE_VERTEX_TESS_GEO_FRAGMENT)
3112         {
3113             ProgramInterfaceDefinition::Shader *tessCtrl =
3114                 m_program->addShader(glu::SHADERTYPE_TESSELLATION_CONTROL, glslVersion);
3115             ProgramInterfaceDefinition::Shader *tessEval =
3116                 m_program->addShader(glu::SHADERTYPE_TESSELLATION_EVALUATION, glslVersion);
3117 
3118             tessCtrl->getDefaultBlock().variables.push_back(glu::VariableDeclaration(
3119                 glu::VarType(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), glu::VarType::UNSIZED_ARRAY),
3120                 "shaderInput", glu::STORAGE_IN, glu::INTERPOLATION_LAST, glu::Layout(1)));
3121             tessCtrl->getDefaultBlock().variables.push_back(glu::VariableDeclaration(
3122                 glu::VarType(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), glu::VarType::UNSIZED_ARRAY),
3123                 "shaderOutput", glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(1)));
3124 
3125             tessEval->getDefaultBlock().variables.push_back(glu::VariableDeclaration(
3126                 glu::VarType(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), glu::VarType::UNSIZED_ARRAY),
3127                 "shaderInput", glu::STORAGE_IN, glu::INTERPOLATION_LAST, glu::Layout(1)));
3128             tessEval->getDefaultBlock().variables.push_back(
3129                 glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "shaderOutput",
3130                                          glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(1)));
3131         }
3132 
3133         if (m_caseType == CASE_VERTEX_GEO_FRAGMENT || m_caseType == CASE_VERTEX_TESS_GEO_FRAGMENT)
3134         {
3135             ProgramInterfaceDefinition::Shader *geometry = m_program->addShader(glu::SHADERTYPE_GEOMETRY, glslVersion);
3136 
3137             geometry->getDefaultBlock().variables.push_back(glu::VariableDeclaration(
3138                 glu::VarType(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), glu::VarType::UNSIZED_ARRAY),
3139                 "shaderInput", glu::STORAGE_IN, glu::INTERPOLATION_LAST, glu::Layout(1)));
3140             geometry->getDefaultBlock().variables.push_back(
3141                 glu::VariableDeclaration(glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), "shaderOutput",
3142                                          glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(1)));
3143         }
3144     }
3145     else
3146         DE_ASSERT(false);
3147 
3148     if (m_program->hasStage(glu::SHADERTYPE_GEOMETRY))
3149         m_program->setGeometryNumOutputVertices(1);
3150     if (m_program->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
3151         m_program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
3152         m_program->setTessellationNumOutputPatchVertices(1);
3153 
3154     DE_ASSERT(m_program->isValid());
3155 }
3156 
deinit(void)3157 void ProgramInputOutputReferencedByCase::deinit(void)
3158 {
3159     delete m_program;
3160     m_program = DE_NULL;
3161 }
3162 
iterate(void)3163 ProgramInputOutputReferencedByCase::IterateResult ProgramInputOutputReferencedByCase::iterate(void)
3164 {
3165     static const struct
3166     {
3167         glw::GLenum propName;
3168         glu::ShaderType shaderType;
3169         const char *extension;
3170     } targetProps[] = {
3171         {GL_REFERENCED_BY_VERTEX_SHADER, glu::SHADERTYPE_VERTEX, DE_NULL},
3172         {GL_REFERENCED_BY_FRAGMENT_SHADER, glu::SHADERTYPE_FRAGMENT, DE_NULL},
3173         {GL_REFERENCED_BY_COMPUTE_SHADER, glu::SHADERTYPE_COMPUTE, DE_NULL},
3174         {GL_REFERENCED_BY_TESS_CONTROL_SHADER, glu::SHADERTYPE_TESSELLATION_CONTROL, "GL_EXT_tessellation_shader"},
3175         {GL_REFERENCED_BY_TESS_EVALUATION_SHADER, glu::SHADERTYPE_TESSELLATION_EVALUATION,
3176          "GL_EXT_tessellation_shader"},
3177         {GL_REFERENCED_BY_GEOMETRY_SHADER, glu::SHADERTYPE_GEOMETRY, "GL_EXT_geometry_shader"},
3178     };
3179 
3180     const bool isInputCase   = (m_targetStorage == glu::STORAGE_IN || m_targetStorage == glu::STORAGE_PATCH_IN);
3181     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3182     const glu::ShaderProgram program(m_context.getRenderContext(), generateProgramInterfaceProgramSources(m_program));
3183     const std::string targetResourceName = (isInputCase) ? ("shaderInput") : ("shaderOutput");
3184     const glw::GLenum programGLInterface = (isInputCase) ? (GL_PROGRAM_INPUT) : (GL_PROGRAM_OUTPUT);
3185     glw::GLuint resourceIndex;
3186 
3187     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3188     checkAndLogProgram(program, m_program, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
3189 
3190     // find target resource index
3191 
3192     resourceIndex = gl.getProgramResourceIndex(program.getProgram(), programGLInterface, targetResourceName.c_str());
3193     GLU_EXPECT_NO_ERROR(gl.getError(), "query resource index");
3194 
3195     if (resourceIndex == GL_INVALID_INDEX)
3196     {
3197         m_testCtx.getLog() << tcu::TestLog::Message << "Error, query for resource \"" << targetResourceName
3198                            << "\" index returned invalid index." << tcu::TestLog::EndMessage;
3199         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource");
3200         return STOP;
3201     }
3202 
3203     // check props
3204     for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(targetProps); ++propNdx)
3205     {
3206         if (targetProps[propNdx].extension == DE_NULL ||
3207             m_context.getContextInfo().isExtensionSupported(targetProps[propNdx].extension))
3208         {
3209             const glw::GLenum prop = targetProps[propNdx].propName;
3210             const bool expected    = (isInputCase) ? (targetProps[propNdx].shaderType == m_program->getFirstStage()) :
3211                                                      (targetProps[propNdx].shaderType == m_program->getLastStage());
3212             glw::GLint value       = -1;
3213             glw::GLint written     = -1;
3214 
3215             m_testCtx.getLog() << tcu::TestLog::Message << "Verifying " << glu::getProgramResourcePropertyName(prop)
3216                                << ", expecting " << ((expected) ? ("TRUE") : ("FALSE")) << tcu::TestLog::EndMessage;
3217 
3218             gl.getProgramResourceiv(program.getProgram(), programGLInterface, resourceIndex, 1, &prop, 1, &written,
3219                                     &value);
3220             GLU_EXPECT_NO_ERROR(gl.getError(), "query buffer binding");
3221 
3222             if (written != 1)
3223             {
3224                 m_testCtx.getLog() << tcu::TestLog::Message
3225                                    << "Error, query for referenced_by_* returned invalid number of values."
3226                                    << tcu::TestLog::EndMessage;
3227                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "property query failed");
3228                 continue;
3229             }
3230 
3231             m_testCtx.getLog() << tcu::TestLog::Message << glu::getProgramResourcePropertyName(prop) << " = "
3232                                << glu::getBooleanStr(value) << tcu::TestLog::EndMessage;
3233 
3234             if (value != ((expected) ? (GL_TRUE) : (GL_FALSE)))
3235             {
3236                 m_testCtx.getLog() << tcu::TestLog::Message << "Error, got unexpected value"
3237                                    << tcu::TestLog::EndMessage;
3238                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "unexpected property value");
3239                 continue;
3240             }
3241         }
3242     }
3243 
3244     return STOP;
3245 }
3246 
3247 class FeedbackResourceListTestCase : public ResourceListTestCase
3248 {
3249 public:
3250     FeedbackResourceListTestCase(Context &context, const ResourceDefinition::Node::SharedPtr &resource,
3251                                  const char *name);
3252     ~FeedbackResourceListTestCase(void);
3253 
3254 private:
3255     IterateResult iterate(void);
3256 };
3257 
FeedbackResourceListTestCase(Context & context,const ResourceDefinition::Node::SharedPtr & resource,const char * name)3258 FeedbackResourceListTestCase::FeedbackResourceListTestCase(Context &context,
3259                                                            const ResourceDefinition::Node::SharedPtr &resource,
3260                                                            const char *name)
3261     : ResourceListTestCase(context, resource, PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, name)
3262 {
3263 }
3264 
~FeedbackResourceListTestCase(void)3265 FeedbackResourceListTestCase::~FeedbackResourceListTestCase(void)
3266 {
3267     deinit();
3268 }
3269 
iterate(void)3270 FeedbackResourceListTestCase::IterateResult FeedbackResourceListTestCase::iterate(void)
3271 {
3272     const glu::ShaderProgram program(m_context.getRenderContext(),
3273                                      generateProgramInterfaceProgramSources(m_programDefinition));
3274 
3275     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3276 
3277     // Feedback varyings
3278     {
3279         tcu::MessageBuilder builder(&m_testCtx.getLog());
3280         builder << "Transform feedback varyings: {";
3281         for (int ndx = 0; ndx < (int)m_programDefinition->getTransformFeedbackVaryings().size(); ++ndx)
3282         {
3283             if (ndx)
3284                 builder << ", ";
3285             builder << "\"" << m_programDefinition->getTransformFeedbackVaryings()[ndx] << "\"";
3286         }
3287         builder << "}" << tcu::TestLog::EndMessage;
3288     }
3289 
3290     checkAndLogProgram(program, m_programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
3291 
3292     // Check resource list
3293     {
3294         const tcu::ScopedLogSection section(m_testCtx.getLog(), "ResourceList", "Resource list");
3295         std::vector<std::string> resourceList;
3296         std::vector<std::string> expectedResources;
3297 
3298         queryResourceList(resourceList, program.getProgram());
3299         expectedResources = getProgramInterfaceResourceList(m_programDefinition, m_programInterface);
3300 
3301         // verify the list and the expected list match
3302 
3303         if (!verifyResourceList(resourceList, expectedResources))
3304             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid resource list");
3305 
3306         // verify GetProgramResourceIndex() matches the indices of the list
3307 
3308         if (!verifyResourceIndexQuery(resourceList, expectedResources, program.getProgram()))
3309             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "GetProgramResourceIndex returned unexpected values");
3310 
3311         // Verify MAX_NAME_LENGTH
3312         if (!verifyMaxNameLength(resourceList, program.getProgram()))
3313             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "MAX_NAME_LENGTH invalid");
3314     }
3315 
3316     return STOP;
3317 }
3318 
getBlockMinDataSize(const glu::InterfaceBlock & block) const3319 int InterfaceBlockDataSizeTestCase::getBlockMinDataSize(const glu::InterfaceBlock &block) const
3320 {
3321     int dataSize = 0;
3322 
3323     for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx)
3324         dataSize += getVarTypeSize(block.variables[ndx].varType);
3325 
3326     return dataSize;
3327 }
3328 
isDataTypeLayoutQualified(glu::DataType type)3329 static bool isDataTypeLayoutQualified(glu::DataType type)
3330 {
3331     return glu::isDataTypeImage(type) || glu::isDataTypeAtomicCounter(type);
3332 }
3333 
generateVariableCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,int expandLevel=3,bool createTestGroup=true)3334 static void generateVariableCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
3335                                   tcu::TestCaseGroup *const targetGroup,
3336                                   const ProgramResourceQueryTestTarget &queryTarget, int expandLevel = 3,
3337                                   bool createTestGroup = true)
3338 {
3339     static const struct
3340     {
3341         int level;
3342         glu::DataType dataType;
3343     } variableTypes[] = {
3344         {0, glu::TYPE_FLOAT},        {1, glu::TYPE_INT},          {1, glu::TYPE_UINT},
3345         {1, glu::TYPE_BOOL},
3346 
3347         {3, glu::TYPE_FLOAT_VEC2},   {1, glu::TYPE_FLOAT_VEC3},   {1, glu::TYPE_FLOAT_VEC4},
3348 
3349         {3, glu::TYPE_INT_VEC2},     {2, glu::TYPE_INT_VEC3},     {3, glu::TYPE_INT_VEC4},
3350 
3351         {3, glu::TYPE_UINT_VEC2},    {2, glu::TYPE_UINT_VEC3},    {3, glu::TYPE_UINT_VEC4},
3352 
3353         {3, glu::TYPE_BOOL_VEC2},    {2, glu::TYPE_BOOL_VEC3},    {3, glu::TYPE_BOOL_VEC4},
3354 
3355         {2, glu::TYPE_FLOAT_MAT2},   {3, glu::TYPE_FLOAT_MAT2X3}, {3, glu::TYPE_FLOAT_MAT2X4},
3356         {2, glu::TYPE_FLOAT_MAT3X2}, {2, glu::TYPE_FLOAT_MAT3},   {3, glu::TYPE_FLOAT_MAT3X4},
3357         {2, glu::TYPE_FLOAT_MAT4X2}, {3, glu::TYPE_FLOAT_MAT4X3}, {2, glu::TYPE_FLOAT_MAT4},
3358     };
3359 
3360     tcu::TestCaseGroup *group;
3361 
3362     if (createTestGroup)
3363     {
3364         group = new tcu::TestCaseGroup(context.getTestContext(), "basic_type", "Basic variable");
3365         targetGroup->addChild(group);
3366     }
3367     else
3368         group = targetGroup;
3369 
3370     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
3371     {
3372         if (variableTypes[ndx].level <= expandLevel)
3373         {
3374             const ResourceDefinition::Node::SharedPtr variable(
3375                 new ResourceDefinition::Variable(parentStructure, variableTypes[ndx].dataType));
3376             group->addChild(new ResourceTestCase(context, variable, queryTarget));
3377         }
3378     }
3379 }
3380 
generateOpaqueTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,int expandLevel=3,bool createTestGroup=true)3381 static void generateOpaqueTypeCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
3382                                     tcu::TestCaseGroup *const targetGroup,
3383                                     const ProgramResourceQueryTestTarget &queryTarget, int expandLevel = 3,
3384                                     bool createTestGroup = true)
3385 {
3386     static const struct
3387     {
3388         int level;
3389         glu::DataType dataType;
3390     } variableTypes[] = {
3391         {0, glu::TYPE_SAMPLER_2D},
3392         {2, glu::TYPE_SAMPLER_CUBE},
3393         {1, glu::TYPE_SAMPLER_2D_ARRAY},
3394         {1, glu::TYPE_SAMPLER_3D},
3395         {2, glu::TYPE_SAMPLER_2D_SHADOW},
3396         {3, glu::TYPE_SAMPLER_CUBE_SHADOW},
3397         {3, glu::TYPE_SAMPLER_2D_ARRAY_SHADOW},
3398         {1, glu::TYPE_INT_SAMPLER_2D},
3399         {3, glu::TYPE_INT_SAMPLER_CUBE},
3400         {3, glu::TYPE_INT_SAMPLER_2D_ARRAY},
3401         {3, glu::TYPE_INT_SAMPLER_3D},
3402         {2, glu::TYPE_UINT_SAMPLER_2D},
3403         {3, glu::TYPE_UINT_SAMPLER_CUBE},
3404         {3, glu::TYPE_UINT_SAMPLER_2D_ARRAY},
3405         {3, glu::TYPE_UINT_SAMPLER_3D},
3406         {2, glu::TYPE_SAMPLER_2D_MULTISAMPLE},
3407         {2, glu::TYPE_INT_SAMPLER_2D_MULTISAMPLE},
3408         {3, glu::TYPE_UINT_SAMPLER_2D_MULTISAMPLE},
3409         {1, glu::TYPE_IMAGE_2D},
3410         {3, glu::TYPE_IMAGE_CUBE},
3411         {3, glu::TYPE_IMAGE_2D_ARRAY},
3412         {3, glu::TYPE_IMAGE_3D},
3413         {3, glu::TYPE_INT_IMAGE_2D},
3414         {3, glu::TYPE_INT_IMAGE_CUBE},
3415         {1, glu::TYPE_INT_IMAGE_2D_ARRAY},
3416         {3, glu::TYPE_INT_IMAGE_3D},
3417         {2, glu::TYPE_UINT_IMAGE_2D},
3418         {3, glu::TYPE_UINT_IMAGE_CUBE},
3419         {3, glu::TYPE_UINT_IMAGE_2D_ARRAY},
3420         {3, glu::TYPE_UINT_IMAGE_3D},
3421         {1, glu::TYPE_UINT_ATOMIC_COUNTER},
3422     };
3423 
3424     bool isStructMember = false;
3425 
3426     // Requirements
3427     for (const ResourceDefinition::Node *node = parentStructure.get(); node; node = node->getEnclosingNode())
3428     {
3429         // Don't insert inside a interface block
3430         if (node->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK)
3431             return;
3432 
3433         isStructMember |= (node->getType() == ResourceDefinition::Node::TYPE_STRUCT_MEMBER);
3434     }
3435 
3436     // Add cases
3437     {
3438         tcu::TestCaseGroup *group;
3439 
3440         if (createTestGroup)
3441         {
3442             group = new tcu::TestCaseGroup(context.getTestContext(), "opaque_type", "Opaque types");
3443             targetGroup->addChild(group);
3444         }
3445         else
3446             group = targetGroup;
3447 
3448         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
3449         {
3450             if (variableTypes[ndx].level > expandLevel)
3451                 continue;
3452 
3453             // Layout qualifiers are not allowed on struct members
3454             if (isDataTypeLayoutQualified(variableTypes[ndx].dataType) && isStructMember)
3455                 continue;
3456 
3457             {
3458                 const ResourceDefinition::Node::SharedPtr variable(
3459                     new ResourceDefinition::Variable(parentStructure, variableTypes[ndx].dataType));
3460                 group->addChild(new ResourceTestCase(context, variable, queryTarget));
3461             }
3462         }
3463     }
3464 }
3465 
3466 static void generateCompoundVariableCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
3467                                           tcu::TestCaseGroup *const targetGroup,
3468                                           const ProgramResourceQueryTestTarget &queryTarget, int expandLevel = 3);
3469 
generateVariableArrayCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,int expandLevel=3)3470 static void generateVariableArrayCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
3471                                        tcu::TestCaseGroup *const targetGroup,
3472                                        const ProgramResourceQueryTestTarget &queryTarget, int expandLevel = 3)
3473 {
3474     if (expandLevel > 0)
3475     {
3476         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
3477         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "array", "Arrays");
3478 
3479         targetGroup->addChild(blockGroup);
3480 
3481         // Arrays of basic variables
3482         generateVariableCases(context, arrayElement, blockGroup, queryTarget, expandLevel, expandLevel != 1);
3483 
3484         // Arrays of opaque types
3485         generateOpaqueTypeCases(context, arrayElement, blockGroup, queryTarget, expandLevel, expandLevel != 1);
3486 
3487         // Arrays of arrays
3488         generateVariableArrayCases(context, arrayElement, blockGroup, queryTarget, expandLevel - 1);
3489 
3490         // Arrays of structs
3491         generateCompoundVariableCases(context, arrayElement, blockGroup, queryTarget, expandLevel - 1);
3492     }
3493 }
3494 
generateCompoundVariableCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,int expandLevel)3495 static void generateCompoundVariableCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
3496                                           tcu::TestCaseGroup *const targetGroup,
3497                                           const ProgramResourceQueryTestTarget &queryTarget, int expandLevel)
3498 {
3499     if (expandLevel > 0)
3500     {
3501         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
3502         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "struct", "Structs");
3503 
3504         targetGroup->addChild(blockGroup);
3505 
3506         // Struct containing basic variable
3507         generateVariableCases(context, structMember, blockGroup, queryTarget, expandLevel, expandLevel != 1);
3508 
3509         // Struct containing opaque types
3510         generateOpaqueTypeCases(context, structMember, blockGroup, queryTarget, expandLevel, expandLevel != 1);
3511 
3512         // Struct containing arrays
3513         generateVariableArrayCases(context, structMember, blockGroup, queryTarget, expandLevel - 1);
3514 
3515         // Struct containing struct
3516         generateCompoundVariableCases(context, structMember, blockGroup, queryTarget, expandLevel - 1);
3517     }
3518 }
3519 
3520 // Resource list cases
3521 
3522 enum BlockFlags
3523 {
3524     BLOCKFLAG_DEFAULT = 0x01,
3525     BLOCKFLAG_NAMED   = 0x02,
3526     BLOCKFLAG_UNNAMED = 0x04,
3527     BLOCKFLAG_ARRAY   = 0x08,
3528 
3529     BLOCKFLAG_ALL = 0x0F
3530 };
3531 
generateUniformCaseBlocks(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,uint32_t blockFlags,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup * const))3532 static void generateUniformCaseBlocks(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
3533                                       tcu::TestCaseGroup *const targetGroup, uint32_t blockFlags,
3534                                       void (*blockContentGenerator)(Context &,
3535                                                                     const ResourceDefinition::Node::SharedPtr &,
3536                                                                     tcu::TestCaseGroup *const))
3537 {
3538     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
3539     const ResourceDefinition::Node::SharedPtr uniform(
3540         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_UNIFORM));
3541 
3542     // .default_block
3543     if (blockFlags & BLOCKFLAG_DEFAULT)
3544     {
3545         tcu::TestCaseGroup *const blockGroup =
3546             new tcu::TestCaseGroup(context.getTestContext(), "default_block", "Default block");
3547         targetGroup->addChild(blockGroup);
3548 
3549         blockContentGenerator(context, uniform, blockGroup);
3550     }
3551 
3552     // .named_block
3553     if (blockFlags & BLOCKFLAG_NAMED)
3554     {
3555         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(uniform, true));
3556 
3557         tcu::TestCaseGroup *const blockGroup =
3558             new tcu::TestCaseGroup(context.getTestContext(), "named_block", "Named uniform block");
3559         targetGroup->addChild(blockGroup);
3560 
3561         blockContentGenerator(context, block, blockGroup);
3562     }
3563 
3564     // .unnamed_block
3565     if (blockFlags & BLOCKFLAG_UNNAMED)
3566     {
3567         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(uniform, false));
3568 
3569         tcu::TestCaseGroup *const blockGroup =
3570             new tcu::TestCaseGroup(context.getTestContext(), "unnamed_block", "Unnamed uniform block");
3571         targetGroup->addChild(blockGroup);
3572 
3573         blockContentGenerator(context, block, blockGroup);
3574     }
3575 
3576     // .block_array
3577     if (blockFlags & BLOCKFLAG_ARRAY)
3578     {
3579         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(uniform));
3580         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(arrayElement, true));
3581 
3582         tcu::TestCaseGroup *const blockGroup =
3583             new tcu::TestCaseGroup(context.getTestContext(), "block_array", "Uniform block array");
3584         targetGroup->addChild(blockGroup);
3585 
3586         blockContentGenerator(context, block, blockGroup);
3587     }
3588 }
3589 
generateBufferBackedResourceListBlockContentCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,ProgramInterface interface,int depth)3590 static void generateBufferBackedResourceListBlockContentCases(
3591     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup,
3592     ProgramInterface interface, int depth)
3593 {
3594     // variable
3595     {
3596         const ResourceDefinition::Node::SharedPtr variable(
3597             new ResourceDefinition::Variable(parentStructure, glu::TYPE_FLOAT_VEC4));
3598         targetGroup->addChild(new ResourceListTestCase(context, variable, interface));
3599     }
3600 
3601     // struct
3602     if (depth > 0)
3603     {
3604         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
3605         generateBufferBackedResourceListBlockContentCases(context, structMember, targetGroup, interface, depth - 1);
3606     }
3607 
3608     // array
3609     if (depth > 0)
3610     {
3611         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
3612         generateBufferBackedResourceListBlockContentCases(context, arrayElement, targetGroup, interface, depth - 1);
3613     }
3614 }
3615 
generateBufferBackedVariableAggregateTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,ProgramInterface interface,ProgramResourcePropFlags targetProp,glu::DataType dataType,const std::string & nameSuffix,int depth)3616 static void generateBufferBackedVariableAggregateTypeCases(Context &context,
3617                                                            const ResourceDefinition::Node::SharedPtr &parentStructure,
3618                                                            tcu::TestCaseGroup *const targetGroup,
3619                                                            ProgramInterface interface,
3620                                                            ProgramResourcePropFlags targetProp, glu::DataType dataType,
3621                                                            const std::string &nameSuffix, int depth)
3622 {
3623     // variable
3624     {
3625         const ResourceDefinition::Node::SharedPtr variable(new ResourceDefinition::Variable(parentStructure, dataType));
3626         targetGroup->addChild(new ResourceTestCase(
3627             context, variable, ProgramResourceQueryTestTarget(interface, targetProp), ("var" + nameSuffix).c_str()));
3628     }
3629 
3630     // struct
3631     if (depth > 0)
3632     {
3633         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
3634         generateBufferBackedVariableAggregateTypeCases(context, structMember, targetGroup, interface, targetProp,
3635                                                        dataType, "_struct" + nameSuffix, depth - 1);
3636     }
3637 
3638     // array
3639     if (depth > 0)
3640     {
3641         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
3642         generateBufferBackedVariableAggregateTypeCases(context, arrayElement, targetGroup, interface, targetProp,
3643                                                        dataType, "_array" + nameSuffix, depth - 1);
3644     }
3645 }
3646 
generateUniformResourceListBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3647 static void generateUniformResourceListBlockContents(Context &context,
3648                                                      const ResourceDefinition::Node::SharedPtr &parentStructure,
3649                                                      tcu::TestCaseGroup *const targetGroup)
3650 {
3651     generateBufferBackedResourceListBlockContentCases(context, parentStructure, targetGroup, PROGRAMINTERFACE_UNIFORM,
3652                                                       4);
3653 }
3654 
generateUniformBlockArraySizeContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3655 static void generateUniformBlockArraySizeContents(Context &context,
3656                                                   const ResourceDefinition::Node::SharedPtr &parentStructure,
3657                                                   tcu::TestCaseGroup *const targetGroup)
3658 {
3659     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_ARRAY_SIZE);
3660     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3661     const bool namedNonArrayBlock =
3662         isInterfaceBlock && static_cast<const ResourceDefinition::InterfaceBlock *>(parentStructure.get())->m_named &&
3663         parentStructure->getEnclosingNode()->getType() != ResourceDefinition::Node::TYPE_ARRAY_ELEMENT;
3664 
3665     if (!isInterfaceBlock || namedNonArrayBlock)
3666     {
3667         // .types
3668         {
3669             tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "types", "Types");
3670             targetGroup->addChild(blockGroup);
3671 
3672             generateVariableCases(context, parentStructure, blockGroup, queryTarget, 2, false);
3673             generateOpaqueTypeCases(context, parentStructure, blockGroup, queryTarget, 2, false);
3674         }
3675 
3676         // aggregates
3677         {
3678             tcu::TestCaseGroup *const blockGroup =
3679                 new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "Aggregate types");
3680             targetGroup->addChild(blockGroup);
3681 
3682             generateBufferBackedVariableAggregateTypeCases(context, parentStructure, blockGroup, queryTarget.interface,
3683                                                            PROGRAMRESOURCEPROP_ARRAY_SIZE, glu::TYPE_FLOAT, "", 3);
3684         }
3685     }
3686     else
3687     {
3688         // aggregates
3689         generateBufferBackedVariableAggregateTypeCases(context, parentStructure, targetGroup, queryTarget.interface,
3690                                                        PROGRAMRESOURCEPROP_ARRAY_SIZE, glu::TYPE_FLOAT, "", 2);
3691     }
3692 }
3693 
generateBufferBackedArrayStrideTypeAggregateSubCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const std::string & namePrefix,ProgramInterface interface,glu::DataType type,int expandLevel)3694 static void generateBufferBackedArrayStrideTypeAggregateSubCases(
3695     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup,
3696     const std::string &namePrefix, ProgramInterface interface, glu::DataType type, int expandLevel)
3697 {
3698     // case
3699     {
3700         const ResourceDefinition::Node::SharedPtr variable(new ResourceDefinition::Variable(parentStructure, type));
3701         targetGroup->addChild(new ResourceTestCase(
3702             context, variable, ProgramResourceQueryTestTarget(interface, PROGRAMRESOURCEPROP_ARRAY_STRIDE),
3703             namePrefix.c_str()));
3704     }
3705 
3706     if (expandLevel > 0)
3707     {
3708         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
3709         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
3710 
3711         // _struct
3712         generateBufferBackedArrayStrideTypeAggregateSubCases(context, structMember, targetGroup, namePrefix + "_struct",
3713                                                              interface, type, expandLevel - 1);
3714 
3715         // _array
3716         generateBufferBackedArrayStrideTypeAggregateSubCases(context, arrayElement, targetGroup, namePrefix + "_array",
3717                                                              interface, type, expandLevel - 1);
3718     }
3719 }
3720 
generateBufferBackedArrayStrideTypeAggregateCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,ProgramInterface interface,glu::DataType type,int expandLevel,bool includeBaseCase)3721 static void generateBufferBackedArrayStrideTypeAggregateCases(
3722     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup,
3723     ProgramInterface interface, glu::DataType type, int expandLevel, bool includeBaseCase)
3724 {
3725     const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
3726     const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
3727     const std::string namePrefix = glu::getDataTypeName(type);
3728 
3729     if (expandLevel == 0 || includeBaseCase)
3730     {
3731         const ResourceDefinition::Node::SharedPtr variable(new ResourceDefinition::Variable(parentStructure, type));
3732         targetGroup->addChild(new ResourceTestCase(
3733             context, variable, ProgramResourceQueryTestTarget(interface, PROGRAMRESOURCEPROP_ARRAY_STRIDE),
3734             namePrefix.c_str()));
3735     }
3736     if (expandLevel >= 1)
3737     {
3738         // _struct
3739         if (!glu::isDataTypeAtomicCounter(type))
3740             generateBufferBackedArrayStrideTypeAggregateSubCases(
3741                 context, structMember, targetGroup, namePrefix + "_struct", interface, type, expandLevel - 1);
3742 
3743         // _array
3744         generateBufferBackedArrayStrideTypeAggregateSubCases(context, arrayElement, targetGroup, namePrefix + "_array",
3745                                                              interface, type, expandLevel - 1);
3746     }
3747 }
3748 
generateUniformBlockArrayStrideContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3749 static void generateUniformBlockArrayStrideContents(Context &context,
3750                                                     const ResourceDefinition::Node::SharedPtr &parentStructure,
3751                                                     tcu::TestCaseGroup *const targetGroup)
3752 {
3753     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_ARRAY_STRIDE);
3754     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3755     const bool namedNonArrayBlock =
3756         isInterfaceBlock && static_cast<const ResourceDefinition::InterfaceBlock *>(parentStructure.get())->m_named &&
3757         parentStructure->getEnclosingNode()->getType() != ResourceDefinition::Node::TYPE_ARRAY_ELEMENT;
3758 
3759     if (!isInterfaceBlock || namedNonArrayBlock)
3760     {
3761         // .types
3762         {
3763             tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "types", "Types");
3764             targetGroup->addChild(blockGroup);
3765 
3766             generateVariableCases(context, parentStructure, blockGroup, queryTarget, 2, false);
3767             generateOpaqueTypeCases(context, parentStructure, blockGroup, queryTarget, 2, false);
3768         }
3769 
3770         // .aggregates
3771         {
3772             tcu::TestCaseGroup *const blockGroup =
3773                 new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "Aggregate types");
3774             targetGroup->addChild(blockGroup);
3775 
3776             // .sampler_2d_*
3777             if (!isInterfaceBlock)
3778                 generateBufferBackedArrayStrideTypeAggregateCases(
3779                     context, parentStructure, blockGroup, queryTarget.interface, glu::TYPE_SAMPLER_2D, 1, false);
3780 
3781             // .atomic_counter_*
3782             if (!isInterfaceBlock)
3783             {
3784                 const ResourceDefinition::Node::SharedPtr layout(
3785                     new ResourceDefinition::LayoutQualifier(parentStructure, glu::Layout(-1, 0)));
3786                 generateBufferBackedArrayStrideTypeAggregateCases(context, layout, blockGroup, queryTarget.interface,
3787                                                                   glu::TYPE_UINT_ATOMIC_COUNTER, 1, false);
3788             }
3789 
3790             // .float_*
3791             generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, blockGroup,
3792                                                               queryTarget.interface, glu::TYPE_FLOAT, 2, false);
3793 
3794             // .bool_*
3795             generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, blockGroup,
3796                                                               queryTarget.interface, glu::TYPE_BOOL, 1, false);
3797 
3798             // .bvec3_*
3799             generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, blockGroup,
3800                                                               queryTarget.interface, glu::TYPE_BOOL_VEC3, 2, false);
3801 
3802             // .vec3_*
3803             generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, blockGroup,
3804                                                               queryTarget.interface, glu::TYPE_FLOAT_VEC3, 2, false);
3805 
3806             // .ivec2_*
3807             generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, blockGroup,
3808                                                               queryTarget.interface, glu::TYPE_INT_VEC3, 2, false);
3809         }
3810     }
3811     else
3812     {
3813         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
3814         generateVariableArrayCases(context, parentStructure, targetGroup, queryTarget, 1);
3815         generateCompoundVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
3816     }
3817 }
3818 
generateUniformBlockLocationContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3819 static void generateUniformBlockLocationContents(Context &context,
3820                                                  const ResourceDefinition::Node::SharedPtr &parentStructure,
3821                                                  tcu::TestCaseGroup *const targetGroup)
3822 {
3823     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_LOCATION);
3824     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3825 
3826     if (!isInterfaceBlock)
3827     {
3828         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 3);
3829         generateOpaqueTypeCases(context, parentStructure, targetGroup, queryTarget, 3);
3830         generateVariableArrayCases(context, parentStructure, targetGroup, queryTarget, 2);
3831         generateCompoundVariableCases(context, parentStructure, targetGroup, queryTarget, 2);
3832     }
3833     else
3834         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 1, false);
3835 }
3836 
generateUniformBlockBlockIndexContents(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion)3837 static void generateUniformBlockBlockIndexContents(Context &context, tcu::TestCaseGroup *const targetGroup,
3838                                                    glu::GLSLVersion glslVersion)
3839 {
3840     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
3841     const ResourceDefinition::Node::SharedPtr shader(
3842         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
3843     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
3844     const ResourceDefinition::Node::SharedPtr uniform(
3845         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_UNIFORM));
3846     const ResourceDefinition::Node::SharedPtr binding(
3847         new ResourceDefinition::LayoutQualifier(uniform, glu::Layout(-1, 0)));
3848 
3849     // .default_block
3850     {
3851         const ResourceDefinition::Node::SharedPtr variable(
3852             new ResourceDefinition::Variable(uniform, glu::TYPE_FLOAT_VEC4));
3853 
3854         targetGroup->addChild(new ResourceTestCase(
3855             context, variable,
3856             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_BLOCK_INDEX),
3857             "default_block"));
3858     }
3859 
3860     // .named_block
3861     {
3862         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(binding, true));
3863         const ResourceDefinition::Node::SharedPtr variable(
3864             new ResourceDefinition::Variable(buffer, glu::TYPE_FLOAT_VEC4));
3865 
3866         targetGroup->addChild(new ResourceTestCase(
3867             context, variable,
3868             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_BLOCK_INDEX), "named_block"));
3869     }
3870 
3871     // .unnamed_block
3872     {
3873         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(binding, false));
3874         const ResourceDefinition::Node::SharedPtr variable(
3875             new ResourceDefinition::Variable(buffer, glu::TYPE_FLOAT_VEC4));
3876 
3877         targetGroup->addChild(new ResourceTestCase(
3878             context, variable,
3879             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_BLOCK_INDEX),
3880             "unnamed_block"));
3881     }
3882 
3883     // .block_array
3884     {
3885         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(binding));
3886         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(arrayElement, true));
3887         const ResourceDefinition::Node::SharedPtr variable(
3888             new ResourceDefinition::Variable(buffer, glu::TYPE_FLOAT_VEC4));
3889 
3890         targetGroup->addChild(new ResourceTestCase(
3891             context, variable,
3892             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_BLOCK_INDEX), "block_array"));
3893     }
3894 }
3895 
generateUniformBlockAtomicCounterBufferIndexContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3896 static void generateUniformBlockAtomicCounterBufferIndexContents(
3897     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup)
3898 {
3899     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM,
3900                                                      PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX);
3901     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3902 
3903     if (!isInterfaceBlock)
3904     {
3905         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 3);
3906         generateOpaqueTypeCases(context, parentStructure, targetGroup, queryTarget, 3);
3907 
3908         // .array
3909         {
3910             const ResourceDefinition::Node::SharedPtr arrayElement(
3911                 new ResourceDefinition::ArrayElement(parentStructure));
3912             const ResourceDefinition::Node::SharedPtr arrayArrayElement(
3913                 new ResourceDefinition::ArrayElement(arrayElement));
3914             const ResourceDefinition::Node::SharedPtr variable(
3915                 new ResourceDefinition::Variable(arrayElement, glu::TYPE_UINT_ATOMIC_COUNTER));
3916             const ResourceDefinition::Node::SharedPtr elementvariable(
3917                 new ResourceDefinition::Variable(arrayArrayElement, glu::TYPE_UINT_ATOMIC_COUNTER));
3918             tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "array", "Arrays");
3919 
3920             targetGroup->addChild(blockGroup);
3921 
3922             blockGroup->addChild(new ResourceTestCase(context, variable, queryTarget, "var_array"));
3923             blockGroup->addChild(new ResourceTestCase(context, elementvariable, queryTarget, "var_array_array"));
3924         }
3925     }
3926     else
3927         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 1, false);
3928 }
3929 
generateUniformBlockNameLengthContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3930 static void generateUniformBlockNameLengthContents(Context &context,
3931                                                    const ResourceDefinition::Node::SharedPtr &parentStructure,
3932                                                    tcu::TestCaseGroup *const targetGroup)
3933 {
3934     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3935     const bool namedNonArrayBlock =
3936         isInterfaceBlock && static_cast<const ResourceDefinition::InterfaceBlock *>(parentStructure.get())->m_named &&
3937         parentStructure->getEnclosingNode()->getType() != ResourceDefinition::Node::TYPE_ARRAY_ELEMENT;
3938 
3939     if (!isInterfaceBlock || namedNonArrayBlock)
3940         generateBufferBackedVariableAggregateTypeCases(context, parentStructure, targetGroup, PROGRAMINTERFACE_UNIFORM,
3941                                                        PROGRAMRESOURCEPROP_NAME_LENGTH, glu::TYPE_FLOAT, "", 2);
3942     else
3943         generateBufferBackedVariableAggregateTypeCases(context, parentStructure, targetGroup, PROGRAMINTERFACE_UNIFORM,
3944                                                        PROGRAMRESOURCEPROP_NAME_LENGTH, glu::TYPE_FLOAT, "", 1);
3945 }
3946 
generateUniformBlockTypeContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3947 static void generateUniformBlockTypeContents(Context &context,
3948                                              const ResourceDefinition::Node::SharedPtr &parentStructure,
3949                                              tcu::TestCaseGroup *const targetGroup)
3950 {
3951     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_TYPE);
3952     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3953     const bool namedNonArrayBlock =
3954         isInterfaceBlock && static_cast<const ResourceDefinition::InterfaceBlock *>(parentStructure.get())->m_named &&
3955         parentStructure->getEnclosingNode()->getType() != ResourceDefinition::Node::TYPE_ARRAY_ELEMENT;
3956 
3957     if (!isInterfaceBlock || namedNonArrayBlock)
3958     {
3959         // .types
3960         {
3961             tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "types", "Types");
3962             targetGroup->addChild(blockGroup);
3963 
3964             generateVariableCases(context, parentStructure, blockGroup, queryTarget, 3, false);
3965             generateOpaqueTypeCases(context, parentStructure, blockGroup, queryTarget, 3, false);
3966         }
3967 
3968         generateVariableArrayCases(context, parentStructure, targetGroup, queryTarget, 1);
3969         generateCompoundVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
3970     }
3971     else
3972     {
3973         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
3974         generateVariableArrayCases(context, parentStructure, targetGroup, queryTarget, 1);
3975         generateCompoundVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
3976     }
3977 }
3978 
generateUniformBlockOffsetContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)3979 static void generateUniformBlockOffsetContents(Context &context,
3980                                                const ResourceDefinition::Node::SharedPtr &parentStructure,
3981                                                tcu::TestCaseGroup *const targetGroup)
3982 {
3983     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_OFFSET);
3984     const bool isInterfaceBlock = (parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
3985     const bool namedNonArrayBlock =
3986         isInterfaceBlock && static_cast<const ResourceDefinition::InterfaceBlock *>(parentStructure.get())->m_named &&
3987         parentStructure->getEnclosingNode()->getType() != ResourceDefinition::Node::TYPE_ARRAY_ELEMENT;
3988 
3989     if (!isInterfaceBlock)
3990     {
3991         // .types
3992         {
3993             tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "types", "Types");
3994             targetGroup->addChild(blockGroup);
3995 
3996             generateVariableCases(context, parentStructure, blockGroup, queryTarget, 3, false);
3997             generateOpaqueTypeCases(context, parentStructure, blockGroup, queryTarget, 3, false);
3998         }
3999 
4000         // .aggregates
4001         {
4002             tcu::TestCaseGroup *const blockGroup =
4003                 new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "Aggregate types");
4004             targetGroup->addChild(blockGroup);
4005 
4006             // .atomic_uint_struct
4007             // .atomic_uint_array
4008             {
4009                 const ResourceDefinition::Node::SharedPtr offset(
4010                     new ResourceDefinition::LayoutQualifier(parentStructure, glu::Layout(-1, -1, 4)));
4011                 const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(offset));
4012                 const ResourceDefinition::Node::SharedPtr elementVariable(
4013                     new ResourceDefinition::Variable(arrayElement, glu::TYPE_UINT_ATOMIC_COUNTER));
4014 
4015                 blockGroup->addChild(new ResourceTestCase(context, elementVariable, queryTarget, "atomic_uint_array"));
4016             }
4017 
4018             // .float_array
4019             // .float_struct
4020             {
4021                 const ResourceDefinition::Node::SharedPtr structMember(
4022                     new ResourceDefinition::StructMember(parentStructure));
4023                 const ResourceDefinition::Node::SharedPtr arrayElement(
4024                     new ResourceDefinition::ArrayElement(parentStructure));
4025                 const ResourceDefinition::Node::SharedPtr memberVariable(
4026                     new ResourceDefinition::Variable(structMember, glu::TYPE_FLOAT));
4027                 const ResourceDefinition::Node::SharedPtr elementVariable(
4028                     new ResourceDefinition::Variable(arrayElement, glu::TYPE_FLOAT));
4029 
4030                 blockGroup->addChild(new ResourceTestCase(context, memberVariable, queryTarget, "float_struct"));
4031                 blockGroup->addChild(new ResourceTestCase(context, elementVariable, queryTarget, "float_array"));
4032             }
4033         }
4034     }
4035     else if (namedNonArrayBlock)
4036     {
4037         // .types
4038         {
4039             tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "types", "Types");
4040             targetGroup->addChild(blockGroup);
4041 
4042             generateVariableCases(context, parentStructure, blockGroup, queryTarget, 3, false);
4043             generateOpaqueTypeCases(context, parentStructure, blockGroup, queryTarget, 3, false);
4044         }
4045 
4046         // .aggregates
4047         {
4048             tcu::TestCaseGroup *const blockGroup =
4049                 new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "Aggregate types");
4050             targetGroup->addChild(blockGroup);
4051 
4052             // .float_array
4053             // .float_struct
4054             {
4055                 const ResourceDefinition::Node::SharedPtr structMember(
4056                     new ResourceDefinition::StructMember(parentStructure));
4057                 const ResourceDefinition::Node::SharedPtr arrayElement(
4058                     new ResourceDefinition::StructMember(parentStructure));
4059                 const ResourceDefinition::Node::SharedPtr memberVariable(
4060                     new ResourceDefinition::Variable(structMember, glu::TYPE_FLOAT));
4061                 const ResourceDefinition::Node::SharedPtr elementVariable(
4062                     new ResourceDefinition::Variable(arrayElement, glu::TYPE_FLOAT));
4063 
4064                 blockGroup->addChild(new ResourceTestCase(context, memberVariable, queryTarget, "float_struct"));
4065                 blockGroup->addChild(new ResourceTestCase(context, elementVariable, queryTarget, "float_array"));
4066             }
4067         }
4068     }
4069     else
4070     {
4071         generateVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
4072         generateVariableArrayCases(context, parentStructure, targetGroup, queryTarget, 1);
4073         generateCompoundVariableCases(context, parentStructure, targetGroup, queryTarget, 1);
4074     }
4075 }
4076 
generateMatrixVariableCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,bool createTestGroup=true,int expandLevel=2)4077 static void generateMatrixVariableCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
4078                                         tcu::TestCaseGroup *const targetGroup,
4079                                         const ProgramResourceQueryTestTarget &queryTarget, bool createTestGroup = true,
4080                                         int expandLevel = 2)
4081 {
4082     static const struct
4083     {
4084         int priority;
4085         glu::DataType type;
4086     } variableTypes[] = {
4087         {0, glu::TYPE_FLOAT_MAT2},   {1, glu::TYPE_FLOAT_MAT2X3}, {2, glu::TYPE_FLOAT_MAT2X4},
4088         {2, glu::TYPE_FLOAT_MAT3X2}, {1, glu::TYPE_FLOAT_MAT3},   {0, glu::TYPE_FLOAT_MAT3X4},
4089         {2, glu::TYPE_FLOAT_MAT4X2}, {1, glu::TYPE_FLOAT_MAT4X3}, {0, glu::TYPE_FLOAT_MAT4},
4090     };
4091 
4092     tcu::TestCaseGroup *group;
4093 
4094     if (createTestGroup)
4095     {
4096         tcu::TestCaseGroup *const blockGroup =
4097             new tcu::TestCaseGroup(context.getTestContext(), "matrix", "Basic matrix type");
4098         targetGroup->addChild(blockGroup);
4099         group = blockGroup;
4100     }
4101     else
4102         group = targetGroup;
4103 
4104     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
4105     {
4106         if (variableTypes[ndx].priority < expandLevel)
4107         {
4108             const ResourceDefinition::Node::SharedPtr variable(
4109                 new ResourceDefinition::Variable(parentStructure, variableTypes[ndx].type));
4110             group->addChild(new ResourceTestCase(context, variable, queryTarget));
4111         }
4112     }
4113 }
4114 
4115 static void generateMatrixStructCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
4116                                       tcu::TestCaseGroup *const targetGroup,
4117                                       const ProgramResourceQueryTestTarget &queryTarget, int expandLevel);
4118 
generateMatrixArrayCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,int expandLevel)4119 static void generateMatrixArrayCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
4120                                      tcu::TestCaseGroup *const targetGroup,
4121                                      const ProgramResourceQueryTestTarget &queryTarget, int expandLevel)
4122 {
4123     if (expandLevel > 0)
4124     {
4125         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
4126         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "array", "Arrays");
4127 
4128         targetGroup->addChild(blockGroup);
4129 
4130         // Arrays of basic variables
4131         generateMatrixVariableCases(context, arrayElement, blockGroup, queryTarget, expandLevel != 1, expandLevel);
4132 
4133         // Arrays of arrays
4134         generateMatrixArrayCases(context, arrayElement, blockGroup, queryTarget, expandLevel - 1);
4135 
4136         // Arrays of structs
4137         generateMatrixStructCases(context, arrayElement, blockGroup, queryTarget, expandLevel - 1);
4138     }
4139 }
4140 
generateMatrixStructCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,int expandLevel)4141 static void generateMatrixStructCases(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
4142                                       tcu::TestCaseGroup *const targetGroup,
4143                                       const ProgramResourceQueryTestTarget &queryTarget, int expandLevel)
4144 {
4145     if (expandLevel > 0)
4146     {
4147         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
4148         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "struct", "Structs");
4149 
4150         targetGroup->addChild(blockGroup);
4151 
4152         // Struct containing basic variable
4153         generateMatrixVariableCases(context, structMember, blockGroup, queryTarget, expandLevel != 1, expandLevel);
4154 
4155         // Struct containing arrays
4156         generateMatrixArrayCases(context, structMember, blockGroup, queryTarget, expandLevel - 1);
4157 
4158         // Struct containing struct
4159         generateMatrixStructCases(context, structMember, blockGroup, queryTarget, expandLevel - 1);
4160     }
4161 }
4162 
generateUniformMatrixOrderCaseBlockContentCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,bool extendedBasicTypeCases,bool opaqueCases)4163 static void generateUniformMatrixOrderCaseBlockContentCases(Context &context,
4164                                                             const ResourceDefinition::Node::SharedPtr &parentStructure,
4165                                                             tcu::TestCaseGroup *const targetGroup,
4166                                                             bool extendedBasicTypeCases, bool opaqueCases)
4167 {
4168     static const struct
4169     {
4170         const char *name;
4171         glu::MatrixOrder order;
4172     } qualifiers[] = {
4173         {"no_qualifier", glu::MATRIXORDER_LAST},
4174         {"row_major", glu::MATRIXORDER_ROW_MAJOR},
4175         {"column_major", glu::MATRIXORDER_COLUMN_MAJOR},
4176     };
4177 
4178     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR);
4179 
4180     for (int qualifierNdx = 0; qualifierNdx < DE_LENGTH_OF_ARRAY(qualifiers); ++qualifierNdx)
4181     {
4182         // Add layout qualifiers only for block members
4183         if (qualifiers[qualifierNdx].order == glu::MATRIXORDER_LAST ||
4184             parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK)
4185         {
4186             ResourceDefinition::Node::SharedPtr subStructure = parentStructure;
4187             tcu::TestCaseGroup *const qualifierGroup =
4188                 new tcu::TestCaseGroup(context.getTestContext(), qualifiers[qualifierNdx].name, "");
4189 
4190             targetGroup->addChild(qualifierGroup);
4191 
4192             if (qualifiers[qualifierNdx].order != glu::MATRIXORDER_LAST)
4193             {
4194                 glu::Layout layout;
4195                 layout.matrixOrder = qualifiers[qualifierNdx].order;
4196                 subStructure =
4197                     ResourceDefinition::Node::SharedPtr(new ResourceDefinition::LayoutQualifier(subStructure, layout));
4198             }
4199 
4200             if (extendedBasicTypeCases && qualifiers[qualifierNdx].order == glu::MATRIXORDER_LAST)
4201             {
4202                 // .types
4203                 {
4204                     tcu::TestCaseGroup *const blockGroup =
4205                         new tcu::TestCaseGroup(context.getTestContext(), "types", "");
4206                     qualifierGroup->addChild(blockGroup);
4207 
4208                     generateVariableCases(context, subStructure, blockGroup, queryTarget, 1, false);
4209                     generateMatrixVariableCases(context, subStructure, blockGroup, queryTarget, false);
4210                     if (opaqueCases)
4211                         generateOpaqueTypeCases(context, subStructure, blockGroup, queryTarget, 2, false);
4212                 }
4213 
4214                 // .aggregates
4215                 {
4216                     tcu::TestCaseGroup *const blockGroup =
4217                         new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "");
4218                     qualifierGroup->addChild(blockGroup);
4219 
4220                     generateBufferBackedVariableAggregateTypeCases(
4221                         context, subStructure, blockGroup, queryTarget.interface, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR,
4222                         glu::TYPE_FLOAT_MAT3X2, "", 1);
4223                 }
4224             }
4225             else
4226             {
4227                 generateBufferBackedVariableAggregateTypeCases(
4228                     context, subStructure, qualifierGroup, queryTarget.interface, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR,
4229                     glu::TYPE_FLOAT_MAT3X2, "", 1);
4230             }
4231         }
4232     }
4233 }
4234 
generateUniformMatrixStrideCaseBlockContentCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,bool extendedBasicTypeCases,bool opaqueCases)4235 static void generateUniformMatrixStrideCaseBlockContentCases(Context &context,
4236                                                              const ResourceDefinition::Node::SharedPtr &parentStructure,
4237                                                              tcu::TestCaseGroup *const targetGroup,
4238                                                              bool extendedBasicTypeCases, bool opaqueCases)
4239 {
4240     static const struct
4241     {
4242         const char *name;
4243         glu::MatrixOrder order;
4244     } qualifiers[] = {
4245         {"no_qualifier", glu::MATRIXORDER_LAST},
4246         {"row_major", glu::MATRIXORDER_ROW_MAJOR},
4247         {"column_major", glu::MATRIXORDER_COLUMN_MAJOR},
4248     };
4249 
4250     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_MATRIX_STRIDE);
4251 
4252     for (int qualifierNdx = 0; qualifierNdx < DE_LENGTH_OF_ARRAY(qualifiers); ++qualifierNdx)
4253     {
4254         // Add layout qualifiers only for block members
4255         if (qualifiers[qualifierNdx].order == glu::MATRIXORDER_LAST ||
4256             parentStructure->getType() == ResourceDefinition::Node::TYPE_INTERFACE_BLOCK)
4257         {
4258             ResourceDefinition::Node::SharedPtr subStructure = parentStructure;
4259             tcu::TestCaseGroup *const qualifierGroup =
4260                 new tcu::TestCaseGroup(context.getTestContext(), qualifiers[qualifierNdx].name, "");
4261 
4262             targetGroup->addChild(qualifierGroup);
4263 
4264             if (qualifiers[qualifierNdx].order != glu::MATRIXORDER_LAST)
4265             {
4266                 glu::Layout layout;
4267                 layout.matrixOrder = qualifiers[qualifierNdx].order;
4268                 subStructure =
4269                     ResourceDefinition::Node::SharedPtr(new ResourceDefinition::LayoutQualifier(subStructure, layout));
4270             }
4271 
4272             if (extendedBasicTypeCases)
4273             {
4274                 // .types
4275                 // .matrix
4276                 if (qualifiers[qualifierNdx].order == glu::MATRIXORDER_LAST)
4277                 {
4278                     tcu::TestCaseGroup *const blockGroup =
4279                         new tcu::TestCaseGroup(context.getTestContext(), "types", "");
4280                     qualifierGroup->addChild(blockGroup);
4281 
4282                     generateVariableCases(context, subStructure, blockGroup, queryTarget, 1, false);
4283                     generateMatrixVariableCases(context, subStructure, blockGroup, queryTarget, false);
4284                     if (opaqueCases)
4285                         generateOpaqueTypeCases(context, subStructure, blockGroup, queryTarget, 2, false);
4286                 }
4287                 else
4288                     generateMatrixVariableCases(context, subStructure, qualifierGroup, queryTarget);
4289 
4290                 // .aggregates
4291                 {
4292                     tcu::TestCaseGroup *const blockGroup =
4293                         new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "");
4294                     qualifierGroup->addChild(blockGroup);
4295 
4296                     generateBufferBackedVariableAggregateTypeCases(
4297                         context, subStructure, blockGroup, queryTarget.interface, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR,
4298                         glu::TYPE_FLOAT_MAT3X2, "", 1);
4299                 }
4300             }
4301             else
4302                 generateBufferBackedVariableAggregateTypeCases(
4303                     context, subStructure, qualifierGroup, queryTarget.interface, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR,
4304                     glu::TYPE_FLOAT_MAT3X2, "", 1);
4305         }
4306     }
4307 }
4308 
generateUniformMatrixCaseBlocks(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup * const,bool,bool))4309 static void generateUniformMatrixCaseBlocks(Context &context,
4310                                             const ResourceDefinition::Node::SharedPtr &parentStructure,
4311                                             tcu::TestCaseGroup *const targetGroup,
4312                                             void (*blockContentGenerator)(Context &,
4313                                                                           const ResourceDefinition::Node::SharedPtr &,
4314                                                                           tcu::TestCaseGroup *const, bool, bool))
4315 {
4316     static const struct
4317     {
4318         const char *name;
4319         const char *description;
4320         bool block;
4321         bool namedBlock;
4322         bool extendedBasicTypeCases;
4323         glu::MatrixOrder order;
4324     } children[] = {
4325         {"default_block", "Default block", false, true, true, glu::MATRIXORDER_LAST},
4326         {"named_block", "Named uniform block", true, true, true, glu::MATRIXORDER_LAST},
4327         {"named_block_row_major", "Named uniform block", true, true, false, glu::MATRIXORDER_ROW_MAJOR},
4328         {"named_block_col_major", "Named uniform block", true, true, false, glu::MATRIXORDER_COLUMN_MAJOR},
4329         {"unnamed_block", "Unnamed uniform block", true, false, false, glu::MATRIXORDER_LAST},
4330         {"unnamed_block_row_major", "Unnamed uniform block", true, false, false, glu::MATRIXORDER_ROW_MAJOR},
4331         {"unnamed_block_col_major", "Unnamed uniform block", true, false, false, glu::MATRIXORDER_COLUMN_MAJOR},
4332     };
4333 
4334     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
4335     const ResourceDefinition::Node::SharedPtr uniform(
4336         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_UNIFORM));
4337 
4338     for (int childNdx = 0; childNdx < (int)DE_LENGTH_OF_ARRAY(children); ++childNdx)
4339     {
4340         ResourceDefinition::Node::SharedPtr subStructure = uniform;
4341         tcu::TestCaseGroup *const blockGroup =
4342             new tcu::TestCaseGroup(context.getTestContext(), children[childNdx].name, children[childNdx].description);
4343         const bool addOpaqueCases = children[childNdx].extendedBasicTypeCases && !children[childNdx].block;
4344 
4345         targetGroup->addChild(blockGroup);
4346 
4347         if (children[childNdx].order != glu::MATRIXORDER_LAST)
4348         {
4349             glu::Layout layout;
4350             layout.matrixOrder = children[childNdx].order;
4351             subStructure =
4352                 ResourceDefinition::Node::SharedPtr(new ResourceDefinition::LayoutQualifier(subStructure, layout));
4353         }
4354 
4355         if (children[childNdx].block)
4356             subStructure = ResourceDefinition::Node::SharedPtr(
4357                 new ResourceDefinition::InterfaceBlock(subStructure, children[childNdx].namedBlock));
4358 
4359         blockContentGenerator(context, subStructure, blockGroup, children[childNdx].extendedBasicTypeCases,
4360                               addOpaqueCases);
4361     }
4362 }
4363 
generateBufferReferencedByShaderInterfaceBlockCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,const ProgramResourceQueryTestTarget & queryTarget,bool extendedCases)4364 static void generateBufferReferencedByShaderInterfaceBlockCases(
4365     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup,
4366     const ProgramResourceQueryTestTarget &queryTarget, bool extendedCases)
4367 {
4368     const bool isDefaultBlock = (parentStructure->getType() != ResourceDefinition::Node::TYPE_INTERFACE_BLOCK);
4369 
4370     // .float
4371     // .float_array
4372     // .float_struct
4373     {
4374         const ResourceDefinition::Node::SharedPtr variable(
4375             new ResourceDefinition::Variable(parentStructure, glu::TYPE_FLOAT));
4376         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
4377         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
4378         const ResourceDefinition::Node::SharedPtr variableArray(
4379             new ResourceDefinition::Variable(arrayElement, glu::TYPE_FLOAT));
4380         const ResourceDefinition::Node::SharedPtr variableStruct(
4381             new ResourceDefinition::Variable(structMember, glu::TYPE_FLOAT));
4382 
4383         targetGroup->addChild(new ResourceTestCase(context, variable, queryTarget, "float"));
4384         targetGroup->addChild(new ResourceTestCase(context, variableArray, queryTarget, "float_array"));
4385         targetGroup->addChild(new ResourceTestCase(context, variableStruct, queryTarget, "float_struct"));
4386     }
4387 
4388     // .sampler
4389     // .sampler_array
4390     // .sampler_struct
4391     if (isDefaultBlock)
4392     {
4393         const ResourceDefinition::Node::SharedPtr layout(
4394             new ResourceDefinition::LayoutQualifier(parentStructure, glu::Layout(-1, 0)));
4395         const ResourceDefinition::Node::SharedPtr variable(
4396             new ResourceDefinition::Variable(layout, glu::TYPE_SAMPLER_2D));
4397         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(layout));
4398         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
4399         const ResourceDefinition::Node::SharedPtr variableArray(
4400             new ResourceDefinition::Variable(arrayElement, glu::TYPE_SAMPLER_2D));
4401         const ResourceDefinition::Node::SharedPtr variableStruct(
4402             new ResourceDefinition::Variable(structMember, glu::TYPE_SAMPLER_2D));
4403 
4404         targetGroup->addChild(new ResourceTestCase(context, variable, queryTarget, "sampler"));
4405         targetGroup->addChild(new ResourceTestCase(context, variableArray, queryTarget, "sampler_array"));
4406         targetGroup->addChild(new ResourceTestCase(context, variableStruct, queryTarget, "sampler_struct"));
4407     }
4408 
4409     // .atomic_uint
4410     // .atomic_uint_array
4411     if (isDefaultBlock)
4412     {
4413         const ResourceDefinition::Node::SharedPtr layout(
4414             new ResourceDefinition::LayoutQualifier(parentStructure, glu::Layout(-1, 0)));
4415         const ResourceDefinition::Node::SharedPtr variable(
4416             new ResourceDefinition::Variable(layout, glu::TYPE_UINT_ATOMIC_COUNTER));
4417         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(layout));
4418         const ResourceDefinition::Node::SharedPtr variableArray(
4419             new ResourceDefinition::Variable(arrayElement, glu::TYPE_UINT_ATOMIC_COUNTER));
4420 
4421         targetGroup->addChild(new ResourceTestCase(context, variable, queryTarget, "atomic_uint"));
4422         targetGroup->addChild(new ResourceTestCase(context, variableArray, queryTarget, "atomic_uint_array"));
4423     }
4424 
4425     if (extendedCases)
4426     {
4427         // .float_array_struct
4428         {
4429             const ResourceDefinition::Node::SharedPtr structMember(
4430                 new ResourceDefinition::StructMember(parentStructure));
4431             const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(structMember));
4432             const ResourceDefinition::Node::SharedPtr variableArrayStruct(
4433                 new ResourceDefinition::Variable(arrayElement, glu::TYPE_FLOAT));
4434 
4435             targetGroup->addChild(
4436                 new ResourceTestCase(context, variableArrayStruct, queryTarget, "float_array_struct"));
4437         }
4438 
4439         // .float_struct_array
4440         {
4441             const ResourceDefinition::Node::SharedPtr arrayElement(
4442                 new ResourceDefinition::ArrayElement(parentStructure));
4443             const ResourceDefinition::Node::SharedPtr arrayStructMember(
4444                 new ResourceDefinition::StructMember(arrayElement));
4445             const ResourceDefinition::Node::SharedPtr variableArrayStruct(
4446                 new ResourceDefinition::Variable(arrayStructMember, glu::TYPE_FLOAT));
4447 
4448             targetGroup->addChild(
4449                 new ResourceTestCase(context, variableArrayStruct, queryTarget, "float_struct_array"));
4450         }
4451 
4452         // .float_array_array
4453         {
4454             const ResourceDefinition::Node::SharedPtr arrayElement(
4455                 new ResourceDefinition::ArrayElement(parentStructure));
4456             const ResourceDefinition::Node::SharedPtr subArrayElement(
4457                 new ResourceDefinition::ArrayElement(arrayElement));
4458             const ResourceDefinition::Node::SharedPtr variableArrayStruct(
4459                 new ResourceDefinition::Variable(subArrayElement, glu::TYPE_FLOAT));
4460 
4461             targetGroup->addChild(new ResourceTestCase(context, variableArrayStruct, queryTarget, "float_array_array"));
4462         }
4463 
4464         // .float_struct_struct
4465         {
4466             const ResourceDefinition::Node::SharedPtr structMember(
4467                 new ResourceDefinition::StructMember(parentStructure));
4468             const ResourceDefinition::Node::SharedPtr subStructMember(
4469                 new ResourceDefinition::StructMember(structMember));
4470             const ResourceDefinition::Node::SharedPtr variableArrayStruct(
4471                 new ResourceDefinition::Variable(subStructMember, glu::TYPE_FLOAT));
4472 
4473             targetGroup->addChild(
4474                 new ResourceTestCase(context, variableArrayStruct, queryTarget, "float_struct_struct"));
4475         }
4476 
4477         if (queryTarget.interface == PROGRAMINTERFACE_BUFFER_VARIABLE)
4478         {
4479             const ResourceDefinition::Node::SharedPtr arrayElement(
4480                 new ResourceDefinition::ArrayElement(parentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
4481 
4482             // .float_unsized_array
4483             {
4484                 const ResourceDefinition::Node::SharedPtr variableArray(
4485                     new ResourceDefinition::Variable(arrayElement, glu::TYPE_FLOAT));
4486 
4487                 targetGroup->addChild(new ResourceTestCase(context, variableArray, queryTarget, "float_unsized_array"));
4488             }
4489 
4490             // .float_unsized_struct_array
4491             {
4492                 const ResourceDefinition::Node::SharedPtr structMember(
4493                     new ResourceDefinition::StructMember(arrayElement));
4494                 const ResourceDefinition::Node::SharedPtr variableArray(
4495                     new ResourceDefinition::Variable(structMember, glu::TYPE_FLOAT));
4496 
4497                 targetGroup->addChild(
4498                     new ResourceTestCase(context, variableArray, queryTarget, "float_unsized_struct_array"));
4499             }
4500         }
4501     }
4502 }
4503 
generateUniformReferencedByShaderSingleBlockContentCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,int expandLevel)4504 static void generateUniformReferencedByShaderSingleBlockContentCases(
4505     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup,
4506     int expandLevel)
4507 {
4508     DE_UNREF(expandLevel);
4509 
4510     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
4511     const ResourceDefinition::Node::SharedPtr uniform(
4512         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_UNIFORM));
4513     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_UNIFORM,
4514                                                      PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER);
4515     const bool singleShaderCase = parentStructure->getType() == ResourceDefinition::Node::TYPE_SHADER;
4516 
4517     // .default_block
4518     {
4519         TestCaseGroup *const blockGroup = new TestCaseGroup(context, "default_block", "");
4520         targetGroup->addChild(blockGroup);
4521 
4522         generateBufferReferencedByShaderInterfaceBlockCases(context, uniform, blockGroup, queryTarget,
4523                                                             singleShaderCase);
4524     }
4525 
4526     // .named_block
4527     {
4528         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(uniform, true));
4529         TestCaseGroup *const blockGroup = new TestCaseGroup(context, "uniform_block", "");
4530 
4531         targetGroup->addChild(blockGroup);
4532 
4533         generateBufferReferencedByShaderInterfaceBlockCases(context, block, blockGroup, queryTarget, singleShaderCase);
4534     }
4535 
4536     // .unnamed_block
4537     {
4538         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(uniform, false));
4539         TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unnamed_block", "");
4540 
4541         targetGroup->addChild(blockGroup);
4542 
4543         generateBufferReferencedByShaderInterfaceBlockCases(context, block, blockGroup, queryTarget, false);
4544     }
4545 
4546     // .block_array
4547     {
4548         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(uniform));
4549         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(arrayElement, true));
4550         TestCaseGroup *const blockGroup = new TestCaseGroup(context, "block_array", "");
4551 
4552         targetGroup->addChild(blockGroup);
4553 
4554         generateBufferReferencedByShaderInterfaceBlockCases(context, block, blockGroup, queryTarget, false);
4555     }
4556 }
4557 
generateReferencedByShaderCaseBlocks(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion,void (* generateBlockContent)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup *,int expandLevel))4558 static void generateReferencedByShaderCaseBlocks(
4559     Context &context, tcu::TestCaseGroup *const targetGroup, glu::GLSLVersion glslVersion,
4560     void (*generateBlockContent)(Context &, const ResourceDefinition::Node::SharedPtr &, tcu::TestCaseGroup *,
4561                                  int expandLevel))
4562 {
4563     static const struct
4564     {
4565         const char *name;
4566         glu::ShaderType stage;
4567         int expandLevel;
4568     } singleStageCases[] = {
4569         {"compute", glu::SHADERTYPE_COMPUTE, 3},
4570         {"separable_vertex", glu::SHADERTYPE_VERTEX, 2},
4571         {"separable_fragment", glu::SHADERTYPE_FRAGMENT, 2},
4572         {"separable_tess_ctrl", glu::SHADERTYPE_TESSELLATION_CONTROL, 2},
4573         {"separable_tess_eval", glu::SHADERTYPE_TESSELLATION_EVALUATION, 2},
4574         {"separable_geometry", glu::SHADERTYPE_GEOMETRY, 2},
4575     };
4576     static const struct
4577     {
4578         const char *name;
4579         uint32_t flags;
4580         int expandLevel;
4581         int subExpandLevel;
4582     } pipelines[] = {
4583         {
4584             "vertex_fragment",
4585             (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT),
4586             3,
4587             2,
4588         },
4589         {
4590             "vertex_tess_fragment",
4591             (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) |
4592                 (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) | (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION),
4593             2,
4594             2,
4595         },
4596         {
4597             "vertex_geo_fragment",
4598             (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) | (1 << glu::SHADERTYPE_GEOMETRY),
4599             2,
4600             2,
4601         },
4602         {
4603             "vertex_tess_geo_fragment",
4604             (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) |
4605                 (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) | (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION) |
4606                 (1 << glu::SHADERTYPE_GEOMETRY),
4607             2,
4608             1,
4609         },
4610     };
4611 
4612     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleStageCases); ++ndx)
4613     {
4614         TestCaseGroup *const blockGroup = new TestCaseGroup(context, singleStageCases[ndx].name, "");
4615         const bool programSeparable     = (singleStageCases[ndx].stage != glu::SHADERTYPE_COMPUTE);
4616         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(programSeparable));
4617         const ResourceDefinition::Node::SharedPtr stage(
4618             new ResourceDefinition::Shader(program, singleStageCases[ndx].stage, glslVersion));
4619 
4620         targetGroup->addChild(blockGroup);
4621 
4622         generateBlockContent(context, stage, blockGroup, singleStageCases[ndx].expandLevel);
4623     }
4624 
4625     for (int pipelineNdx = 0; pipelineNdx < DE_LENGTH_OF_ARRAY(pipelines); ++pipelineNdx)
4626     {
4627         // whole pipeline
4628         {
4629             TestCaseGroup *const blockGroup = new TestCaseGroup(context, pipelines[pipelineNdx].name, "");
4630             const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
4631             ResourceDefinition::ShaderSet *shaderSet = new ResourceDefinition::ShaderSet(
4632                 program, glslVersion, pipelines[pipelineNdx].flags, pipelines[pipelineNdx].flags);
4633             targetGroup->addChild(blockGroup);
4634 
4635             {
4636                 const ResourceDefinition::Node::SharedPtr shaders(shaderSet);
4637                 generateBlockContent(context, shaders, blockGroup, pipelines[pipelineNdx].expandLevel);
4638             }
4639         }
4640 
4641         // only one stage
4642         for (int selectedStageBit = 0; selectedStageBit < glu::SHADERTYPE_LAST; ++selectedStageBit)
4643         {
4644             if (pipelines[pipelineNdx].flags & (1 << selectedStageBit))
4645             {
4646                 const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
4647                 ResourceDefinition::ShaderSet *shaderSet = new ResourceDefinition::ShaderSet(
4648                     program, glslVersion, pipelines[pipelineNdx].flags, (1u << selectedStageBit));
4649                 const char *stageName           = (selectedStageBit == glu::SHADERTYPE_VERTEX)   ? ("vertex") :
4650                                                   (selectedStageBit == glu::SHADERTYPE_FRAGMENT) ? ("fragment") :
4651                                                   (selectedStageBit == glu::SHADERTYPE_GEOMETRY) ? ("geo") :
4652                                                   (selectedStageBit == glu::SHADERTYPE_TESSELLATION_CONTROL) ? ("tess_ctrl") :
4653                                                   (selectedStageBit == glu::SHADERTYPE_TESSELLATION_EVALUATION) ? ("tess_eval") :
4654                                                                                                                   (DE_NULL);
4655                 const std::string setName       = std::string() + pipelines[pipelineNdx].name + "_only_" + stageName;
4656                 TestCaseGroup *const blockGroup = new TestCaseGroup(context, setName.c_str(), "");
4657                 const ResourceDefinition::Node::SharedPtr shaders(shaderSet);
4658 
4659                 generateBlockContent(context, shaders, blockGroup, pipelines[pipelineNdx].subExpandLevel);
4660                 targetGroup->addChild(blockGroup);
4661             }
4662         }
4663     }
4664 }
4665 
generateRandomDataType(de::Random & rnd,bool excludeOpaqueTypes)4666 static glu::DataType generateRandomDataType(de::Random &rnd, bool excludeOpaqueTypes)
4667 {
4668     static const glu::DataType s_types[] = {glu::TYPE_FLOAT,
4669                                             glu::TYPE_INT,
4670                                             glu::TYPE_UINT,
4671                                             glu::TYPE_BOOL,
4672                                             glu::TYPE_FLOAT_VEC2,
4673                                             glu::TYPE_FLOAT_VEC3,
4674                                             glu::TYPE_FLOAT_VEC4,
4675                                             glu::TYPE_INT_VEC2,
4676                                             glu::TYPE_INT_VEC3,
4677                                             glu::TYPE_INT_VEC4,
4678                                             glu::TYPE_UINT_VEC2,
4679                                             glu::TYPE_UINT_VEC3,
4680                                             glu::TYPE_UINT_VEC4,
4681                                             glu::TYPE_BOOL_VEC2,
4682                                             glu::TYPE_BOOL_VEC3,
4683                                             glu::TYPE_BOOL_VEC4,
4684                                             glu::TYPE_FLOAT_MAT2,
4685                                             glu::TYPE_FLOAT_MAT2X3,
4686                                             glu::TYPE_FLOAT_MAT2X4,
4687                                             glu::TYPE_FLOAT_MAT3X2,
4688                                             glu::TYPE_FLOAT_MAT3,
4689                                             glu::TYPE_FLOAT_MAT3X4,
4690                                             glu::TYPE_FLOAT_MAT4X2,
4691                                             glu::TYPE_FLOAT_MAT4X3,
4692                                             glu::TYPE_FLOAT_MAT4,
4693 
4694                                             glu::TYPE_SAMPLER_2D,
4695                                             glu::TYPE_SAMPLER_CUBE,
4696                                             glu::TYPE_SAMPLER_2D_ARRAY,
4697                                             glu::TYPE_SAMPLER_3D,
4698                                             glu::TYPE_SAMPLER_2D_SHADOW,
4699                                             glu::TYPE_SAMPLER_CUBE_SHADOW,
4700                                             glu::TYPE_SAMPLER_2D_ARRAY_SHADOW,
4701                                             glu::TYPE_INT_SAMPLER_2D,
4702                                             glu::TYPE_INT_SAMPLER_CUBE,
4703                                             glu::TYPE_INT_SAMPLER_2D_ARRAY,
4704                                             glu::TYPE_INT_SAMPLER_3D,
4705                                             glu::TYPE_UINT_SAMPLER_2D,
4706                                             glu::TYPE_UINT_SAMPLER_CUBE,
4707                                             glu::TYPE_UINT_SAMPLER_2D_ARRAY,
4708                                             glu::TYPE_UINT_SAMPLER_3D,
4709                                             glu::TYPE_SAMPLER_2D_MULTISAMPLE,
4710                                             glu::TYPE_INT_SAMPLER_2D_MULTISAMPLE,
4711                                             glu::TYPE_UINT_SAMPLER_2D_MULTISAMPLE,
4712                                             glu::TYPE_IMAGE_2D,
4713                                             glu::TYPE_IMAGE_CUBE,
4714                                             glu::TYPE_IMAGE_2D_ARRAY,
4715                                             glu::TYPE_IMAGE_3D,
4716                                             glu::TYPE_INT_IMAGE_2D,
4717                                             glu::TYPE_INT_IMAGE_CUBE,
4718                                             glu::TYPE_INT_IMAGE_2D_ARRAY,
4719                                             glu::TYPE_INT_IMAGE_3D,
4720                                             glu::TYPE_UINT_IMAGE_2D,
4721                                             glu::TYPE_UINT_IMAGE_CUBE,
4722                                             glu::TYPE_UINT_IMAGE_2D_ARRAY,
4723                                             glu::TYPE_UINT_IMAGE_3D,
4724                                             glu::TYPE_UINT_ATOMIC_COUNTER};
4725 
4726     for (;;)
4727     {
4728         const glu::DataType type = s_types[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_types) - 1)];
4729 
4730         if (!excludeOpaqueTypes || glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type))
4731             return type;
4732     }
4733 }
4734 
generateRandomVariableDefinition(de::Random & rnd,const ResourceDefinition::Node::SharedPtr & parentStructure,glu::DataType baseType,const glu::Layout & layout,bool allowUnsized)4735 static ResourceDefinition::Node::SharedPtr generateRandomVariableDefinition(
4736     de::Random &rnd, const ResourceDefinition::Node::SharedPtr &parentStructure, glu::DataType baseType,
4737     const glu::Layout &layout, bool allowUnsized)
4738 {
4739     const int maxNesting                                 = 4;
4740     ResourceDefinition::Node::SharedPtr currentStructure = parentStructure;
4741     const bool canBeInsideAStruct                        = layout.binding == -1 && !isDataTypeLayoutQualified(baseType);
4742 
4743     for (int nestNdx = 0; nestNdx < maxNesting; ++nestNdx)
4744     {
4745         if (allowUnsized && nestNdx == 0 && rnd.getFloat() < 0.2)
4746             currentStructure = ResourceDefinition::Node::SharedPtr(new ResourceDefinition::ArrayElement(
4747                 currentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
4748         else if (rnd.getFloat() < 0.3 && canBeInsideAStruct)
4749             currentStructure =
4750                 ResourceDefinition::Node::SharedPtr(new ResourceDefinition::StructMember(currentStructure));
4751         else if (rnd.getFloat() < 0.3)
4752             currentStructure =
4753                 ResourceDefinition::Node::SharedPtr(new ResourceDefinition::ArrayElement(currentStructure));
4754         else
4755             break;
4756     }
4757 
4758     return ResourceDefinition::Node::SharedPtr(new ResourceDefinition::Variable(currentStructure, baseType));
4759 }
4760 
generateRandomCoreShaderSet(de::Random & rnd,glu::GLSLVersion glslVersion)4761 static ResourceDefinition::Node::SharedPtr generateRandomCoreShaderSet(de::Random &rnd, glu::GLSLVersion glslVersion)
4762 {
4763     if (rnd.getFloat() < 0.5f)
4764     {
4765         // compute only
4766         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
4767         return ResourceDefinition::Node::SharedPtr(
4768             new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
4769     }
4770     else if (rnd.getFloat() < 0.5f)
4771     {
4772         // vertex and fragment
4773         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
4774         ResourceDefinition::ShaderSet *shaderSet = new ResourceDefinition::ShaderSet(program, glslVersion);
4775 
4776         if (rnd.getBool())
4777         {
4778             shaderSet->setStage(glu::SHADERTYPE_VERTEX, true);
4779             shaderSet->setStage(glu::SHADERTYPE_FRAGMENT, rnd.getBool());
4780         }
4781         else
4782         {
4783             shaderSet->setStage(glu::SHADERTYPE_VERTEX, rnd.getBool());
4784             shaderSet->setStage(glu::SHADERTYPE_FRAGMENT, true);
4785         }
4786 
4787         return ResourceDefinition::Node::SharedPtr(shaderSet);
4788     }
4789     else
4790     {
4791         // separate vertex or fragment
4792         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(true));
4793         const glu::ShaderType shaderType = (rnd.getBool()) ? (glu::SHADERTYPE_VERTEX) : (glu::SHADERTYPE_FRAGMENT);
4794 
4795         return ResourceDefinition::Node::SharedPtr(new ResourceDefinition::Shader(program, shaderType, glslVersion));
4796     }
4797 }
4798 
generateRandomExtShaderSet(de::Random & rnd,glu::GLSLVersion glslVersion)4799 static ResourceDefinition::Node::SharedPtr generateRandomExtShaderSet(de::Random &rnd, glu::GLSLVersion glslVersion)
4800 {
4801     if (rnd.getFloat() < 0.5f)
4802     {
4803         // whole pipeline
4804         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
4805         ResourceDefinition::ShaderSet *shaderSet = new ResourceDefinition::ShaderSet(program, glslVersion);
4806 
4807         shaderSet->setStage(glu::SHADERTYPE_VERTEX, rnd.getBool());
4808         shaderSet->setStage(glu::SHADERTYPE_FRAGMENT, rnd.getBool());
4809 
4810         // tess shader are either both or neither present. Make cases interesting
4811         // by forcing one extended shader to always have reference
4812         if (rnd.getBool())
4813         {
4814             shaderSet->setStage(glu::SHADERTYPE_GEOMETRY, true);
4815 
4816             if (rnd.getBool())
4817             {
4818                 shaderSet->setStage(glu::SHADERTYPE_TESSELLATION_CONTROL, rnd.getBool());
4819                 shaderSet->setStage(glu::SHADERTYPE_TESSELLATION_EVALUATION, rnd.getBool());
4820             }
4821         }
4822         else
4823         {
4824             shaderSet->setStage(glu::SHADERTYPE_GEOMETRY, rnd.getBool());
4825 
4826             if (rnd.getBool())
4827             {
4828                 shaderSet->setStage(glu::SHADERTYPE_TESSELLATION_CONTROL, true);
4829                 shaderSet->setStage(glu::SHADERTYPE_TESSELLATION_EVALUATION, rnd.getBool());
4830             }
4831             else
4832             {
4833                 shaderSet->setStage(glu::SHADERTYPE_TESSELLATION_CONTROL, rnd.getBool());
4834                 shaderSet->setStage(glu::SHADERTYPE_TESSELLATION_EVALUATION, true);
4835             }
4836         }
4837 
4838         return ResourceDefinition::Node::SharedPtr(shaderSet);
4839     }
4840     else
4841     {
4842         // separate
4843         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(true));
4844         const int selector               = rnd.getInt(0, 2);
4845         const glu::ShaderType shaderType = (selector == 0) ? (glu::SHADERTYPE_GEOMETRY) :
4846                                            (selector == 1) ? (glu::SHADERTYPE_TESSELLATION_CONTROL) :
4847                                            (selector == 2) ? (glu::SHADERTYPE_TESSELLATION_EVALUATION) :
4848                                                              (glu::SHADERTYPE_LAST);
4849 
4850         return ResourceDefinition::Node::SharedPtr(new ResourceDefinition::Shader(program, shaderType, glslVersion));
4851     }
4852 }
4853 
generateRandomShaderSet(de::Random & rnd,glu::GLSLVersion glslVersion,bool onlyExtensionStages)4854 static ResourceDefinition::Node::SharedPtr generateRandomShaderSet(de::Random &rnd, glu::GLSLVersion glslVersion,
4855                                                                    bool onlyExtensionStages)
4856 {
4857     if (!onlyExtensionStages)
4858         return generateRandomCoreShaderSet(rnd, glslVersion);
4859     else
4860         return generateRandomExtShaderSet(rnd, glslVersion);
4861 }
4862 
generateRandomUniformBlockLayout(de::Random & rnd)4863 static glu::Layout generateRandomUniformBlockLayout(de::Random &rnd)
4864 {
4865     glu::Layout layout;
4866 
4867     if (rnd.getBool())
4868         layout.binding = rnd.getInt(0, 5);
4869 
4870     if (rnd.getBool())
4871         layout.matrixOrder = (rnd.getBool()) ? (glu::MATRIXORDER_COLUMN_MAJOR) : (glu::MATRIXORDER_ROW_MAJOR);
4872 
4873     return layout;
4874 }
4875 
generateRandomBufferBlockLayout(de::Random & rnd)4876 static glu::Layout generateRandomBufferBlockLayout(de::Random &rnd)
4877 {
4878     return generateRandomUniformBlockLayout(rnd);
4879 }
4880 
generateRandomVariableLayout(de::Random & rnd,glu::DataType type,bool interfaceBlockMember)4881 static glu::Layout generateRandomVariableLayout(de::Random &rnd, glu::DataType type, bool interfaceBlockMember)
4882 {
4883     glu::Layout layout;
4884 
4885     if ((glu::isDataTypeAtomicCounter(type) || glu::isDataTypeImage(type) || glu::isDataTypeSampler(type)) &&
4886         rnd.getBool())
4887         layout.binding = rnd.getInt(0, 5);
4888 
4889     if (glu::isDataTypeAtomicCounter(type) && rnd.getBool())
4890         layout.offset = rnd.getInt(0, 3) * 4;
4891 
4892     if (glu::isDataTypeMatrix(type) && interfaceBlockMember && rnd.getBool())
4893         layout.matrixOrder = (rnd.getBool()) ? (glu::MATRIXORDER_COLUMN_MAJOR) : (glu::MATRIXORDER_ROW_MAJOR);
4894 
4895     return layout;
4896 }
4897 
generateUniformRandomCase(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion,int index,bool onlyExtensionStages)4898 static void generateUniformRandomCase(Context &context, tcu::TestCaseGroup *const targetGroup,
4899                                       glu::GLSLVersion glslVersion, int index, bool onlyExtensionStages)
4900 {
4901     de::Random rnd(index * 0x12345);
4902     const ResourceDefinition::Node::SharedPtr shader = generateRandomShaderSet(rnd, glslVersion, onlyExtensionStages);
4903     const bool interfaceBlock                        = rnd.getBool();
4904     const glu::DataType type                         = generateRandomDataType(rnd, interfaceBlock);
4905     const glu::Layout layout                         = generateRandomVariableLayout(rnd, type, interfaceBlock);
4906     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
4907     const ResourceDefinition::Node::SharedPtr uniform(
4908         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_UNIFORM));
4909     ResourceDefinition::Node::SharedPtr currentStructure = uniform;
4910 
4911     if (interfaceBlock)
4912     {
4913         const bool namedBlock = rnd.getBool();
4914 
4915         currentStructure = ResourceDefinition::Node::SharedPtr(
4916             new ResourceDefinition::LayoutQualifier(currentStructure, generateRandomUniformBlockLayout(rnd)));
4917 
4918         if (namedBlock && rnd.getBool())
4919             currentStructure =
4920                 ResourceDefinition::Node::SharedPtr(new ResourceDefinition::ArrayElement(currentStructure));
4921 
4922         currentStructure =
4923             ResourceDefinition::Node::SharedPtr(new ResourceDefinition::InterfaceBlock(currentStructure, namedBlock));
4924     }
4925 
4926     currentStructure =
4927         ResourceDefinition::Node::SharedPtr(new ResourceDefinition::LayoutQualifier(currentStructure, layout));
4928     currentStructure = generateRandomVariableDefinition(rnd, currentStructure, type, layout, false);
4929 
4930     targetGroup->addChild(new ResourceTestCase(
4931         context, currentStructure,
4932         ProgramResourceQueryTestTarget(PROGRAMINTERFACE_UNIFORM, PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK),
4933         de::toString(index).c_str()));
4934 }
4935 
generateUniformCaseRandomCases(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion)4936 static void generateUniformCaseRandomCases(Context &context, tcu::TestCaseGroup *const targetGroup,
4937                                            glu::GLSLVersion glslVersion)
4938 {
4939     const int numBasicCases   = 40;
4940     const int numTessGeoCases = 40;
4941 
4942     for (int ndx = 0; ndx < numBasicCases; ++ndx)
4943         generateUniformRandomCase(context, targetGroup, glslVersion, ndx, false);
4944     for (int ndx = 0; ndx < numTessGeoCases; ++ndx)
4945         generateUniformRandomCase(context, targetGroup, glslVersion, numBasicCases + ndx, true);
4946 }
4947 
4948 class UniformInterfaceTestGroup : public TestCaseGroup
4949 {
4950 public:
4951     UniformInterfaceTestGroup(Context &context);
4952     void init(void);
4953 };
4954 
UniformInterfaceTestGroup(Context & context)4955 UniformInterfaceTestGroup::UniformInterfaceTestGroup(Context &context)
4956     : TestCaseGroup(context, "uniform", "Uniform interace")
4957 {
4958 }
4959 
init(void)4960 void UniformInterfaceTestGroup::init(void)
4961 {
4962     glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
4963     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
4964     const ResourceDefinition::Node::SharedPtr computeShader(
4965         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
4966 
4967     // .resource_list
4968     {
4969         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "resource_list", "Resource list");
4970         addChild(blockGroup);
4971         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_ALL,
4972                                   generateUniformResourceListBlockContents);
4973     }
4974 
4975     // .array_size
4976     {
4977         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "array_size", "Query array size");
4978         addChild(blockGroup);
4979         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_ALL,
4980                                   generateUniformBlockArraySizeContents);
4981     }
4982 
4983     // .array_stride
4984     {
4985         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "array_stride", "Query array stride");
4986         addChild(blockGroup);
4987         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_ALL,
4988                                   generateUniformBlockArrayStrideContents);
4989     }
4990 
4991     // .atomic_counter_buffer_index
4992     {
4993         tcu::TestCaseGroup *const blockGroup =
4994             new tcu::TestCaseGroup(m_testCtx, "atomic_counter_buffer_index", "Query atomic counter buffer index");
4995         addChild(blockGroup);
4996         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_DEFAULT | BLOCKFLAG_NAMED,
4997                                   generateUniformBlockAtomicCounterBufferIndexContents);
4998     }
4999 
5000     // .block_index
5001     {
5002         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "block_index", "Query block index");
5003         addChild(blockGroup);
5004         generateUniformBlockBlockIndexContents(m_context, blockGroup, glslVersion);
5005     }
5006 
5007     // .location
5008     {
5009         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "location", "Query location");
5010         addChild(blockGroup);
5011         generateUniformCaseBlocks(m_context, computeShader, blockGroup,
5012                                   BLOCKFLAG_DEFAULT | BLOCKFLAG_NAMED | BLOCKFLAG_UNNAMED,
5013                                   generateUniformBlockLocationContents);
5014     }
5015 
5016     // .matrix_row_major
5017     {
5018         tcu::TestCaseGroup *const blockGroup =
5019             new tcu::TestCaseGroup(m_testCtx, "matrix_row_major", "Query matrix row_major");
5020         addChild(blockGroup);
5021         generateUniformMatrixCaseBlocks(m_context, computeShader, blockGroup,
5022                                         generateUniformMatrixOrderCaseBlockContentCases);
5023     }
5024 
5025     // .matrix_stride
5026     {
5027         tcu::TestCaseGroup *const blockGroup =
5028             new tcu::TestCaseGroup(m_testCtx, "matrix_stride", "Query matrix stride");
5029         addChild(blockGroup);
5030         generateUniformMatrixCaseBlocks(m_context, computeShader, blockGroup,
5031                                         generateUniformMatrixStrideCaseBlockContentCases);
5032     }
5033 
5034     // .name_length
5035     {
5036         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "name_length", "Query name length");
5037         addChild(blockGroup);
5038         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_ALL,
5039                                   generateUniformBlockNameLengthContents);
5040     }
5041 
5042     // .offset
5043     {
5044         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "offset", "Query offset");
5045         addChild(blockGroup);
5046         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_ALL,
5047                                   generateUniformBlockOffsetContents);
5048     }
5049 
5050     // .referenced_by_shader
5051     {
5052         tcu::TestCaseGroup *const blockGroup =
5053             new tcu::TestCaseGroup(m_testCtx, "referenced_by_shader", "Query referenced by shader");
5054         addChild(blockGroup);
5055         generateReferencedByShaderCaseBlocks(m_context, blockGroup, glslVersion,
5056                                              generateUniformReferencedByShaderSingleBlockContentCases);
5057     }
5058 
5059     // .type
5060     {
5061         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "type", "Query type");
5062         addChild(blockGroup);
5063         generateUniformCaseBlocks(m_context, computeShader, blockGroup, BLOCKFLAG_ALL,
5064                                   generateUniformBlockTypeContents);
5065     }
5066 
5067     // .random
5068     {
5069         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random");
5070         addChild(blockGroup);
5071         generateUniformCaseRandomCases(m_context, blockGroup, glslVersion);
5072     }
5073 }
5074 
generateBufferBackedInterfaceResourceListCase(Context & context,const ResourceDefinition::Node::SharedPtr & targetResource,tcu::TestCaseGroup * const targetGroup,ProgramInterface interface,const char * blockName)5075 static void generateBufferBackedInterfaceResourceListCase(Context &context,
5076                                                           const ResourceDefinition::Node::SharedPtr &targetResource,
5077                                                           tcu::TestCaseGroup *const targetGroup,
5078                                                           ProgramInterface interface, const char *blockName)
5079 {
5080     targetGroup->addChild(new ResourceListTestCase(context, targetResource, interface, blockName));
5081 }
5082 
generateBufferBackedInterfaceNameLengthCase(Context & context,const ResourceDefinition::Node::SharedPtr & targetResource,tcu::TestCaseGroup * const targetGroup,ProgramInterface interface,const char * blockName)5083 static void generateBufferBackedInterfaceNameLengthCase(Context &context,
5084                                                         const ResourceDefinition::Node::SharedPtr &targetResource,
5085                                                         tcu::TestCaseGroup *const targetGroup,
5086                                                         ProgramInterface interface, const char *blockName)
5087 {
5088     targetGroup->addChild(
5089         new ResourceTestCase(context, targetResource,
5090                              ProgramResourceQueryTestTarget(interface, PROGRAMRESOURCEPROP_NAME_LENGTH), blockName));
5091 }
5092 
generateBufferBackedInterfaceResourceBasicBlockTypes(Context & context,tcu::TestCaseGroup * targetGroup,glu::GLSLVersion glslVersion,glu::Storage storage,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup * const,ProgramInterface interface,const char * blockName))5093 static void generateBufferBackedInterfaceResourceBasicBlockTypes(
5094     Context &context, tcu::TestCaseGroup *targetGroup, glu::GLSLVersion glslVersion, glu::Storage storage,
5095     void (*blockContentGenerator)(Context &, const ResourceDefinition::Node::SharedPtr &, tcu::TestCaseGroup *const,
5096                                   ProgramInterface interface, const char *blockName))
5097 {
5098     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
5099     const ResourceDefinition::Node::SharedPtr shader(
5100         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
5101     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
5102     const ResourceDefinition::Node::SharedPtr storageQualifier(
5103         new ResourceDefinition::StorageQualifier(defaultBlock, storage));
5104     const ResourceDefinition::Node::SharedPtr binding(
5105         new ResourceDefinition::LayoutQualifier(storageQualifier, glu::Layout(-1, 1)));
5106     const ProgramInterface programInterface =
5107         (storage == glu::STORAGE_UNIFORM) ? (PROGRAMINTERFACE_UNIFORM_BLOCK) : (PROGRAMINTERFACE_SHADER_STORAGE_BLOCK);
5108 
5109     // .named_block
5110     {
5111         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(binding, true));
5112         const ResourceDefinition::Node::SharedPtr unusedVariable(
5113             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5114 
5115         blockContentGenerator(context, unusedVariable, targetGroup, programInterface, "named_block");
5116     }
5117 
5118     // .unnamed_block
5119     {
5120         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(binding, false));
5121         const ResourceDefinition::Node::SharedPtr unusedVariable(
5122             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5123 
5124         blockContentGenerator(context, unusedVariable, targetGroup, programInterface, "unnamed_block");
5125     }
5126 
5127     // .block_array
5128     {
5129         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(binding, 3));
5130         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(arrayElement, true));
5131         const ResourceDefinition::Node::SharedPtr unusedVariable(
5132             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5133 
5134         blockContentGenerator(context, unusedVariable, targetGroup, programInterface, "block_array");
5135     }
5136 
5137     // .block_array_single_element
5138     {
5139         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(binding, 1));
5140         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(arrayElement, true));
5141         const ResourceDefinition::Node::SharedPtr unusedVariable(
5142             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5143 
5144         blockContentGenerator(context, unusedVariable, targetGroup, programInterface, "block_array_single_element");
5145     }
5146 }
5147 
generateBufferBackedInterfaceResourceBufferBindingCases(Context & context,tcu::TestCaseGroup * targetGroup,glu::GLSLVersion glslVersion,glu::Storage storage)5148 static void generateBufferBackedInterfaceResourceBufferBindingCases(Context &context, tcu::TestCaseGroup *targetGroup,
5149                                                                     glu::GLSLVersion glslVersion, glu::Storage storage)
5150 {
5151     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
5152     const ResourceDefinition::Node::SharedPtr shader(
5153         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
5154     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
5155     const ResourceDefinition::Node::SharedPtr storageQualifier(
5156         new ResourceDefinition::StorageQualifier(defaultBlock, storage));
5157 
5158     for (int ndx = 0; ndx < 2; ++ndx)
5159     {
5160         const bool explicitBinding   = (ndx == 1);
5161         const int bindingNdx         = (explicitBinding) ? (1) : (-1);
5162         const std::string nameSuffix = (explicitBinding) ? ("_explicit_binding") : ("");
5163         const ResourceDefinition::Node::SharedPtr binding(
5164             new ResourceDefinition::LayoutQualifier(storageQualifier, glu::Layout(-1, bindingNdx)));
5165         const ProgramInterface programInterface = (storage == glu::STORAGE_UNIFORM) ?
5166                                                       (PROGRAMINTERFACE_UNIFORM_BLOCK) :
5167                                                       (PROGRAMINTERFACE_SHADER_STORAGE_BLOCK);
5168 
5169         // .named_block*
5170         {
5171             const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(binding, true));
5172             const ResourceDefinition::Node::SharedPtr unusedVariable(
5173                 new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5174 
5175             targetGroup->addChild(new ResourceTestCase(
5176                 context, unusedVariable,
5177                 ProgramResourceQueryTestTarget(programInterface, PROGRAMRESOURCEPROP_BUFFER_BINDING),
5178                 ("named_block" + nameSuffix).c_str()));
5179         }
5180 
5181         // .unnamed_block*
5182         {
5183             const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(binding, false));
5184             const ResourceDefinition::Node::SharedPtr unusedVariable(
5185                 new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5186 
5187             targetGroup->addChild(new ResourceTestCase(
5188                 context, unusedVariable,
5189                 ProgramResourceQueryTestTarget(programInterface, PROGRAMRESOURCEPROP_BUFFER_BINDING),
5190                 ("unnamed_block" + nameSuffix).c_str()));
5191         }
5192 
5193         // .block_array*
5194         {
5195             const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(binding, 3));
5196             const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(arrayElement, true));
5197             const ResourceDefinition::Node::SharedPtr unusedVariable(
5198                 new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5199 
5200             targetGroup->addChild(new ResourceTestCase(
5201                 context, unusedVariable,
5202                 ProgramResourceQueryTestTarget(programInterface, PROGRAMRESOURCEPROP_BUFFER_BINDING),
5203                 ("block_array" + nameSuffix).c_str()));
5204         }
5205     }
5206 }
5207 
5208 template <glu::Storage Storage>
generateBufferBlockReferencedByShaderSingleBlockContentCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,int expandLevel)5209 static void generateBufferBlockReferencedByShaderSingleBlockContentCases(
5210     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *targetGroup,
5211     int expandLevel)
5212 {
5213     const ProgramInterface programInterface =
5214         (Storage == glu::STORAGE_UNIFORM) ? (PROGRAMINTERFACE_UNIFORM_BLOCK) :
5215         (Storage == glu::STORAGE_BUFFER)  ? (PROGRAMINTERFACE_SHADER_STORAGE_BLOCK) :
5216                                             (PROGRAMINTERFACE_LAST);
5217     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
5218     const ResourceDefinition::Node::SharedPtr storage(new ResourceDefinition::StorageQualifier(defaultBlock, Storage));
5219 
5220     DE_UNREF(expandLevel);
5221 
5222     DE_ASSERT(programInterface != PROGRAMINTERFACE_LAST);
5223 
5224     // .named_block
5225     {
5226         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(storage, true));
5227         const ResourceDefinition::Node::SharedPtr unusedVariable(
5228             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5229 
5230         targetGroup->addChild(new ResourceTestCase(
5231             context, unusedVariable,
5232             ProgramResourceQueryTestTarget(programInterface, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER), "named_block"));
5233     }
5234 
5235     // .unnamed_block
5236     {
5237         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(storage, false));
5238         const ResourceDefinition::Node::SharedPtr unusedVariable(
5239             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5240 
5241         targetGroup->addChild(new ResourceTestCase(
5242             context, unusedVariable,
5243             ProgramResourceQueryTestTarget(programInterface, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER),
5244             "unnamed_block"));
5245     }
5246 
5247     // .block_array
5248     {
5249         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(storage, 3));
5250         const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(arrayElement, true));
5251         const ResourceDefinition::Node::SharedPtr unusedVariable(
5252             new ResourceDefinition::Variable(block, glu::TYPE_BOOL_VEC3));
5253 
5254         targetGroup->addChild(new ResourceTestCase(
5255             context, unusedVariable,
5256             ProgramResourceQueryTestTarget(programInterface, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER), "block_array"));
5257     }
5258 }
5259 
generateBufferBackedInterfaceResourceActiveVariablesCase(Context & context,tcu::TestCaseGroup * targetGroup,glu::Storage storage)5260 static void generateBufferBackedInterfaceResourceActiveVariablesCase(Context &context, tcu::TestCaseGroup *targetGroup,
5261                                                                      glu::Storage storage)
5262 {
5263     targetGroup->addChild(new InterfaceBlockActiveVariablesTestCase(
5264         context, "named_block", "Named block", storage, InterfaceBlockActiveVariablesTestCase::CASE_NAMED_BLOCK));
5265     targetGroup->addChild(new InterfaceBlockActiveVariablesTestCase(
5266         context, "unnamed_block", "Unnamed block", storage, InterfaceBlockActiveVariablesTestCase::CASE_UNNAMED_BLOCK));
5267     targetGroup->addChild(new InterfaceBlockActiveVariablesTestCase(
5268         context, "block_array", "Block array", storage, InterfaceBlockActiveVariablesTestCase::CASE_BLOCK_ARRAY));
5269 }
5270 
generateBufferBackedInterfaceResourceBufferDataSizeCases(Context & context,tcu::TestCaseGroup * targetGroup,glu::Storage storage)5271 static void generateBufferBackedInterfaceResourceBufferDataSizeCases(Context &context, tcu::TestCaseGroup *targetGroup,
5272                                                                      glu::Storage storage)
5273 {
5274     targetGroup->addChild(new InterfaceBlockDataSizeTestCase(context, "named_block", "Named block", storage,
5275                                                              InterfaceBlockDataSizeTestCase::CASE_NAMED_BLOCK));
5276     targetGroup->addChild(new InterfaceBlockDataSizeTestCase(context, "unnamed_block", "Unnamed block", storage,
5277                                                              InterfaceBlockDataSizeTestCase::CASE_UNNAMED_BLOCK));
5278     targetGroup->addChild(new InterfaceBlockDataSizeTestCase(context, "block_array", "Block array", storage,
5279                                                              InterfaceBlockDataSizeTestCase::CASE_BLOCK_ARRAY));
5280 }
5281 
5282 class BufferBackedBlockInterfaceTestGroup : public TestCaseGroup
5283 {
5284 public:
5285     BufferBackedBlockInterfaceTestGroup(Context &context, glu::Storage interfaceBlockStorage);
5286     void init(void);
5287 
5288 private:
5289     static const char *getGroupName(glu::Storage storage);
5290     static const char *getGroupDescription(glu::Storage storage);
5291 
5292     const glu::Storage m_storage;
5293 };
5294 
BufferBackedBlockInterfaceTestGroup(Context & context,glu::Storage storage)5295 BufferBackedBlockInterfaceTestGroup::BufferBackedBlockInterfaceTestGroup(Context &context, glu::Storage storage)
5296     : TestCaseGroup(context, getGroupName(storage), getGroupDescription(storage))
5297     , m_storage(storage)
5298 {
5299     DE_ASSERT(storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM);
5300 }
5301 
init(void)5302 void BufferBackedBlockInterfaceTestGroup::init(void)
5303 {
5304     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
5305 
5306     // .resource_list
5307     {
5308         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "resource_list", "Resource list");
5309         addChild(blockGroup);
5310         generateBufferBackedInterfaceResourceBasicBlockTypes(m_context, blockGroup, glslVersion, m_storage,
5311                                                              generateBufferBackedInterfaceResourceListCase);
5312     }
5313 
5314     // .active_variables
5315     {
5316         tcu::TestCaseGroup *const blockGroup =
5317             new tcu::TestCaseGroup(m_testCtx, "active_variables", "Active variables");
5318         addChild(blockGroup);
5319         generateBufferBackedInterfaceResourceActiveVariablesCase(m_context, blockGroup, m_storage);
5320     }
5321 
5322     // .buffer_binding
5323     {
5324         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "buffer_binding", "Buffer binding");
5325         addChild(blockGroup);
5326         generateBufferBackedInterfaceResourceBufferBindingCases(m_context, blockGroup, glslVersion, m_storage);
5327     }
5328 
5329     // .buffer_data_size
5330     {
5331         tcu::TestCaseGroup *const blockGroup =
5332             new tcu::TestCaseGroup(m_testCtx, "buffer_data_size", "Buffer data size");
5333         addChild(blockGroup);
5334         generateBufferBackedInterfaceResourceBufferDataSizeCases(m_context, blockGroup, m_storage);
5335     }
5336 
5337     // .name_length
5338     {
5339         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "name_length", "Name length");
5340         addChild(blockGroup);
5341         generateBufferBackedInterfaceResourceBasicBlockTypes(m_context, blockGroup, glslVersion, m_storage,
5342                                                              generateBufferBackedInterfaceNameLengthCase);
5343     }
5344 
5345     // .referenced_by
5346     {
5347         tcu::TestCaseGroup *const blockGroup =
5348             new tcu::TestCaseGroup(m_testCtx, "referenced_by", "Referenced by shader");
5349         addChild(blockGroup);
5350 
5351         if (m_storage == glu::STORAGE_UNIFORM)
5352             generateReferencedByShaderCaseBlocks(
5353                 m_context, blockGroup, glslVersion,
5354                 generateBufferBlockReferencedByShaderSingleBlockContentCases<glu::STORAGE_UNIFORM>);
5355         else if (m_storage == glu::STORAGE_BUFFER)
5356             generateReferencedByShaderCaseBlocks(
5357                 m_context, blockGroup, glslVersion,
5358                 generateBufferBlockReferencedByShaderSingleBlockContentCases<glu::STORAGE_BUFFER>);
5359         else
5360             DE_ASSERT(false);
5361     }
5362 }
5363 
getGroupName(glu::Storage storage)5364 const char *BufferBackedBlockInterfaceTestGroup::getGroupName(glu::Storage storage)
5365 {
5366     switch (storage)
5367     {
5368     case glu::STORAGE_UNIFORM:
5369         return "uniform_block";
5370     case glu::STORAGE_BUFFER:
5371         return "shader_storage_block";
5372     default:
5373         DE_FATAL("invalid storage enum value");
5374         return DE_NULL;
5375     }
5376 }
5377 
getGroupDescription(glu::Storage storage)5378 const char *BufferBackedBlockInterfaceTestGroup::getGroupDescription(glu::Storage storage)
5379 {
5380     switch (storage)
5381     {
5382     case glu::STORAGE_UNIFORM:
5383         return "Uniform block interface";
5384     case glu::STORAGE_BUFFER:
5385         return "Shader storage block interface";
5386     default:
5387         DE_FATAL("invalid storage enum value");
5388         return DE_NULL;
5389     }
5390 }
5391 
5392 class AtomicCounterTestGroup : public TestCaseGroup
5393 {
5394 public:
5395     AtomicCounterTestGroup(Context &context);
5396     void init(void);
5397 };
5398 
AtomicCounterTestGroup(Context & context)5399 AtomicCounterTestGroup::AtomicCounterTestGroup(Context &context)
5400     : TestCaseGroup(context, "atomic_counter_buffer", "Atomic counter buffer")
5401 {
5402 }
5403 
init(void)5404 void AtomicCounterTestGroup::init(void)
5405 {
5406     static const struct
5407     {
5408         const char *name;
5409         uint32_t flags;
5410     } pipelines[] = {
5411         {"vertex_fragment", (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT)},
5412         {"vertex_tess_fragment", (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) |
5413                                      (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) |
5414                                      (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION)},
5415         {"vertex_geo_fragment",
5416          (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) | (1 << glu::SHADERTYPE_GEOMETRY)},
5417         {
5418             "vertex_tess_geo_fragment",
5419             (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) |
5420                 (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) | (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION) |
5421                 (1 << glu::SHADERTYPE_GEOMETRY),
5422         },
5423     };
5424 
5425     // .resource_list
5426     addChild(new AtomicCounterResourceListCase(m_context, "resource_list", "Resource list"));
5427 
5428     // .active_variables
5429     addChild(new AtomicCounterActiveVariablesCase(m_context, "active_variables", "Active variables"));
5430 
5431     // .buffer_binding
5432     addChild(new AtomicCounterBufferBindingCase(m_context, "buffer_binding", "Buffer binding"));
5433 
5434     // .buffer_data_size
5435     addChild(new AtomicCounterBufferDataSizeCase(m_context, "buffer_data_size", "Buffer binding"));
5436 
5437     // .referenced_by
5438     addChild(new AtomicCounterReferencedByCase(m_context, "referenced_by_compute", "", false,
5439                                                (1 << glu::SHADERTYPE_COMPUTE), (1 << glu::SHADERTYPE_COMPUTE)));
5440     addChild(new AtomicCounterReferencedByCase(m_context, "referenced_by_separable_vertex", "", true,
5441                                                (1 << glu::SHADERTYPE_VERTEX), (1 << glu::SHADERTYPE_VERTEX)));
5442     addChild(new AtomicCounterReferencedByCase(m_context, "referenced_by_separable_fragment", "", true,
5443                                                (1 << glu::SHADERTYPE_FRAGMENT), (1 << glu::SHADERTYPE_FRAGMENT)));
5444     addChild(new AtomicCounterReferencedByCase(m_context, "referenced_by_separable_geometry", "", true,
5445                                                (1 << glu::SHADERTYPE_GEOMETRY), (1 << glu::SHADERTYPE_GEOMETRY)));
5446     addChild(new AtomicCounterReferencedByCase(m_context, "referenced_by_separable_tess_ctrl", "", true,
5447                                                (1 << glu::SHADERTYPE_TESSELLATION_CONTROL),
5448                                                (1 << glu::SHADERTYPE_TESSELLATION_CONTROL)));
5449     addChild(new AtomicCounterReferencedByCase(m_context, "referenced_by_separable_tess_eval", "", true,
5450                                                (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION),
5451                                                (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION)));
5452 
5453     for (int pipelineNdx = 0; pipelineNdx < DE_LENGTH_OF_ARRAY(pipelines); ++pipelineNdx)
5454     {
5455         addChild(new AtomicCounterReferencedByCase(
5456             m_context, (std::string() + "referenced_by_" + pipelines[pipelineNdx].name).c_str(), "", false,
5457             pipelines[pipelineNdx].flags, pipelines[pipelineNdx].flags));
5458 
5459         for (uint32_t stageNdx = 0; stageNdx < glu::SHADERTYPE_LAST; ++stageNdx)
5460         {
5461             const uint32_t currentBit = (1u << stageNdx);
5462             if (currentBit > pipelines[pipelineNdx].flags)
5463                 break;
5464             if (currentBit & pipelines[pipelineNdx].flags)
5465             {
5466                 const char *stageName = (stageNdx == glu::SHADERTYPE_VERTEX)                  ? ("vertex") :
5467                                         (stageNdx == glu::SHADERTYPE_FRAGMENT)                ? ("fragment") :
5468                                         (stageNdx == glu::SHADERTYPE_GEOMETRY)                ? ("geo") :
5469                                         (stageNdx == glu::SHADERTYPE_TESSELLATION_CONTROL)    ? ("tess_ctrl") :
5470                                         (stageNdx == glu::SHADERTYPE_TESSELLATION_EVALUATION) ? ("tess_eval") :
5471                                                                                                 (DE_NULL);
5472                 const std::string name =
5473                     std::string() + "referenced_by_" + pipelines[pipelineNdx].name + "_only_" + stageName;
5474 
5475                 addChild(new AtomicCounterReferencedByCase(m_context, name.c_str(), "", false,
5476                                                            pipelines[pipelineNdx].flags, currentBit));
5477             }
5478         }
5479     }
5480 }
5481 
generateProgramInputOutputShaderCaseBlocks(Context & context,tcu::TestCaseGroup * targetGroup,glu::GLSLVersion glslVersion,bool withCompute,bool inputCase,bool isGL45,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup *,uint32_t,bool))5482 static void generateProgramInputOutputShaderCaseBlocks(
5483     Context &context, tcu::TestCaseGroup *targetGroup, glu::GLSLVersion glslVersion, bool withCompute, bool inputCase,
5484     bool isGL45,
5485     void (*blockContentGenerator)(Context &, const ResourceDefinition::Node::SharedPtr &, tcu::TestCaseGroup *,
5486                                   uint32_t, bool))
5487 {
5488     static const struct
5489     {
5490         const char *name;
5491         glu::ShaderType stage;
5492     } singleStageCases[] = {
5493         {"separable_vertex", glu::SHADERTYPE_VERTEX},
5494         {"separable_fragment", glu::SHADERTYPE_FRAGMENT},
5495         {"separable_tess_ctrl", glu::SHADERTYPE_TESSELLATION_CONTROL},
5496         {"separable_tess_eval", glu::SHADERTYPE_TESSELLATION_EVALUATION},
5497         {"separable_geometry", glu::SHADERTYPE_GEOMETRY},
5498     };
5499 
5500     // .vertex_fragment
5501     {
5502         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "vertex_fragment", "Vertex and fragment");
5503         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(false));
5504         ResourceDefinition::ShaderSet *shaderSetPtr = new ResourceDefinition::ShaderSet(program, glslVersion);
5505         const ResourceDefinition::Node::SharedPtr shaderSet(shaderSetPtr);
5506         const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shaderSet));
5507 
5508         shaderSetPtr->setStage(glu::SHADERTYPE_VERTEX, inputCase);
5509         shaderSetPtr->setStage(glu::SHADERTYPE_FRAGMENT, !inputCase);
5510 
5511         targetGroup->addChild(blockGroup);
5512 
5513         blockContentGenerator(context, defaultBlock, blockGroup,
5514                               (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT), isGL45);
5515     }
5516 
5517     // .separable_*
5518     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleStageCases); ++ndx)
5519     {
5520         TestCaseGroup *const blockGroup = new TestCaseGroup(context, singleStageCases[ndx].name, "");
5521         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(true));
5522         const ResourceDefinition::Node::SharedPtr shader(
5523             new ResourceDefinition::Shader(program, singleStageCases[ndx].stage, glslVersion));
5524         const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
5525 
5526         targetGroup->addChild(blockGroup);
5527         blockContentGenerator(context, defaultBlock, blockGroup, (1 << singleStageCases[ndx].stage), isGL45);
5528     }
5529 
5530     // .compute
5531     if (withCompute)
5532     {
5533         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "compute", "Compute");
5534         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(true));
5535         const ResourceDefinition::Node::SharedPtr shader(
5536             new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
5537         const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
5538 
5539         targetGroup->addChild(blockGroup);
5540 
5541         blockContentGenerator(context, defaultBlock, blockGroup, (1 << glu::SHADERTYPE_COMPUTE), isGL45);
5542     }
5543 
5544     // .interface_blocks
5545     {
5546         static const struct
5547         {
5548             const char *inputName;
5549             glu::ShaderType inputStage;
5550             glu::Storage inputStorage;
5551             const char *outputName;
5552             glu::ShaderType outputStage;
5553             glu::Storage outputStorage;
5554         } ioBlockTypes[] = {
5555             {
5556                 "in",
5557                 glu::SHADERTYPE_FRAGMENT,
5558                 glu::STORAGE_IN,
5559                 "out",
5560                 glu::SHADERTYPE_VERTEX,
5561                 glu::STORAGE_OUT,
5562             },
5563             {
5564                 "patch_in",
5565                 glu::SHADERTYPE_TESSELLATION_EVALUATION,
5566                 glu::STORAGE_PATCH_IN,
5567                 "patch_out",
5568                 glu::SHADERTYPE_TESSELLATION_CONTROL,
5569                 glu::STORAGE_PATCH_OUT,
5570             },
5571         };
5572 
5573         tcu::TestCaseGroup *const ioBlocksGroup = new TestCaseGroup(context, "interface_blocks", "Interface blocks");
5574         targetGroup->addChild(ioBlocksGroup);
5575 
5576         // .in/out
5577         // .sample in/out
5578         // .patch in/out
5579         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ioBlockTypes); ++ndx)
5580         {
5581             const char *const name = (inputCase) ? (ioBlockTypes[ndx].inputName) : (ioBlockTypes[ndx].outputName);
5582             const glu::ShaderType shaderType =
5583                 (inputCase) ? (ioBlockTypes[ndx].inputStage) : (ioBlockTypes[ndx].outputStage);
5584             const glu::Storage storageType =
5585                 (inputCase) ? (ioBlockTypes[ndx].inputStorage) : (ioBlockTypes[ndx].outputStorage);
5586             tcu::TestCaseGroup *const ioBlockGroup = new TestCaseGroup(context, name, "");
5587             const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(true));
5588             const ResourceDefinition::Node::SharedPtr shader(
5589                 new ResourceDefinition::Shader(program, shaderType, glslVersion));
5590             const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
5591             const ResourceDefinition::Node::SharedPtr storage(
5592                 new ResourceDefinition::StorageQualifier(defaultBlock, storageType));
5593 
5594             ioBlocksGroup->addChild(ioBlockGroup);
5595 
5596             // .named_block
5597             {
5598                 const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(storage, true));
5599                 tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "named_block", "Named block");
5600 
5601                 ioBlockGroup->addChild(blockGroup);
5602 
5603                 blockContentGenerator(context, block, blockGroup, (1 << shaderType), isGL45);
5604             }
5605 
5606             // .named_block_explicit_location
5607             {
5608                 const ResourceDefinition::Node::SharedPtr layout(
5609                     new ResourceDefinition::LayoutQualifier(storage, glu::Layout(3)));
5610                 const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(layout, true));
5611                 tcu::TestCaseGroup *const blockGroup =
5612                     new TestCaseGroup(context, "named_block_explicit_location", "Named block with explicit location");
5613 
5614                 ioBlockGroup->addChild(blockGroup);
5615 
5616                 blockContentGenerator(context, block, blockGroup, (1 << shaderType), isGL45);
5617             }
5618 
5619             // .unnamed_block
5620             if (!isGL45)
5621             {
5622                 const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(storage, false));
5623                 tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unnamed_block", "Unnamed block");
5624 
5625                 ioBlockGroup->addChild(blockGroup);
5626 
5627                 blockContentGenerator(context, block, blockGroup, (1 << shaderType), isGL45);
5628             }
5629 
5630             // .block_array
5631             {
5632                 const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(storage));
5633                 const ResourceDefinition::Node::SharedPtr block(
5634                     new ResourceDefinition::InterfaceBlock(arrayElement, true));
5635                 tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "block_array", "Block array");
5636 
5637                 ioBlockGroup->addChild(blockGroup);
5638 
5639                 blockContentGenerator(context, block, blockGroup, (1 << shaderType), isGL45);
5640             }
5641         }
5642     }
5643 }
5644 
generateProgramInputBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool includeEmpty,void (* genCase)(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,ProgramInterface interface,const char * name))5645 static void generateProgramInputBlockContents(
5646     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *targetGroup,
5647     uint32_t presentShadersMask, bool includeEmpty,
5648     void (*genCase)(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
5649                     tcu::TestCaseGroup *targetGroup, ProgramInterface interface, const char *name))
5650 {
5651     const bool inDefaultBlock = parentStructure->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK;
5652     const ResourceDefinition::Node::SharedPtr input =
5653         (inDefaultBlock) ? (ResourceDefinition::Node::SharedPtr(
5654                                new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_IN))) :
5655                            (parentStructure);
5656     const glu::ShaderType firstStage = getShaderMaskFirstStage(presentShadersMask);
5657 
5658     // .empty
5659     if (includeEmpty && inDefaultBlock)
5660         genCase(context, parentStructure, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "empty");
5661 
5662     if (firstStage == glu::SHADERTYPE_VERTEX)
5663     {
5664         // .var
5665         const ResourceDefinition::Node::SharedPtr variable(
5666             new ResourceDefinition::Variable(input, glu::TYPE_FLOAT_VEC4));
5667         genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "var");
5668     }
5669     else if (firstStage == glu::SHADERTYPE_FRAGMENT || !inDefaultBlock)
5670     {
5671         // .var
5672         {
5673             const ResourceDefinition::Node::SharedPtr variable(
5674                 new ResourceDefinition::Variable(input, glu::TYPE_FLOAT_VEC4));
5675             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "var");
5676         }
5677         // .var_struct
5678         {
5679             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(input));
5680             const ResourceDefinition::Node::SharedPtr variable(
5681                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
5682             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "var_struct");
5683         }
5684         // .var_array
5685         {
5686             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(input));
5687             const ResourceDefinition::Node::SharedPtr variable(
5688                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5689             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "var_array");
5690         }
5691     }
5692     else if (firstStage == glu::SHADERTYPE_TESSELLATION_CONTROL || firstStage == glu::SHADERTYPE_GEOMETRY)
5693     {
5694         // arrayed interface
5695 
5696         // .var
5697         {
5698             const ResourceDefinition::Node::SharedPtr arrayElem(
5699                 new ResourceDefinition::ArrayElement(input, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
5700             const ResourceDefinition::Node::SharedPtr variable(
5701                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5702             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "var");
5703         }
5704         // extension forbids use arrays of structs
5705         // extension forbids use arrays of arrays
5706     }
5707     else if (firstStage == glu::SHADERTYPE_TESSELLATION_EVALUATION)
5708     {
5709         // arrayed interface
5710         const ResourceDefinition::Node::SharedPtr patchInput(
5711             new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_PATCH_IN));
5712 
5713         // .var
5714         {
5715             const ResourceDefinition::Node::SharedPtr arrayElem(
5716                 new ResourceDefinition::ArrayElement(input, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
5717             const ResourceDefinition::Node::SharedPtr variable(
5718                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5719             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "var");
5720         }
5721         // extension forbids use arrays of structs
5722         // extension forbids use arrays of arrays
5723 
5724         // .patch_var
5725         {
5726             const ResourceDefinition::Node::SharedPtr variable(
5727                 new ResourceDefinition::Variable(patchInput, glu::TYPE_FLOAT_VEC4));
5728             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "patch_var");
5729         }
5730         // .patch_var_struct
5731         {
5732             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(patchInput));
5733             const ResourceDefinition::Node::SharedPtr variable(
5734                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
5735             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "patch_var_struct");
5736         }
5737         // .patch_var_array
5738         {
5739             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(patchInput));
5740             const ResourceDefinition::Node::SharedPtr variable(
5741                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5742             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_INPUT, "patch_var_array");
5743         }
5744     }
5745     else if (firstStage == glu::SHADERTYPE_COMPUTE)
5746     {
5747         // nada
5748     }
5749     else
5750         DE_ASSERT(false);
5751 }
5752 
generateProgramOutputBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool includeEmpty,void (* genCase)(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,ProgramInterface interface,const char * name))5753 static void generateProgramOutputBlockContents(
5754     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *targetGroup,
5755     uint32_t presentShadersMask, bool includeEmpty,
5756     void (*genCase)(Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure,
5757                     tcu::TestCaseGroup *targetGroup, ProgramInterface interface, const char *name))
5758 {
5759     const bool inDefaultBlock = parentStructure->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK;
5760     const ResourceDefinition::Node::SharedPtr output =
5761         (inDefaultBlock) ? (ResourceDefinition::Node::SharedPtr(
5762                                new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_OUT))) :
5763                            (parentStructure);
5764     const glu::ShaderType lastStage = getShaderMaskLastStage(presentShadersMask);
5765 
5766     // .empty
5767     if (includeEmpty && inDefaultBlock)
5768         genCase(context, parentStructure, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "empty");
5769 
5770     if (lastStage == glu::SHADERTYPE_VERTEX || lastStage == glu::SHADERTYPE_GEOMETRY ||
5771         lastStage == glu::SHADERTYPE_TESSELLATION_EVALUATION || !inDefaultBlock)
5772     {
5773         // .var
5774         {
5775             const ResourceDefinition::Node::SharedPtr variable(
5776                 new ResourceDefinition::Variable(output, glu::TYPE_FLOAT_VEC4));
5777             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "var");
5778         }
5779         // .var_struct
5780         {
5781             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(output));
5782             const ResourceDefinition::Node::SharedPtr variable(
5783                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
5784             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "var_struct");
5785         }
5786         // .var_array
5787         {
5788             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(output));
5789             const ResourceDefinition::Node::SharedPtr variable(
5790                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5791             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "var_array");
5792         }
5793     }
5794     else if (lastStage == glu::SHADERTYPE_FRAGMENT)
5795     {
5796         // .var
5797         {
5798             const ResourceDefinition::Node::SharedPtr variable(
5799                 new ResourceDefinition::Variable(output, glu::TYPE_FLOAT_VEC4));
5800             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "var");
5801         }
5802         // .var_array
5803         {
5804             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(output));
5805             const ResourceDefinition::Node::SharedPtr variable(
5806                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5807             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "var_array");
5808         }
5809     }
5810     else if (lastStage == glu::SHADERTYPE_TESSELLATION_CONTROL)
5811     {
5812         // arrayed interface
5813         const ResourceDefinition::Node::SharedPtr patchOutput(
5814             new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_PATCH_OUT));
5815 
5816         // .var
5817         {
5818             const ResourceDefinition::Node::SharedPtr arrayElem(
5819                 new ResourceDefinition::ArrayElement(output, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
5820             const ResourceDefinition::Node::SharedPtr variable(
5821                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5822             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "var");
5823         }
5824         // extension forbids use arrays of structs
5825         // extension forbids use array of arrays
5826 
5827         // .patch_var
5828         {
5829             const ResourceDefinition::Node::SharedPtr variable(
5830                 new ResourceDefinition::Variable(patchOutput, glu::TYPE_FLOAT_VEC4));
5831             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "patch_var");
5832         }
5833         // .patch_var_struct
5834         {
5835             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(patchOutput));
5836             const ResourceDefinition::Node::SharedPtr variable(
5837                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
5838             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "patch_var_struct");
5839         }
5840         // .patch_var_array
5841         {
5842             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(patchOutput));
5843             const ResourceDefinition::Node::SharedPtr variable(
5844                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
5845             genCase(context, variable, targetGroup, PROGRAMINTERFACE_PROGRAM_OUTPUT, "patch_var_array");
5846         }
5847     }
5848     else if (lastStage == glu::SHADERTYPE_COMPUTE)
5849     {
5850         // nada
5851     }
5852     else
5853         DE_ASSERT(false);
5854 }
5855 
addProgramInputOutputResourceListCase(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,ProgramInterface programInterface,const char * name)5856 static void addProgramInputOutputResourceListCase(Context &context,
5857                                                   const ResourceDefinition::Node::SharedPtr &parentStructure,
5858                                                   tcu::TestCaseGroup *targetGroup, ProgramInterface programInterface,
5859                                                   const char *name)
5860 {
5861     ResourceListTestCase *const resourceListCase = new ResourceListTestCase(context, parentStructure, programInterface);
5862 
5863     DE_ASSERT(deStringEqual(name, resourceListCase->getName()));
5864     DE_UNREF(name);
5865     targetGroup->addChild(resourceListCase);
5866 }
5867 
generateProgramInputResourceListBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)5868 static void generateProgramInputResourceListBlockContents(Context &context,
5869                                                           const ResourceDefinition::Node::SharedPtr &parentStructure,
5870                                                           tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
5871                                                           bool isGL45)
5872 {
5873     DE_UNREF(isGL45);
5874     generateProgramInputBlockContents(context, parentStructure, targetGroup, presentShadersMask, true,
5875                                       addProgramInputOutputResourceListCase);
5876 }
5877 
generateProgramOutputResourceListBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)5878 static void generateProgramOutputResourceListBlockContents(Context &context,
5879                                                            const ResourceDefinition::Node::SharedPtr &parentStructure,
5880                                                            tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
5881                                                            bool isGL45)
5882 {
5883     DE_UNREF(isGL45);
5884     generateProgramOutputBlockContents(context, parentStructure, targetGroup, presentShadersMask, true,
5885                                        addProgramInputOutputResourceListCase);
5886 }
5887 
5888 template <ProgramResourcePropFlags TargetProp>
addProgramInputOutputResourceTestCase(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,ProgramInterface programInterface,const char * name)5889 static void addProgramInputOutputResourceTestCase(Context &context,
5890                                                   const ResourceDefinition::Node::SharedPtr &parentStructure,
5891                                                   tcu::TestCaseGroup *targetGroup, ProgramInterface programInterface,
5892                                                   const char *name)
5893 {
5894     ResourceTestCase *const resourceTestCase = new ResourceTestCase(
5895         context, parentStructure, ProgramResourceQueryTestTarget(programInterface, TargetProp), name);
5896     targetGroup->addChild(resourceTestCase);
5897 }
5898 
5899 template <ProgramResourcePropFlags TargetProp>
generateProgramInputBasicBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)5900 static void generateProgramInputBasicBlockContents(Context &context,
5901                                                    const ResourceDefinition::Node::SharedPtr &parentStructure,
5902                                                    tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
5903                                                    bool isGL45)
5904 {
5905     DE_UNREF(isGL45);
5906     generateProgramInputBlockContents(context, parentStructure, targetGroup, presentShadersMask, false,
5907                                       addProgramInputOutputResourceTestCase<TargetProp>);
5908 }
5909 
5910 template <ProgramResourcePropFlags TargetProp>
generateProgramOutputBasicBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)5911 static void generateProgramOutputBasicBlockContents(Context &context,
5912                                                     const ResourceDefinition::Node::SharedPtr &parentStructure,
5913                                                     tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
5914                                                     bool isGL45)
5915 {
5916     DE_UNREF(isGL45);
5917     generateProgramOutputBlockContents(context, parentStructure, targetGroup, presentShadersMask, false,
5918                                        addProgramInputOutputResourceTestCase<TargetProp>);
5919 }
5920 
generateProgramInputLocationBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)5921 static void generateProgramInputLocationBlockContents(Context &context,
5922                                                       const ResourceDefinition::Node::SharedPtr &parentStructure,
5923                                                       tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
5924                                                       bool isGL45)
5925 {
5926     DE_UNREF(isGL45);
5927     const bool inDefaultBlock = parentStructure->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK;
5928     const ResourceDefinition::Node::SharedPtr input =
5929         (inDefaultBlock) ? (ResourceDefinition::Node::SharedPtr(
5930                                new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_IN))) :
5931                            (parentStructure);
5932     const glu::ShaderType firstStage = getShaderMaskFirstStage(presentShadersMask);
5933 
5934     const bool inBlockArray = true == deStringEqual("block_array", targetGroup->getName());
5935 
5936     if (firstStage == glu::SHADERTYPE_VERTEX)
5937     {
5938         // .var
5939         {
5940             const ResourceDefinition::Node::SharedPtr variable(
5941                 new ResourceDefinition::Variable(input, glu::TYPE_FLOAT_VEC4));
5942             targetGroup->addChild(new ResourceTestCase(
5943                 context, variable,
5944                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
5945         }
5946         // .var_explicit_location
5947         {
5948             const ResourceDefinition::Node::SharedPtr layout(
5949                 new ResourceDefinition::LayoutQualifier(input, glu::Layout(2)));
5950             const ResourceDefinition::Node::SharedPtr variable(
5951                 new ResourceDefinition::Variable(layout, glu::TYPE_FLOAT_VEC4));
5952             targetGroup->addChild(new ResourceTestCase(
5953                 context, variable,
5954                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
5955                 "var_explicit_location"));
5956         }
5957     }
5958     else if (firstStage == glu::SHADERTYPE_FRAGMENT || !inDefaultBlock)
5959     {
5960         // .var
5961         {
5962             const ResourceDefinition::Node::SharedPtr variable(
5963                 new ResourceDefinition::Variable(input, glu::TYPE_FLOAT_VEC4));
5964             targetGroup->addChild(new ResourceTestCase(
5965                 context, variable,
5966                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
5967         }
5968         // .var_explicit_location
5969         if (!inBlockArray)
5970         {
5971             const ResourceDefinition::Node::SharedPtr layout(
5972                 new ResourceDefinition::LayoutQualifier(input, glu::Layout(2)));
5973             const ResourceDefinition::Node::SharedPtr variable(
5974                 new ResourceDefinition::Variable(layout, glu::TYPE_FLOAT_VEC4));
5975             targetGroup->addChild(new ResourceTestCase(
5976                 context, variable,
5977                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
5978                 "var_explicit_location"));
5979         }
5980         // .var_struct
5981         {
5982             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(input));
5983             const ResourceDefinition::Node::SharedPtr variable(
5984                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
5985             targetGroup->addChild(new ResourceTestCase(
5986                 context, variable,
5987                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
5988                 "var_struct"));
5989         }
5990         // .var_struct_explicit_location
5991         if (!inBlockArray)
5992         {
5993             const ResourceDefinition::Node::SharedPtr layout(
5994                 new ResourceDefinition::LayoutQualifier(input, glu::Layout(2)));
5995             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(layout));
5996             const ResourceDefinition::Node::SharedPtr variable(
5997                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
5998             targetGroup->addChild(new ResourceTestCase(
5999                 context, variable,
6000                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6001                 "var_struct_explicit_location"));
6002         }
6003         // .var_array
6004         {
6005             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(input));
6006             const ResourceDefinition::Node::SharedPtr variable(
6007                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6008             targetGroup->addChild(new ResourceTestCase(
6009                 context, variable,
6010                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6011                 "var_array"));
6012         }
6013         // .var_array_explicit_location
6014         if (!inBlockArray)
6015         {
6016             const ResourceDefinition::Node::SharedPtr layout(
6017                 new ResourceDefinition::LayoutQualifier(input, glu::Layout(2)));
6018             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(layout));
6019             const ResourceDefinition::Node::SharedPtr variable(
6020                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6021             targetGroup->addChild(new ResourceTestCase(
6022                 context, variable,
6023                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6024                 "var_array_explicit_location"));
6025         }
6026     }
6027     else if (firstStage == glu::SHADERTYPE_TESSELLATION_CONTROL || firstStage == glu::SHADERTYPE_GEOMETRY)
6028     {
6029         // arrayed interface
6030 
6031         // .var
6032         {
6033             const ResourceDefinition::Node::SharedPtr arrayElem(
6034                 new ResourceDefinition::ArrayElement(input, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6035             const ResourceDefinition::Node::SharedPtr variable(
6036                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6037             targetGroup->addChild(new ResourceTestCase(
6038                 context, variable,
6039                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
6040         }
6041         // .var_explicit_location
6042         {
6043             const ResourceDefinition::Node::SharedPtr layout(
6044                 new ResourceDefinition::LayoutQualifier(input, glu::Layout(2)));
6045             const ResourceDefinition::Node::SharedPtr arrayElem(
6046                 new ResourceDefinition::ArrayElement(layout, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6047             const ResourceDefinition::Node::SharedPtr variable(
6048                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6049             targetGroup->addChild(new ResourceTestCase(
6050                 context, variable,
6051                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6052                 "var_explicit_location"));
6053         }
6054         // extension forbids use arrays of structs
6055         // extension forbids use arrays of arrays
6056     }
6057     else if (firstStage == glu::SHADERTYPE_TESSELLATION_EVALUATION)
6058     {
6059         // arrayed interface
6060         const ResourceDefinition::Node::SharedPtr patchInput(
6061             new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_PATCH_IN));
6062 
6063         // .var
6064         {
6065             const ResourceDefinition::Node::SharedPtr arrayElem(
6066                 new ResourceDefinition::ArrayElement(input, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6067             const ResourceDefinition::Node::SharedPtr variable(
6068                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6069             targetGroup->addChild(new ResourceTestCase(
6070                 context, variable,
6071                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
6072         }
6073         // .var_explicit_location
6074         {
6075             const ResourceDefinition::Node::SharedPtr layout(
6076                 new ResourceDefinition::LayoutQualifier(input, glu::Layout(2)));
6077             const ResourceDefinition::Node::SharedPtr arrayElem(
6078                 new ResourceDefinition::ArrayElement(layout, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6079             const ResourceDefinition::Node::SharedPtr variable(
6080                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6081             targetGroup->addChild(new ResourceTestCase(
6082                 context, variable,
6083                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6084                 "var_explicit_location"));
6085         }
6086         // extension forbids use arrays of structs
6087         // extension forbids use arrays of arrays
6088 
6089         // .patch_var
6090         {
6091             const ResourceDefinition::Node::SharedPtr variable(
6092                 new ResourceDefinition::Variable(patchInput, glu::TYPE_FLOAT_VEC4));
6093             targetGroup->addChild(new ResourceTestCase(
6094                 context, variable,
6095                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6096                 "patch_var"));
6097         }
6098         // .patch_var_explicit_location
6099         {
6100             const ResourceDefinition::Node::SharedPtr layout(
6101                 new ResourceDefinition::LayoutQualifier(patchInput, glu::Layout(2)));
6102             const ResourceDefinition::Node::SharedPtr variable(
6103                 new ResourceDefinition::Variable(layout, glu::TYPE_FLOAT_VEC4));
6104             targetGroup->addChild(new ResourceTestCase(
6105                 context, variable,
6106                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6107                 "patch_var_explicit_location"));
6108         }
6109         // .patch_var_struct
6110         {
6111             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(patchInput));
6112             const ResourceDefinition::Node::SharedPtr variable(
6113                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
6114             targetGroup->addChild(new ResourceTestCase(
6115                 context, variable,
6116                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6117                 "patch_var_struct"));
6118         }
6119         // .patch_var_struct_explicit_location
6120         {
6121             const ResourceDefinition::Node::SharedPtr layout(
6122                 new ResourceDefinition::LayoutQualifier(patchInput, glu::Layout(2)));
6123             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(layout));
6124             const ResourceDefinition::Node::SharedPtr variable(
6125                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
6126             targetGroup->addChild(new ResourceTestCase(
6127                 context, variable,
6128                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6129                 "patch_var_struct_explicit_location"));
6130         }
6131         // .patch_var_array
6132         {
6133             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(patchInput));
6134             const ResourceDefinition::Node::SharedPtr variable(
6135                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6136             targetGroup->addChild(new ResourceTestCase(
6137                 context, variable,
6138                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6139                 "patch_var_array"));
6140         }
6141         // .patch_var_array_explicit_location
6142         {
6143             const ResourceDefinition::Node::SharedPtr layout(
6144                 new ResourceDefinition::LayoutQualifier(patchInput, glu::Layout(2)));
6145             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(layout));
6146             const ResourceDefinition::Node::SharedPtr variable(
6147                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6148             targetGroup->addChild(new ResourceTestCase(
6149                 context, variable,
6150                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_INPUT, PROGRAMRESOURCEPROP_LOCATION),
6151                 "patch_var_array_explicit_location"));
6152         }
6153     }
6154     else if (firstStage == glu::SHADERTYPE_COMPUTE)
6155     {
6156         // nada
6157     }
6158     else
6159         DE_ASSERT(false);
6160 }
6161 
generateProgramOutputLocationBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)6162 static void generateProgramOutputLocationBlockContents(Context &context,
6163                                                        const ResourceDefinition::Node::SharedPtr &parentStructure,
6164                                                        tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
6165                                                        bool isGL45)
6166 {
6167     DE_UNREF(isGL45);
6168     const bool inDefaultBlock = parentStructure->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK;
6169     const ResourceDefinition::Node::SharedPtr output =
6170         (inDefaultBlock) ? (ResourceDefinition::Node::SharedPtr(
6171                                new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_OUT))) :
6172                            (parentStructure);
6173     const glu::ShaderType lastStage = getShaderMaskLastStage(presentShadersMask);
6174 
6175     const bool inBlockArray = true == deStringEqual("block_array", targetGroup->getName());
6176 
6177     if (lastStage == glu::SHADERTYPE_VERTEX || lastStage == glu::SHADERTYPE_GEOMETRY ||
6178         lastStage == glu::SHADERTYPE_TESSELLATION_EVALUATION || !inDefaultBlock)
6179     {
6180         // .var
6181         {
6182             const ResourceDefinition::Node::SharedPtr variable(
6183                 new ResourceDefinition::Variable(output, glu::TYPE_FLOAT_VEC4));
6184             targetGroup->addChild(new ResourceTestCase(
6185                 context, variable,
6186                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
6187         }
6188         // .var_explicit_location
6189         if (!inBlockArray)
6190         {
6191             const ResourceDefinition::Node::SharedPtr layout(
6192                 new ResourceDefinition::LayoutQualifier(output, glu::Layout(2)));
6193             const ResourceDefinition::Node::SharedPtr variable(
6194                 new ResourceDefinition::Variable(layout, glu::TYPE_FLOAT_VEC4));
6195             targetGroup->addChild(new ResourceTestCase(
6196                 context, variable,
6197                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6198                 "var_explicit_location"));
6199         }
6200         // .var_struct
6201         {
6202             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(output));
6203             const ResourceDefinition::Node::SharedPtr variable(
6204                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
6205             targetGroup->addChild(new ResourceTestCase(
6206                 context, variable,
6207                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6208                 "var_struct"));
6209         }
6210         // .var_struct_explicit_location
6211         if (!inBlockArray)
6212         {
6213             const ResourceDefinition::Node::SharedPtr layout(
6214                 new ResourceDefinition::LayoutQualifier(output, glu::Layout(2)));
6215             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(layout));
6216             const ResourceDefinition::Node::SharedPtr variable(
6217                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
6218             targetGroup->addChild(new ResourceTestCase(
6219                 context, variable,
6220                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6221                 "var_struct_explicit_location"));
6222         }
6223         // .var_array
6224         {
6225             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(output));
6226             const ResourceDefinition::Node::SharedPtr variable(
6227                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6228             targetGroup->addChild(new ResourceTestCase(
6229                 context, variable,
6230                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6231                 "var_array"));
6232         }
6233         // .var_array_explicit_location
6234         if (!inBlockArray)
6235         {
6236             const ResourceDefinition::Node::SharedPtr layout(
6237                 new ResourceDefinition::LayoutQualifier(output, glu::Layout(2)));
6238             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(layout));
6239             const ResourceDefinition::Node::SharedPtr variable(
6240                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6241             targetGroup->addChild(new ResourceTestCase(
6242                 context, variable,
6243                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6244                 "var_array_explicit_location"));
6245         }
6246     }
6247     else if (lastStage == glu::SHADERTYPE_FRAGMENT)
6248     {
6249         // .var
6250         {
6251             const ResourceDefinition::Node::SharedPtr variable(
6252                 new ResourceDefinition::Variable(output, glu::TYPE_FLOAT_VEC4));
6253             targetGroup->addChild(new ResourceTestCase(
6254                 context, variable,
6255                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
6256         }
6257         // .var_explicit_location
6258         if (!inBlockArray)
6259         {
6260             const ResourceDefinition::Node::SharedPtr layout(
6261                 new ResourceDefinition::LayoutQualifier(output, glu::Layout(2)));
6262             const ResourceDefinition::Node::SharedPtr variable(
6263                 new ResourceDefinition::Variable(layout, glu::TYPE_FLOAT_VEC4));
6264             targetGroup->addChild(new ResourceTestCase(
6265                 context, variable,
6266                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6267                 "var_explicit_location"));
6268         }
6269         // .var_array
6270         {
6271             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(output));
6272             const ResourceDefinition::Node::SharedPtr variable(
6273                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6274             targetGroup->addChild(new ResourceTestCase(
6275                 context, variable,
6276                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6277                 "var_array"));
6278         }
6279         // .var_array_explicit_location
6280         if (!inBlockArray)
6281         {
6282             const ResourceDefinition::Node::SharedPtr layout(
6283                 new ResourceDefinition::LayoutQualifier(output, glu::Layout(1)));
6284             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(layout));
6285             const ResourceDefinition::Node::SharedPtr variable(
6286                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6287             targetGroup->addChild(new ResourceTestCase(
6288                 context, variable,
6289                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6290                 "var_array_explicit_location"));
6291         }
6292     }
6293     else if (lastStage == glu::SHADERTYPE_TESSELLATION_CONTROL)
6294     {
6295         // arrayed interface
6296         const ResourceDefinition::Node::SharedPtr patchOutput(
6297             new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_PATCH_OUT));
6298 
6299         // .var
6300         {
6301             const ResourceDefinition::Node::SharedPtr arrayElem(
6302                 new ResourceDefinition::ArrayElement(output, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6303             const ResourceDefinition::Node::SharedPtr variable(
6304                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6305             targetGroup->addChild(new ResourceTestCase(
6306                 context, variable,
6307                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION), "var"));
6308         }
6309         // .var_explicit_location
6310         {
6311             const ResourceDefinition::Node::SharedPtr layout(
6312                 new ResourceDefinition::LayoutQualifier(output, glu::Layout(2)));
6313             const ResourceDefinition::Node::SharedPtr arrayElem(
6314                 new ResourceDefinition::ArrayElement(layout, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6315             const ResourceDefinition::Node::SharedPtr variable(
6316                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6317             targetGroup->addChild(new ResourceTestCase(
6318                 context, variable,
6319                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6320                 "var_explicit_location"));
6321         }
6322         // extension forbids use arrays of structs
6323         // extension forbids use array of arrays
6324 
6325         // .patch_var
6326         {
6327             const ResourceDefinition::Node::SharedPtr variable(
6328                 new ResourceDefinition::Variable(patchOutput, glu::TYPE_FLOAT_VEC4));
6329             targetGroup->addChild(new ResourceTestCase(
6330                 context, variable,
6331                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6332                 "patch_var"));
6333         }
6334         // .patch_var_explicit_location
6335         {
6336             const ResourceDefinition::Node::SharedPtr layout(
6337                 new ResourceDefinition::LayoutQualifier(patchOutput, glu::Layout(2)));
6338             const ResourceDefinition::Node::SharedPtr variable(
6339                 new ResourceDefinition::Variable(layout, glu::TYPE_FLOAT_VEC4));
6340             targetGroup->addChild(new ResourceTestCase(
6341                 context, variable,
6342                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6343                 "patch_var_explicit_location"));
6344         }
6345         // .patch_var_struct
6346         {
6347             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(patchOutput));
6348             const ResourceDefinition::Node::SharedPtr variable(
6349                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
6350             targetGroup->addChild(new ResourceTestCase(
6351                 context, variable,
6352                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6353                 "patch_var_struct"));
6354         }
6355         // .patch_var_struct_explicit_location
6356         {
6357             const ResourceDefinition::Node::SharedPtr layout(
6358                 new ResourceDefinition::LayoutQualifier(patchOutput, glu::Layout(2)));
6359             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(layout));
6360             const ResourceDefinition::Node::SharedPtr variable(
6361                 new ResourceDefinition::Variable(structMbr, glu::TYPE_FLOAT_VEC4));
6362             targetGroup->addChild(new ResourceTestCase(
6363                 context, variable,
6364                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6365                 "patch_var_struct_explicit_location"));
6366         }
6367         // .patch_var_array
6368         {
6369             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(patchOutput));
6370             const ResourceDefinition::Node::SharedPtr variable(
6371                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6372             targetGroup->addChild(new ResourceTestCase(
6373                 context, variable,
6374                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6375                 "patch_var_array"));
6376         }
6377         // .patch_var_array_explicit_location
6378         {
6379             const ResourceDefinition::Node::SharedPtr layout(
6380                 new ResourceDefinition::LayoutQualifier(patchOutput, glu::Layout(2)));
6381             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(layout));
6382             const ResourceDefinition::Node::SharedPtr variable(
6383                 new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6384             targetGroup->addChild(new ResourceTestCase(
6385                 context, variable,
6386                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_PROGRAM_OUTPUT, PROGRAMRESOURCEPROP_LOCATION),
6387                 "patch_var_array_explicit_location"));
6388         }
6389     }
6390     else if (lastStage == glu::SHADERTYPE_COMPUTE)
6391     {
6392         // nada
6393     }
6394     else
6395         DE_ASSERT(false);
6396 }
6397 
generateProgramInputOutputReferencedByCases(Context & context,tcu::TestCaseGroup * targetGroup,glu::Storage storage)6398 static void generateProgramInputOutputReferencedByCases(Context &context, tcu::TestCaseGroup *targetGroup,
6399                                                         glu::Storage storage)
6400 {
6401     // all whole pipelines
6402     targetGroup->addChild(
6403         new ProgramInputOutputReferencedByCase(context, "referenced_by_vertex_fragment", "", storage,
6404                                                ProgramInputOutputReferencedByCase::CASE_VERTEX_FRAGMENT));
6405     targetGroup->addChild(
6406         new ProgramInputOutputReferencedByCase(context, "referenced_by_vertex_tess_fragment", "", storage,
6407                                                ProgramInputOutputReferencedByCase::CASE_VERTEX_TESS_FRAGMENT));
6408     targetGroup->addChild(
6409         new ProgramInputOutputReferencedByCase(context, "referenced_by_vertex_geo_fragment", "", storage,
6410                                                ProgramInputOutputReferencedByCase::CASE_VERTEX_GEO_FRAGMENT));
6411     targetGroup->addChild(
6412         new ProgramInputOutputReferencedByCase(context, "referenced_by_vertex_tess_geo_fragment", "", storage,
6413                                                ProgramInputOutputReferencedByCase::CASE_VERTEX_TESS_GEO_FRAGMENT));
6414 
6415     // all partial pipelines
6416     targetGroup->addChild(
6417         new ProgramInputOutputReferencedByCase(context, "referenced_by_separable_vertex", "", storage,
6418                                                ProgramInputOutputReferencedByCase::CASE_SEPARABLE_VERTEX));
6419     targetGroup->addChild(
6420         new ProgramInputOutputReferencedByCase(context, "referenced_by_separable_fragment", "", storage,
6421                                                ProgramInputOutputReferencedByCase::CASE_SEPARABLE_FRAGMENT));
6422     targetGroup->addChild(
6423         new ProgramInputOutputReferencedByCase(context, "referenced_by_separable_geometry", "", storage,
6424                                                ProgramInputOutputReferencedByCase::CASE_SEPARABLE_GEOMETRY));
6425     targetGroup->addChild(
6426         new ProgramInputOutputReferencedByCase(context, "referenced_by_separable_tess_eval", "", storage,
6427                                                ProgramInputOutputReferencedByCase::CASE_SEPARABLE_TESS_EVAL));
6428     targetGroup->addChild(
6429         new ProgramInputOutputReferencedByCase(context, "referenced_by_separable_tess_ctrl", "", storage,
6430                                                ProgramInputOutputReferencedByCase::CASE_SEPARABLE_TESS_CTRL));
6431 
6432     // patch
6433     if (storage == glu::STORAGE_IN)
6434         targetGroup->addChild(new ProgramInputOutputReferencedByCase(
6435             context, "referenced_by_separable_tess_eval_patch_in", "", glu::STORAGE_PATCH_IN,
6436             ProgramInputOutputReferencedByCase::CASE_SEPARABLE_TESS_EVAL));
6437     else if (storage == glu::STORAGE_OUT)
6438         targetGroup->addChild(new ProgramInputOutputReferencedByCase(
6439             context, "referenced_by_separable_tess_ctrl_patch_out", "", glu::STORAGE_PATCH_OUT,
6440             ProgramInputOutputReferencedByCase::CASE_SEPARABLE_TESS_CTRL));
6441     else
6442         DE_ASSERT(false);
6443 }
6444 
6445 template <ProgramInterface interface>
generateProgramInputOutputTypeBasicTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,bool allowMatrixCases,int expandLevel)6446 static void generateProgramInputOutputTypeBasicTypeCases(Context &context,
6447                                                          const ResourceDefinition::Node::SharedPtr &parentStructure,
6448                                                          tcu::TestCaseGroup *targetGroup, bool allowMatrixCases,
6449                                                          int expandLevel)
6450 {
6451     static const struct
6452     {
6453         glu::DataType type;
6454         bool isMatrix;
6455         int level;
6456     } variableTypes[] = {
6457         {glu::TYPE_FLOAT, false, 0},       {glu::TYPE_INT, false, 1},         {glu::TYPE_UINT, false, 1},
6458         {glu::TYPE_FLOAT_VEC2, false, 2},  {glu::TYPE_FLOAT_VEC3, false, 1},  {glu::TYPE_FLOAT_VEC4, false, 2},
6459         {glu::TYPE_INT_VEC2, false, 0},    {glu::TYPE_INT_VEC3, false, 2},    {glu::TYPE_INT_VEC4, false, 2},
6460         {glu::TYPE_UINT_VEC2, false, 2},   {glu::TYPE_UINT_VEC3, false, 2},   {glu::TYPE_UINT_VEC4, false, 0},
6461         {glu::TYPE_FLOAT_MAT2, true, 2},   {glu::TYPE_FLOAT_MAT2X3, true, 2}, {glu::TYPE_FLOAT_MAT2X4, true, 2},
6462         {glu::TYPE_FLOAT_MAT3X2, true, 0}, {glu::TYPE_FLOAT_MAT3, true, 2},   {glu::TYPE_FLOAT_MAT3X4, true, 2},
6463         {glu::TYPE_FLOAT_MAT4X2, true, 2}, {glu::TYPE_FLOAT_MAT4X3, true, 2}, {glu::TYPE_FLOAT_MAT4, true, 2},
6464     };
6465 
6466     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
6467     {
6468         if (!allowMatrixCases && variableTypes[ndx].isMatrix)
6469             continue;
6470 
6471         if (variableTypes[ndx].level <= expandLevel)
6472         {
6473             const ResourceDefinition::Node::SharedPtr variable(
6474                 new ResourceDefinition::Variable(parentStructure, variableTypes[ndx].type));
6475             targetGroup->addChild(new ResourceTestCase(
6476                 context, variable, ProgramResourceQueryTestTarget(interface, PROGRAMRESOURCEPROP_TYPE)));
6477         }
6478     }
6479 }
6480 
generateProgramInputTypeBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)6481 static void generateProgramInputTypeBlockContents(Context &context,
6482                                                   const ResourceDefinition::Node::SharedPtr &parentStructure,
6483                                                   tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
6484                                                   bool isGL45)
6485 {
6486     DE_UNREF(isGL45);
6487     const bool inDefaultBlock = parentStructure->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK;
6488     const ResourceDefinition::Node::SharedPtr input =
6489         (inDefaultBlock) ? (ResourceDefinition::Node::SharedPtr(
6490                                new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_IN))) :
6491                            (parentStructure);
6492     const glu::ShaderType firstStage = getShaderMaskFirstStage(presentShadersMask);
6493     const int interfaceBlockExpansionReducement =
6494         (!inDefaultBlock) ? (1) : (0); // lesser expansions on block members to keep test counts reasonable
6495 
6496     if (firstStage == glu::SHADERTYPE_VERTEX)
6497     {
6498         // Only basic types (and no booleans)
6499         generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(
6500             context, input, targetGroup, true, 2 - interfaceBlockExpansionReducement);
6501     }
6502     else if (firstStage == glu::SHADERTYPE_FRAGMENT || !inDefaultBlock)
6503     {
6504         const ResourceDefinition::Node::SharedPtr flatShading(
6505             new ResourceDefinition::InterpolationQualifier(input, glu::INTERPOLATION_FLAT));
6506 
6507         // Only basic types, arrays of basic types, struct of basic types (and no booleans)
6508         {
6509             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic types");
6510             targetGroup->addChild(blockGroup);
6511             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(
6512                 context, flatShading, blockGroup, true, 2 - interfaceBlockExpansionReducement);
6513         }
6514         {
6515             const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(flatShading));
6516             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "array", "Array types");
6517 
6518             targetGroup->addChild(blockGroup);
6519             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(
6520                 context, arrayElement, blockGroup, true, 2 - interfaceBlockExpansionReducement);
6521         }
6522         {
6523             const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(flatShading));
6524             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "struct", "Struct types");
6525 
6526             targetGroup->addChild(blockGroup);
6527             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(
6528                 context, structMember, blockGroup, true, 2 - interfaceBlockExpansionReducement);
6529         }
6530     }
6531     else if (firstStage == glu::SHADERTYPE_TESSELLATION_CONTROL || firstStage == glu::SHADERTYPE_GEOMETRY)
6532     {
6533         // arrayed interface
6534 
6535         // Only basic types (and no booleans)
6536         const ResourceDefinition::Node::SharedPtr arrayElement(
6537             new ResourceDefinition::ArrayElement(input, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6538         generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(context, arrayElement, targetGroup,
6539                                                                                      true, 2);
6540     }
6541     else if (firstStage == glu::SHADERTYPE_TESSELLATION_EVALUATION)
6542     {
6543         // arrayed interface
6544         const ResourceDefinition::Node::SharedPtr patchInput(
6545             new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_PATCH_IN));
6546 
6547         // .var
6548         {
6549             const ResourceDefinition::Node::SharedPtr arrayElem(
6550                 new ResourceDefinition::ArrayElement(input, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6551             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic types");
6552 
6553             targetGroup->addChild(blockGroup);
6554             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(context, arrayElem, blockGroup,
6555                                                                                          true, 2);
6556         }
6557         // extension forbids use arrays of structs
6558         // extension forbids use arrays of arrays
6559 
6560         // .patch_var
6561         {
6562             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "patch_var", "Basic types, per-patch");
6563 
6564             targetGroup->addChild(blockGroup);
6565             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(context, patchInput,
6566                                                                                          blockGroup, true, 1);
6567         }
6568         // .patch_var_struct
6569         {
6570             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(patchInput));
6571             tcu::TestCaseGroup *const blockGroup =
6572                 new TestCaseGroup(context, "patch_var_struct", "Struct types, per-patch");
6573 
6574             targetGroup->addChild(blockGroup);
6575             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(context, structMbr, blockGroup,
6576                                                                                          true, 1);
6577         }
6578         // .patch_var_array
6579         {
6580             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(patchInput));
6581             tcu::TestCaseGroup *const blockGroup =
6582                 new TestCaseGroup(context, "patch_var_array", "Array types, per-patch");
6583 
6584             targetGroup->addChild(blockGroup);
6585             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_INPUT>(context, arrayElem, blockGroup,
6586                                                                                          true, 1);
6587         }
6588     }
6589     else if (firstStage == glu::SHADERTYPE_COMPUTE)
6590     {
6591         // nada
6592     }
6593     else
6594         DE_ASSERT(false);
6595 }
6596 
generateProgramOutputTypeBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,uint32_t presentShadersMask,bool isGL45)6597 static void generateProgramOutputTypeBlockContents(Context &context,
6598                                                    const ResourceDefinition::Node::SharedPtr &parentStructure,
6599                                                    tcu::TestCaseGroup *targetGroup, uint32_t presentShadersMask,
6600                                                    bool isGL45)
6601 {
6602     DE_UNREF(isGL45);
6603     const bool inDefaultBlock = parentStructure->getType() == ResourceDefinition::Node::TYPE_DEFAULT_BLOCK;
6604     const ResourceDefinition::Node::SharedPtr output =
6605         (inDefaultBlock) ? (ResourceDefinition::Node::SharedPtr(
6606                                new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_OUT))) :
6607                            (parentStructure);
6608     const glu::ShaderType lastStage = getShaderMaskLastStage(presentShadersMask);
6609     const int interfaceBlockExpansionReducement =
6610         (!inDefaultBlock) ? (1) : (0); // lesser expansions on block members to keep test counts reasonable
6611 
6612     if (lastStage == glu::SHADERTYPE_VERTEX || lastStage == glu::SHADERTYPE_GEOMETRY ||
6613         lastStage == glu::SHADERTYPE_TESSELLATION_EVALUATION || !inDefaultBlock)
6614     {
6615         const ResourceDefinition::Node::SharedPtr flatShading(
6616             new ResourceDefinition::InterpolationQualifier(output, glu::INTERPOLATION_FLAT));
6617 
6618         // Only basic types, arrays of basic types, struct of basic types (and no booleans)
6619         {
6620             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic types");
6621             targetGroup->addChild(blockGroup);
6622             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(
6623                 context, flatShading, blockGroup, true, 2 - interfaceBlockExpansionReducement);
6624         }
6625         {
6626             const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(flatShading));
6627             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "array", "Array types");
6628             const int typeExpansionReducement =
6629                 (lastStage != glu::SHADERTYPE_VERTEX) ? (1) : (0); // lesser expansions on other stages
6630             const int expansionLevel = 2 - interfaceBlockExpansionReducement - typeExpansionReducement;
6631 
6632             targetGroup->addChild(blockGroup);
6633             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(
6634                 context, arrayElement, blockGroup, true, expansionLevel);
6635         }
6636         {
6637             const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(flatShading));
6638             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "struct", "Struct types");
6639             const int typeExpansionReducement =
6640                 (lastStage != glu::SHADERTYPE_VERTEX) ? (1) : (0); // lesser expansions on other stages
6641             const int expansionLevel = 2 - interfaceBlockExpansionReducement - typeExpansionReducement;
6642 
6643             targetGroup->addChild(blockGroup);
6644             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(
6645                 context, structMember, blockGroup, true, expansionLevel);
6646         }
6647     }
6648     else if (lastStage == glu::SHADERTYPE_FRAGMENT)
6649     {
6650         // only basic type and basic type array (and no booleans or matrices)
6651         {
6652             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic types");
6653             targetGroup->addChild(blockGroup);
6654             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(context, output, blockGroup,
6655                                                                                           false, 2);
6656         }
6657         {
6658             const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(output));
6659             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "array", "Array types");
6660 
6661             targetGroup->addChild(blockGroup);
6662             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(context, arrayElement,
6663                                                                                           blockGroup, false, 2);
6664         }
6665     }
6666     else if (lastStage == glu::SHADERTYPE_TESSELLATION_CONTROL)
6667     {
6668         // arrayed interface
6669         const ResourceDefinition::Node::SharedPtr patchOutput(
6670             new ResourceDefinition::StorageQualifier(parentStructure, glu::STORAGE_PATCH_OUT));
6671 
6672         // .var
6673         {
6674             const ResourceDefinition::Node::SharedPtr arrayElem(
6675                 new ResourceDefinition::ArrayElement(output, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
6676             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic types");
6677 
6678             targetGroup->addChild(blockGroup);
6679             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(context, arrayElem,
6680                                                                                           blockGroup, true, 2);
6681         }
6682         // extension forbids use arrays of structs
6683         // extension forbids use arrays of arrays
6684 
6685         // .patch_var
6686         {
6687             tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "patch_var", "Basic types, per-patch");
6688 
6689             targetGroup->addChild(blockGroup);
6690             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(context, patchOutput,
6691                                                                                           blockGroup, true, 1);
6692         }
6693         // .patch_var_struct
6694         {
6695             const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(patchOutput));
6696             tcu::TestCaseGroup *const blockGroup =
6697                 new TestCaseGroup(context, "patch_var_struct", "Struct types, per-patch");
6698 
6699             targetGroup->addChild(blockGroup);
6700             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(context, structMbr,
6701                                                                                           blockGroup, true, 1);
6702         }
6703         // .patch_var_array
6704         {
6705             const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(patchOutput));
6706             tcu::TestCaseGroup *const blockGroup =
6707                 new TestCaseGroup(context, "patch_var_array", "Array types, per-patch");
6708 
6709             targetGroup->addChild(blockGroup);
6710             generateProgramInputOutputTypeBasicTypeCases<PROGRAMINTERFACE_PROGRAM_OUTPUT>(context, arrayElem,
6711                                                                                           blockGroup, true, 1);
6712         }
6713     }
6714     else if (lastStage == glu::SHADERTYPE_COMPUTE)
6715     {
6716         // nada
6717     }
6718     else
6719         DE_ASSERT(false);
6720 }
6721 
6722 class ProgramInputTestGroup : public TestCaseGroup
6723 {
6724 public:
6725     ProgramInputTestGroup(Context &context, bool is_GL45);
6726     void init(void);
6727 
6728 private:
6729     bool m_isGL45;
6730 };
6731 
ProgramInputTestGroup(Context & context,bool is_GL45)6732 ProgramInputTestGroup::ProgramInputTestGroup(Context &context, bool is_GL45)
6733     : TestCaseGroup(context, "program_input", "Program input")
6734     , m_isGL45(is_GL45)
6735 {
6736 }
6737 
init(void)6738 void ProgramInputTestGroup::init(void)
6739 {
6740     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
6741 
6742     // .resource_list
6743     {
6744         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "resource_list", "Resource list");
6745         addChild(blockGroup);
6746         generateProgramInputOutputShaderCaseBlocks(m_context, blockGroup, glslVersion, true, true, m_isGL45,
6747                                                    generateProgramInputResourceListBlockContents);
6748     }
6749 
6750     // .array_size
6751     {
6752         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "array_size", "Array size");
6753         addChild(blockGroup);
6754         generateProgramInputOutputShaderCaseBlocks(
6755             m_context, blockGroup, glslVersion, false, true, m_isGL45,
6756             generateProgramInputBasicBlockContents<PROGRAMRESOURCEPROP_ARRAY_SIZE>);
6757     }
6758 
6759     // .location
6760     {
6761         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "location", "Location");
6762         addChild(blockGroup);
6763         generateProgramInputOutputShaderCaseBlocks(m_context, blockGroup, glslVersion, false, true, m_isGL45,
6764                                                    generateProgramInputLocationBlockContents);
6765     }
6766 
6767     // .name_length
6768     {
6769         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "name_length", "Name length");
6770         addChild(blockGroup);
6771         generateProgramInputOutputShaderCaseBlocks(
6772             m_context, blockGroup, glslVersion, false, true, m_isGL45,
6773             generateProgramInputBasicBlockContents<PROGRAMRESOURCEPROP_NAME_LENGTH>);
6774     }
6775 
6776     // .referenced_by
6777     {
6778         tcu::TestCaseGroup *const blockGroup =
6779             new tcu::TestCaseGroup(m_testCtx, "referenced_by", "Reference by shader");
6780         addChild(blockGroup);
6781         generateProgramInputOutputReferencedByCases(m_context, blockGroup, glu::STORAGE_IN);
6782     }
6783 
6784     // .type
6785     {
6786         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "type", "Type");
6787         addChild(blockGroup);
6788         generateProgramInputOutputShaderCaseBlocks(m_context, blockGroup, glslVersion, false, true, m_isGL45,
6789                                                    generateProgramInputTypeBlockContents);
6790     }
6791 
6792     // .is_per_patch
6793     {
6794         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "is_per_patch", "Is per patch");
6795         addChild(blockGroup);
6796         generateProgramInputOutputShaderCaseBlocks(
6797             m_context, blockGroup, glslVersion, false, true, m_isGL45,
6798             generateProgramInputBasicBlockContents<PROGRAMRESOURCEPROP_IS_PER_PATCH>);
6799     }
6800 }
6801 
6802 class ProgramOutputTestGroup : public TestCaseGroup
6803 {
6804 public:
6805     ProgramOutputTestGroup(Context &context, bool is_GL45);
6806     void init(void);
6807 
6808 private:
6809     bool m_isGL45;
6810 };
6811 
ProgramOutputTestGroup(Context & context,bool is_GL45)6812 ProgramOutputTestGroup::ProgramOutputTestGroup(Context &context, bool is_GL45)
6813     : TestCaseGroup(context, "program_output", "Program output")
6814     , m_isGL45(is_GL45)
6815 {
6816 }
6817 
init(void)6818 void ProgramOutputTestGroup::init(void)
6819 {
6820     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
6821 
6822     // .resource_list
6823     {
6824         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "resource_list", "Resource list");
6825         addChild(blockGroup);
6826         generateProgramInputOutputShaderCaseBlocks(m_context, blockGroup, glslVersion, true, false, m_isGL45,
6827                                                    generateProgramOutputResourceListBlockContents);
6828     }
6829 
6830     // .array_size
6831     {
6832         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "array_size", "Array size");
6833         addChild(blockGroup);
6834         generateProgramInputOutputShaderCaseBlocks(
6835             m_context, blockGroup, glslVersion, false, false, m_isGL45,
6836             generateProgramOutputBasicBlockContents<PROGRAMRESOURCEPROP_ARRAY_SIZE>);
6837     }
6838 
6839     // .location
6840     {
6841         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "location", "Location");
6842         addChild(blockGroup);
6843         generateProgramInputOutputShaderCaseBlocks(m_context, blockGroup, glslVersion, false, false, m_isGL45,
6844                                                    generateProgramOutputLocationBlockContents);
6845     }
6846 
6847     // .name_length
6848     {
6849         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "name_length", "Name length");
6850         addChild(blockGroup);
6851         generateProgramInputOutputShaderCaseBlocks(
6852             m_context, blockGroup, glslVersion, false, false, m_isGL45,
6853             generateProgramOutputBasicBlockContents<PROGRAMRESOURCEPROP_NAME_LENGTH>);
6854     }
6855 
6856     // .referenced_by
6857     {
6858         tcu::TestCaseGroup *const blockGroup =
6859             new tcu::TestCaseGroup(m_testCtx, "referenced_by", "Reference by shader");
6860         addChild(blockGroup);
6861         generateProgramInputOutputReferencedByCases(m_context, blockGroup, glu::STORAGE_OUT);
6862     }
6863 
6864     // .type
6865     {
6866         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "type", "Type");
6867         addChild(blockGroup);
6868         generateProgramInputOutputShaderCaseBlocks(m_context, blockGroup, glslVersion, false, false, m_isGL45,
6869                                                    generateProgramOutputTypeBlockContents);
6870     }
6871 
6872     // .is_per_patch
6873     {
6874         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(m_testCtx, "is_per_patch", "Is per patch");
6875         addChild(blockGroup);
6876         generateProgramInputOutputShaderCaseBlocks(
6877             m_context, blockGroup, glslVersion, false, false, m_isGL45,
6878             generateProgramOutputBasicBlockContents<PROGRAMRESOURCEPROP_IS_PER_PATCH>);
6879     }
6880 }
6881 
generateTransformFeedbackShaderCaseBlocks(Context & context,tcu::TestCaseGroup * targetGroup,glu::GLSLVersion glslVersion,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup *,bool))6882 static void generateTransformFeedbackShaderCaseBlocks(
6883     Context &context, tcu::TestCaseGroup *targetGroup, glu::GLSLVersion glslVersion,
6884     void (*blockContentGenerator)(Context &, const ResourceDefinition::Node::SharedPtr &, tcu::TestCaseGroup *, bool))
6885 {
6886     static const struct
6887     {
6888         const char *name;
6889         uint32_t stageBits;
6890         uint32_t lastStageBit;
6891         bool reducedSet;
6892     } pipelines[] = {
6893         {"vertex_fragment", (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT),
6894          (1 << glu::SHADERTYPE_VERTEX), false},
6895         {"vertex_tess_fragment",
6896          (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) | (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) |
6897              (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION),
6898          (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION), true},
6899         {"vertex_geo_fragment",
6900          (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) | (1 << glu::SHADERTYPE_GEOMETRY),
6901          (1 << glu::SHADERTYPE_GEOMETRY), true},
6902         {"vertex_tess_geo_fragment",
6903          (1 << glu::SHADERTYPE_VERTEX) | (1 << glu::SHADERTYPE_FRAGMENT) | (1 << glu::SHADERTYPE_TESSELLATION_CONTROL) |
6904              (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION) | (1 << glu::SHADERTYPE_GEOMETRY),
6905          (1 << glu::SHADERTYPE_GEOMETRY), true},
6906     };
6907     static const struct
6908     {
6909         const char *name;
6910         glu::ShaderType stage;
6911         bool reducedSet;
6912     } singleStageCases[] = {
6913         {"separable_vertex", glu::SHADERTYPE_VERTEX, false},
6914         {"separable_tess_eval", glu::SHADERTYPE_TESSELLATION_EVALUATION, true},
6915         {"separable_geometry", glu::SHADERTYPE_GEOMETRY, true},
6916     };
6917 
6918     // monolithic pipeline
6919     for (int pipelineNdx = 0; pipelineNdx < DE_LENGTH_OF_ARRAY(pipelines); ++pipelineNdx)
6920     {
6921         TestCaseGroup *const blockGroup = new TestCaseGroup(context, pipelines[pipelineNdx].name, "");
6922         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
6923         const ResourceDefinition::Node::SharedPtr shaderSet(new ResourceDefinition::ShaderSet(
6924             program, glslVersion, pipelines[pipelineNdx].stageBits, pipelines[pipelineNdx].lastStageBit));
6925 
6926         targetGroup->addChild(blockGroup);
6927         blockContentGenerator(context, shaderSet, blockGroup, pipelines[pipelineNdx].reducedSet);
6928     }
6929 
6930     // separable pipeline
6931     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleStageCases); ++ndx)
6932     {
6933         TestCaseGroup *const blockGroup = new TestCaseGroup(context, singleStageCases[ndx].name, "");
6934         const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program(true));
6935         const ResourceDefinition::Node::SharedPtr shader(
6936             new ResourceDefinition::Shader(program, singleStageCases[ndx].stage, glslVersion));
6937 
6938         targetGroup->addChild(blockGroup);
6939         blockContentGenerator(context, shader, blockGroup, singleStageCases[ndx].reducedSet);
6940     }
6941 }
6942 
generateTransformFeedbackResourceListBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,bool reducedSet)6943 static void generateTransformFeedbackResourceListBlockContents(
6944     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *targetGroup,
6945     bool reducedSet)
6946 {
6947     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
6948     const ResourceDefinition::Node::SharedPtr output(
6949         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_OUT));
6950 
6951     DE_UNREF(reducedSet);
6952 
6953     // .builtin_gl_position
6954     {
6955         const ResourceDefinition::Node::SharedPtr xfbTarget(
6956             new ResourceDefinition::TransformFeedbackTarget(defaultBlock, "gl_Position"));
6957         targetGroup->addChild(new FeedbackResourceListTestCase(context, xfbTarget, "builtin_gl_position"));
6958     }
6959     // .default_block_basic_type
6960     {
6961         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(output));
6962         const ResourceDefinition::Node::SharedPtr variable(
6963             new ResourceDefinition::Variable(xfbTarget, glu::TYPE_FLOAT_VEC4));
6964         targetGroup->addChild(new FeedbackResourceListTestCase(context, variable, "default_block_basic_type"));
6965     }
6966     // .default_block_struct_member
6967     {
6968         const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(output));
6969         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(structMbr));
6970         const ResourceDefinition::Node::SharedPtr variable(
6971             new ResourceDefinition::Variable(xfbTarget, glu::TYPE_FLOAT_VEC4));
6972         targetGroup->addChild(new FeedbackResourceListTestCase(context, variable, "default_block_struct_member"));
6973     }
6974     // .default_block_array
6975     {
6976         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(output));
6977         const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(xfbTarget));
6978         const ResourceDefinition::Node::SharedPtr variable(
6979             new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
6980         targetGroup->addChild(new FeedbackResourceListTestCase(context, variable, "default_block_array"));
6981     }
6982     // .default_block_array_element
6983     {
6984         const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(output));
6985         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(arrayElem));
6986         const ResourceDefinition::Node::SharedPtr variable(
6987             new ResourceDefinition::Variable(xfbTarget, glu::TYPE_FLOAT_VEC4));
6988         targetGroup->addChild(new FeedbackResourceListTestCase(context, variable, "default_block_array_element"));
6989     }
6990 }
6991 
6992 template <ProgramResourcePropFlags TargetProp>
generateTransformFeedbackVariableBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,bool reducedSet)6993 static void generateTransformFeedbackVariableBlockContents(Context &context,
6994                                                            const ResourceDefinition::Node::SharedPtr &parentStructure,
6995                                                            tcu::TestCaseGroup *targetGroup, bool reducedSet)
6996 {
6997     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
6998     const ResourceDefinition::Node::SharedPtr output(
6999         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_OUT));
7000 
7001     DE_UNREF(reducedSet);
7002 
7003     // .builtin_gl_position
7004     {
7005         const ResourceDefinition::Node::SharedPtr xfbTarget(
7006             new ResourceDefinition::TransformFeedbackTarget(defaultBlock, "gl_Position"));
7007         targetGroup->addChild(new ResourceTestCase(
7008             context, xfbTarget, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, TargetProp),
7009             "builtin_gl_position"));
7010     }
7011     // .default_block_basic_type
7012     {
7013         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(output));
7014         const ResourceDefinition::Node::SharedPtr variable(
7015             new ResourceDefinition::Variable(xfbTarget, glu::TYPE_FLOAT_VEC4));
7016         targetGroup->addChild(new ResourceTestCase(
7017             context, variable, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, TargetProp),
7018             "default_block_basic_type"));
7019     }
7020     // .default_block_struct_member
7021     {
7022         const ResourceDefinition::Node::SharedPtr structMbr(new ResourceDefinition::StructMember(output));
7023         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(structMbr));
7024         const ResourceDefinition::Node::SharedPtr variable(
7025             new ResourceDefinition::Variable(xfbTarget, glu::TYPE_FLOAT_VEC4));
7026         targetGroup->addChild(new ResourceTestCase(
7027             context, variable, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, TargetProp),
7028             "default_block_struct_member"));
7029     }
7030     // .default_block_array
7031     {
7032         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(output));
7033         const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(xfbTarget));
7034         const ResourceDefinition::Node::SharedPtr variable(
7035             new ResourceDefinition::Variable(arrayElem, glu::TYPE_FLOAT_VEC4));
7036         targetGroup->addChild(new ResourceTestCase(
7037             context, variable, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, TargetProp),
7038             "default_block_array"));
7039     }
7040     // .default_block_array_element
7041     {
7042         const ResourceDefinition::Node::SharedPtr arrayElem(new ResourceDefinition::ArrayElement(output));
7043         const ResourceDefinition::Node::SharedPtr xfbTarget(new ResourceDefinition::TransformFeedbackTarget(arrayElem));
7044         const ResourceDefinition::Node::SharedPtr variable(
7045             new ResourceDefinition::Variable(xfbTarget, glu::TYPE_FLOAT_VEC4));
7046         targetGroup->addChild(new ResourceTestCase(
7047             context, variable, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, TargetProp),
7048             "default_block_array_element"));
7049     }
7050 }
7051 
generateTransformFeedbackVariableBasicTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,bool reducedSet)7052 static void generateTransformFeedbackVariableBasicTypeCases(Context &context,
7053                                                             const ResourceDefinition::Node::SharedPtr &parentStructure,
7054                                                             tcu::TestCaseGroup *targetGroup, bool reducedSet)
7055 {
7056     static const struct
7057     {
7058         glu::DataType type;
7059         bool important;
7060     } variableTypes[] = {
7061         {glu::TYPE_FLOAT, true},         {glu::TYPE_INT, true},           {glu::TYPE_UINT, true},
7062 
7063         {glu::TYPE_FLOAT_VEC2, false},   {glu::TYPE_FLOAT_VEC3, true},    {glu::TYPE_FLOAT_VEC4, false},
7064 
7065         {glu::TYPE_INT_VEC2, false},     {glu::TYPE_INT_VEC3, true},      {glu::TYPE_INT_VEC4, false},
7066 
7067         {glu::TYPE_UINT_VEC2, true},     {glu::TYPE_UINT_VEC3, false},    {glu::TYPE_UINT_VEC4, false},
7068 
7069         {glu::TYPE_FLOAT_MAT2, false},   {glu::TYPE_FLOAT_MAT2X3, false}, {glu::TYPE_FLOAT_MAT2X4, false},
7070         {glu::TYPE_FLOAT_MAT3X2, false}, {glu::TYPE_FLOAT_MAT3, false},   {glu::TYPE_FLOAT_MAT3X4, true},
7071         {glu::TYPE_FLOAT_MAT4X2, false}, {glu::TYPE_FLOAT_MAT4X3, false}, {glu::TYPE_FLOAT_MAT4, false},
7072     };
7073 
7074     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
7075     {
7076         if (variableTypes[ndx].important || !reducedSet)
7077         {
7078             const ResourceDefinition::Node::SharedPtr variable(
7079                 new ResourceDefinition::Variable(parentStructure, variableTypes[ndx].type));
7080             targetGroup->addChild(new ResourceTestCase(
7081                 context, variable,
7082                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, PROGRAMRESOURCEPROP_TYPE)));
7083         }
7084     }
7085 }
7086 
generateTransformFeedbackVariableTypeBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,bool reducedSet)7087 static void generateTransformFeedbackVariableTypeBlockContents(
7088     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *targetGroup,
7089     bool reducedSet)
7090 {
7091     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
7092     const ResourceDefinition::Node::SharedPtr output(
7093         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_OUT));
7094     const ResourceDefinition::Node::SharedPtr flatShading(
7095         new ResourceDefinition::InterpolationQualifier(output, glu::INTERPOLATION_FLAT));
7096 
7097     // Only builtins, basic types, arrays of basic types, struct of basic types (and no booleans)
7098     {
7099         const ResourceDefinition::Node::SharedPtr xfbTarget(
7100             new ResourceDefinition::TransformFeedbackTarget(defaultBlock, "gl_Position"));
7101         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "builtin", "Built-in outputs");
7102 
7103         targetGroup->addChild(blockGroup);
7104         blockGroup->addChild(new ResourceTestCase(
7105             context, xfbTarget,
7106             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING, PROGRAMRESOURCEPROP_TYPE),
7107             "gl_position"));
7108     }
7109     {
7110         const ResourceDefinition::Node::SharedPtr xfbTarget(
7111             new ResourceDefinition::TransformFeedbackTarget(flatShading));
7112         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic types");
7113 
7114         targetGroup->addChild(blockGroup);
7115         generateTransformFeedbackVariableBasicTypeCases(context, xfbTarget, blockGroup, reducedSet);
7116     }
7117     {
7118         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(flatShading));
7119         const ResourceDefinition::Node::SharedPtr xfbTarget(
7120             new ResourceDefinition::TransformFeedbackTarget(arrayElement));
7121         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "array", "Array types");
7122 
7123         targetGroup->addChild(blockGroup);
7124         generateTransformFeedbackVariableBasicTypeCases(context, xfbTarget, blockGroup, reducedSet);
7125     }
7126     {
7127         const ResourceDefinition::Node::SharedPtr xfbTarget(
7128             new ResourceDefinition::TransformFeedbackTarget(flatShading));
7129         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(xfbTarget));
7130         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "whole_array", "Whole array");
7131 
7132         targetGroup->addChild(blockGroup);
7133         generateTransformFeedbackVariableBasicTypeCases(context, arrayElement, blockGroup, reducedSet);
7134     }
7135     {
7136         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(flatShading));
7137         const ResourceDefinition::Node::SharedPtr xfbTarget(
7138             new ResourceDefinition::TransformFeedbackTarget(structMember));
7139         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "struct", "Struct types");
7140 
7141         targetGroup->addChild(blockGroup);
7142         generateTransformFeedbackVariableBasicTypeCases(context, xfbTarget, blockGroup, reducedSet);
7143     }
7144 }
7145 
7146 class TransformFeedbackVaryingTestGroup : public TestCaseGroup
7147 {
7148 public:
7149     TransformFeedbackVaryingTestGroup(Context &context);
7150     void init(void);
7151 };
7152 
TransformFeedbackVaryingTestGroup(Context & context)7153 TransformFeedbackVaryingTestGroup::TransformFeedbackVaryingTestGroup(Context &context)
7154     : TestCaseGroup(context, "transform_feedback_varying", "Transform feedback varyings")
7155 {
7156 }
7157 
init(void)7158 void TransformFeedbackVaryingTestGroup::init(void)
7159 {
7160     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
7161 
7162     // .resource_list
7163     {
7164         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "resource_list", "Resource list");
7165         addChild(blockGroup);
7166         generateTransformFeedbackShaderCaseBlocks(m_context, blockGroup, glslVersion,
7167                                                   generateTransformFeedbackResourceListBlockContents);
7168     }
7169 
7170     // .array_size
7171     {
7172         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "array_size", "Array size");
7173         addChild(blockGroup);
7174         generateTransformFeedbackShaderCaseBlocks(
7175             m_context, blockGroup, glslVersion,
7176             generateTransformFeedbackVariableBlockContents<PROGRAMRESOURCEPROP_ARRAY_SIZE>);
7177     }
7178 
7179     // .name_length
7180     {
7181         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "name_length", "Name length");
7182         addChild(blockGroup);
7183         generateTransformFeedbackShaderCaseBlocks(
7184             m_context, blockGroup, glslVersion,
7185             generateTransformFeedbackVariableBlockContents<PROGRAMRESOURCEPROP_NAME_LENGTH>);
7186     }
7187 
7188     // .type
7189     {
7190         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "type", "Type");
7191         addChild(blockGroup);
7192         generateTransformFeedbackShaderCaseBlocks(m_context, blockGroup, glslVersion,
7193                                                   generateTransformFeedbackVariableTypeBlockContents);
7194     }
7195 }
7196 
generateBufferVariableBufferCaseBlocks(Context & context,tcu::TestCaseGroup * targetGroup,glu::GLSLVersion glslVersion,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup *))7197 static void generateBufferVariableBufferCaseBlocks(
7198     Context &context, tcu::TestCaseGroup *targetGroup, glu::GLSLVersion glslVersion,
7199     void (*blockContentGenerator)(Context &, const ResourceDefinition::Node::SharedPtr &, tcu::TestCaseGroup *))
7200 {
7201     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
7202     const ResourceDefinition::Node::SharedPtr shader(
7203         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
7204     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
7205     const ResourceDefinition::Node::SharedPtr bufferStorage(
7206         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_BUFFER));
7207     const ResourceDefinition::Node::SharedPtr binding(
7208         new ResourceDefinition::LayoutQualifier(bufferStorage, glu::Layout(-1, 0)));
7209 
7210     // .named_block
7211     {
7212         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(binding, true));
7213         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "named_block", "Named block");
7214 
7215         targetGroup->addChild(blockGroup);
7216 
7217         blockContentGenerator(context, buffer, blockGroup);
7218     }
7219 
7220     // .unnamed_block
7221     {
7222         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(binding, false));
7223         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unnamed_block", "Unnamed block");
7224 
7225         targetGroup->addChild(blockGroup);
7226 
7227         blockContentGenerator(context, buffer, blockGroup);
7228     }
7229 
7230     // .block_array
7231     {
7232         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(binding));
7233         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(arrayElement, true));
7234         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "block_array", "Block array");
7235 
7236         targetGroup->addChild(blockGroup);
7237 
7238         blockContentGenerator(context, buffer, blockGroup);
7239     }
7240 }
7241 
generateBufferVariableResourceListBlockContentsProxy(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)7242 static void generateBufferVariableResourceListBlockContentsProxy(
7243     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *const targetGroup)
7244 {
7245     generateBufferBackedResourceListBlockContentCases(context, parentStructure, targetGroup,
7246                                                       PROGRAMINTERFACE_BUFFER_VARIABLE, 4);
7247 }
7248 
generateBufferVariableArraySizeSubCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup,ProgramResourcePropFlags targetProp,bool sizedArray,bool extendedCases)7249 static void generateBufferVariableArraySizeSubCases(Context &context,
7250                                                     const ResourceDefinition::Node::SharedPtr &parentStructure,
7251                                                     tcu::TestCaseGroup *const targetGroup,
7252                                                     ProgramResourcePropFlags targetProp, bool sizedArray,
7253                                                     bool extendedCases)
7254 {
7255     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, targetProp);
7256     tcu::TestCaseGroup *aggregateGroup;
7257 
7258     // .types
7259     if (extendedCases)
7260     {
7261         tcu::TestCaseGroup *const blockGroup = new tcu::TestCaseGroup(context.getTestContext(), "types", "Types");
7262         targetGroup->addChild(blockGroup);
7263 
7264         generateVariableCases(context, parentStructure, blockGroup, queryTarget, (sizedArray) ? (2) : (1), false);
7265     }
7266 
7267     // .aggregates
7268     if (extendedCases)
7269     {
7270         aggregateGroup = new tcu::TestCaseGroup(context.getTestContext(), "aggregates", "Aggregate types");
7271         targetGroup->addChild(aggregateGroup);
7272     }
7273     else
7274         aggregateGroup = targetGroup;
7275 
7276     // .float_*
7277     generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, aggregateGroup, queryTarget.interface,
7278                                                       glu::TYPE_FLOAT, (extendedCases && sizedArray) ? (2) : (1),
7279                                                       !extendedCases);
7280 
7281     // .bool_*
7282     generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, aggregateGroup, queryTarget.interface,
7283                                                       glu::TYPE_BOOL, (extendedCases && sizedArray) ? (1) : (0),
7284                                                       !extendedCases);
7285 
7286     // .bvec3_*
7287     generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, aggregateGroup, queryTarget.interface,
7288                                                       glu::TYPE_BOOL_VEC3, (extendedCases && sizedArray) ? (2) : (1),
7289                                                       !extendedCases);
7290 
7291     // .vec4_*
7292     generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, aggregateGroup, queryTarget.interface,
7293                                                       glu::TYPE_FLOAT_VEC4, (extendedCases && sizedArray) ? (2) : (1),
7294                                                       !extendedCases);
7295 
7296     // .ivec2_*
7297     generateBufferBackedArrayStrideTypeAggregateCases(context, parentStructure, aggregateGroup, queryTarget.interface,
7298                                                       glu::TYPE_INT_VEC2, (extendedCases && sizedArray) ? (2) : (1),
7299                                                       !extendedCases);
7300 }
7301 
7302 template <ProgramResourcePropFlags TargetProp>
generateBufferVariableArrayCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * const targetGroup)7303 static void generateBufferVariableArrayCases(Context &context,
7304                                              const ResourceDefinition::Node::SharedPtr &parentStructure,
7305                                              tcu::TestCaseGroup *const targetGroup)
7306 {
7307     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, TargetProp);
7308     const bool namedNonArrayBlock =
7309         static_cast<const ResourceDefinition::InterfaceBlock *>(parentStructure.get())->m_named &&
7310         parentStructure->getEnclosingNode()->getType() != ResourceDefinition::Node::TYPE_ARRAY_ELEMENT;
7311 
7312     // .non_array
7313     if (namedNonArrayBlock)
7314     {
7315         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "non_array", "Non-array target");
7316         targetGroup->addChild(blockGroup);
7317 
7318         generateVariableCases(context, parentStructure, blockGroup, queryTarget, 1, false);
7319     }
7320 
7321     // .sized
7322     {
7323         const ResourceDefinition::Node::SharedPtr sized(new ResourceDefinition::ArrayElement(parentStructure));
7324         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "sized", "Sized target");
7325         targetGroup->addChild(blockGroup);
7326 
7327         generateBufferVariableArraySizeSubCases(context, sized, blockGroup, TargetProp, true, namedNonArrayBlock);
7328     }
7329 
7330     // .unsized
7331     {
7332         const ResourceDefinition::Node::SharedPtr unsized(
7333             new ResourceDefinition::ArrayElement(parentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
7334         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unsized", "Unsized target");
7335         targetGroup->addChild(blockGroup);
7336 
7337         generateBufferVariableArraySizeSubCases(context, unsized, blockGroup, TargetProp, false, namedNonArrayBlock);
7338     }
7339 }
7340 
generateBufferVariableBlockIndexCases(Context & context,glu::GLSLVersion glslVersion,tcu::TestCaseGroup * const targetGroup)7341 static void generateBufferVariableBlockIndexCases(Context &context, glu::GLSLVersion glslVersion,
7342                                                   tcu::TestCaseGroup *const targetGroup)
7343 {
7344     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
7345     const ResourceDefinition::Node::SharedPtr shader(
7346         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
7347     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
7348     const ResourceDefinition::Node::SharedPtr bufferStorage(
7349         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_BUFFER));
7350     const ResourceDefinition::Node::SharedPtr binding(
7351         new ResourceDefinition::LayoutQualifier(bufferStorage, glu::Layout(-1, 0)));
7352 
7353     // .named_block
7354     {
7355         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(binding, true));
7356         const ResourceDefinition::Node::SharedPtr variable(
7357             new ResourceDefinition::Variable(buffer, glu::TYPE_FLOAT_VEC4));
7358 
7359         targetGroup->addChild(new ResourceTestCase(
7360             context, variable,
7361             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, PROGRAMRESOURCEPROP_BLOCK_INDEX),
7362             "named_block"));
7363     }
7364 
7365     // .unnamed_block
7366     {
7367         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(binding, false));
7368         const ResourceDefinition::Node::SharedPtr variable(
7369             new ResourceDefinition::Variable(buffer, glu::TYPE_FLOAT_VEC4));
7370 
7371         targetGroup->addChild(new ResourceTestCase(
7372             context, variable,
7373             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, PROGRAMRESOURCEPROP_BLOCK_INDEX),
7374             "unnamed_block"));
7375     }
7376 
7377     // .block_array
7378     {
7379         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(binding));
7380         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(arrayElement, true));
7381         const ResourceDefinition::Node::SharedPtr variable(
7382             new ResourceDefinition::Variable(buffer, glu::TYPE_FLOAT_VEC4));
7383 
7384         targetGroup->addChild(new ResourceTestCase(
7385             context, variable,
7386             ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, PROGRAMRESOURCEPROP_BLOCK_INDEX),
7387             "block_array"));
7388     }
7389 }
7390 
generateBufferVariableMatrixCaseBlocks(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion,void (* blockContentGenerator)(Context &,const ResourceDefinition::Node::SharedPtr &,tcu::TestCaseGroup *,bool))7391 static void generateBufferVariableMatrixCaseBlocks(
7392     Context &context, tcu::TestCaseGroup *const targetGroup, glu::GLSLVersion glslVersion,
7393     void (*blockContentGenerator)(Context &, const ResourceDefinition::Node::SharedPtr &, tcu::TestCaseGroup *, bool))
7394 {
7395     static const struct
7396     {
7397         const char *name;
7398         const char *description;
7399         bool namedBlock;
7400         bool extendedBasicTypeCases;
7401         glu::MatrixOrder order;
7402     } children[] = {
7403         {"named_block", "Named uniform block", true, true, glu::MATRIXORDER_LAST},
7404         {"named_block_row_major", "Named uniform block", true, false, glu::MATRIXORDER_ROW_MAJOR},
7405         {"named_block_col_major", "Named uniform block", true, false, glu::MATRIXORDER_COLUMN_MAJOR},
7406         {"unnamed_block", "Unnamed uniform block", false, false, glu::MATRIXORDER_LAST},
7407         {"unnamed_block_row_major", "Unnamed uniform block", false, false, glu::MATRIXORDER_ROW_MAJOR},
7408         {"unnamed_block_col_major", "Unnamed uniform block", false, false, glu::MATRIXORDER_COLUMN_MAJOR},
7409     };
7410 
7411     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
7412     const ResourceDefinition::Node::SharedPtr shader(
7413         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
7414     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
7415     const ResourceDefinition::Node::SharedPtr buffer(
7416         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_BUFFER));
7417 
7418     for (int childNdx = 0; childNdx < (int)DE_LENGTH_OF_ARRAY(children); ++childNdx)
7419     {
7420         ResourceDefinition::Node::SharedPtr parentStructure = buffer;
7421         tcu::TestCaseGroup *const blockGroup =
7422             new TestCaseGroup(context, children[childNdx].name, children[childNdx].description);
7423 
7424         targetGroup->addChild(blockGroup);
7425 
7426         if (children[childNdx].order != glu::MATRIXORDER_LAST)
7427         {
7428             glu::Layout layout;
7429             layout.matrixOrder = children[childNdx].order;
7430             parentStructure =
7431                 ResourceDefinition::Node::SharedPtr(new ResourceDefinition::LayoutQualifier(parentStructure, layout));
7432         }
7433 
7434         parentStructure = ResourceDefinition::Node::SharedPtr(
7435             new ResourceDefinition::InterfaceBlock(parentStructure, children[childNdx].namedBlock));
7436 
7437         blockContentGenerator(context, parentStructure, blockGroup, children[childNdx].extendedBasicTypeCases);
7438     }
7439 }
7440 
generateBufferVariableMatrixVariableBasicTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,ProgramResourcePropFlags targetProp)7441 static void generateBufferVariableMatrixVariableBasicTypeCases(
7442     Context &context, const ResourceDefinition::Node::SharedPtr &parentStructure, tcu::TestCaseGroup *targetGroup,
7443     ProgramResourcePropFlags targetProp)
7444 {
7445     // all matrix types and some non-matrix
7446 
7447     static const glu::DataType variableTypes[] = {
7448         glu::TYPE_FLOAT,        glu::TYPE_INT_VEC3,     glu::TYPE_FLOAT_MAT2, glu::TYPE_FLOAT_MAT2X3,
7449         glu::TYPE_FLOAT_MAT2X4, glu::TYPE_FLOAT_MAT3X2, glu::TYPE_FLOAT_MAT3, glu::TYPE_FLOAT_MAT3X4,
7450         glu::TYPE_FLOAT_MAT4X2, glu::TYPE_FLOAT_MAT4X3, glu::TYPE_FLOAT_MAT4,
7451     };
7452 
7453     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
7454     {
7455         const ResourceDefinition::Node::SharedPtr variable(
7456             new ResourceDefinition::Variable(parentStructure, variableTypes[ndx]));
7457         targetGroup->addChild(new ResourceTestCase(
7458             context, variable, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, targetProp)));
7459     }
7460 }
7461 
generateBufferVariableMatrixVariableCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,ProgramResourcePropFlags targetProp)7462 static void generateBufferVariableMatrixVariableCases(Context &context,
7463                                                       const ResourceDefinition::Node::SharedPtr &parentStructure,
7464                                                       tcu::TestCaseGroup *targetGroup,
7465                                                       ProgramResourcePropFlags targetProp)
7466 {
7467     // Basic aggregates
7468     generateBufferBackedVariableAggregateTypeCases(context, parentStructure, targetGroup,
7469                                                    PROGRAMINTERFACE_BUFFER_VARIABLE, targetProp, glu::TYPE_FLOAT_MAT3X2,
7470                                                    "", 2);
7471 
7472     // Unsized array
7473     {
7474         const ResourceDefinition::Node::SharedPtr unsized(
7475             new ResourceDefinition::ArrayElement(parentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
7476         const ResourceDefinition::Node::SharedPtr variable(
7477             new ResourceDefinition::Variable(unsized, glu::TYPE_FLOAT_MAT3X2));
7478 
7479         targetGroup->addChild(new ResourceTestCase(
7480             context, variable, ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, targetProp),
7481             "var_unsized_array"));
7482     }
7483 }
7484 
7485 template <ProgramResourcePropFlags TargetProp>
generateBufferVariableMatrixCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,bool extendedTypeCases)7486 static void generateBufferVariableMatrixCases(Context &context,
7487                                               const ResourceDefinition::Node::SharedPtr &parentStructure,
7488                                               tcu::TestCaseGroup *targetGroup, bool extendedTypeCases)
7489 {
7490     // .types
7491     if (extendedTypeCases)
7492     {
7493         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "types", "Types");
7494         targetGroup->addChild(blockGroup);
7495         generateBufferVariableMatrixVariableBasicTypeCases(context, parentStructure, blockGroup, TargetProp);
7496     }
7497 
7498     // .no_qualifier
7499     {
7500         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "no_qualifier", "No qualifier");
7501         targetGroup->addChild(blockGroup);
7502         generateBufferVariableMatrixVariableCases(context, parentStructure, blockGroup, TargetProp);
7503     }
7504 
7505     // .column_major
7506     {
7507         const ResourceDefinition::Node::SharedPtr matrixOrder(new ResourceDefinition::LayoutQualifier(
7508             parentStructure, glu::Layout(-1, -1, -1, glu::FORMATLAYOUT_LAST, glu::MATRIXORDER_COLUMN_MAJOR)));
7509 
7510         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "column_major", "Column major qualifier");
7511         targetGroup->addChild(blockGroup);
7512         generateBufferVariableMatrixVariableCases(context, matrixOrder, blockGroup, TargetProp);
7513     }
7514 
7515     // .row_major
7516     {
7517         const ResourceDefinition::Node::SharedPtr matrixOrder(new ResourceDefinition::LayoutQualifier(
7518             parentStructure, glu::Layout(-1, -1, -1, glu::FORMATLAYOUT_LAST, glu::MATRIXORDER_ROW_MAJOR)));
7519 
7520         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "row_major", "Row major qualifier");
7521         targetGroup->addChild(blockGroup);
7522         generateBufferVariableMatrixVariableCases(context, matrixOrder, blockGroup, TargetProp);
7523     }
7524 }
7525 
generateBufferVariableNameLengthCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup)7526 static void generateBufferVariableNameLengthCases(Context &context,
7527                                                   const ResourceDefinition::Node::SharedPtr &parentStructure,
7528                                                   tcu::TestCaseGroup *targetGroup)
7529 {
7530     // .sized
7531     {
7532         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "sized", "Sized target");
7533         targetGroup->addChild(blockGroup);
7534 
7535         generateBufferBackedVariableAggregateTypeCases(context, parentStructure, blockGroup,
7536                                                        PROGRAMINTERFACE_BUFFER_VARIABLE,
7537                                                        PROGRAMRESOURCEPROP_NAME_LENGTH, glu::TYPE_FLOAT, "", 3);
7538     }
7539 
7540     // .unsized
7541     {
7542         const ResourceDefinition::Node::SharedPtr unsized(
7543             new ResourceDefinition::ArrayElement(parentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
7544         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unsized", "Unsized target");
7545         targetGroup->addChild(blockGroup);
7546 
7547         generateBufferBackedVariableAggregateTypeCases(context, unsized, blockGroup, PROGRAMINTERFACE_BUFFER_VARIABLE,
7548                                                        PROGRAMRESOURCEPROP_NAME_LENGTH, glu::TYPE_FLOAT, "", 2);
7549     }
7550 }
7551 
generateBufferVariableOffsetCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup)7552 static void generateBufferVariableOffsetCases(Context &context,
7553                                               const ResourceDefinition::Node::SharedPtr &parentStructure,
7554                                               tcu::TestCaseGroup *targetGroup)
7555 {
7556     // .sized
7557     {
7558         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "sized", "Sized target");
7559         targetGroup->addChild(blockGroup);
7560 
7561         generateBufferBackedVariableAggregateTypeCases(context, parentStructure, blockGroup,
7562                                                        PROGRAMINTERFACE_BUFFER_VARIABLE, PROGRAMRESOURCEPROP_OFFSET,
7563                                                        glu::TYPE_FLOAT, "", 3);
7564     }
7565 
7566     // .unsized
7567     {
7568         const ResourceDefinition::Node::SharedPtr unsized(
7569             new ResourceDefinition::ArrayElement(parentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
7570         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unsized", "Unsized target");
7571         targetGroup->addChild(blockGroup);
7572 
7573         generateBufferBackedVariableAggregateTypeCases(context, unsized, blockGroup, PROGRAMINTERFACE_BUFFER_VARIABLE,
7574                                                        PROGRAMRESOURCEPROP_OFFSET, glu::TYPE_FLOAT, "", 2);
7575     }
7576 }
7577 
generateBufferVariableReferencedByBlockContents(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,int expandLevel)7578 static void generateBufferVariableReferencedByBlockContents(Context &context,
7579                                                             const ResourceDefinition::Node::SharedPtr &parentStructure,
7580                                                             tcu::TestCaseGroup *targetGroup, int expandLevel)
7581 {
7582     DE_UNREF(expandLevel);
7583 
7584     const ProgramResourceQueryTestTarget queryTarget(PROGRAMINTERFACE_BUFFER_VARIABLE,
7585                                                      PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER);
7586     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(parentStructure));
7587     const ResourceDefinition::Node::SharedPtr storage(
7588         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_BUFFER));
7589     const bool singleShaderCase = parentStructure->getType() == ResourceDefinition::Node::TYPE_SHADER;
7590 
7591     // .named_block
7592     {
7593         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(storage, true));
7594         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "named_block", "Named block");
7595 
7596         targetGroup->addChild(blockGroup);
7597 
7598         generateBufferReferencedByShaderInterfaceBlockCases(context, buffer, blockGroup, queryTarget, singleShaderCase);
7599     }
7600 
7601     // .unnamed_block
7602     {
7603         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(storage, false));
7604         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "unnamed_block", "Unnamed block");
7605 
7606         targetGroup->addChild(blockGroup);
7607 
7608         generateBufferReferencedByShaderInterfaceBlockCases(context, buffer, blockGroup, queryTarget, false);
7609     }
7610 
7611     // .block_array
7612     {
7613         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(storage));
7614         const ResourceDefinition::Node::SharedPtr buffer(new ResourceDefinition::InterfaceBlock(arrayElement, true));
7615         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "block_array", "Block array");
7616 
7617         targetGroup->addChild(blockGroup);
7618 
7619         generateBufferReferencedByShaderInterfaceBlockCases(context, buffer, blockGroup, queryTarget, false);
7620     }
7621 }
7622 
7623 template <ProgramResourcePropFlags TargetProp>
generateBufferVariableTopLevelCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup)7624 static void generateBufferVariableTopLevelCases(Context &context,
7625                                                 const ResourceDefinition::Node::SharedPtr &parentStructure,
7626                                                 tcu::TestCaseGroup *targetGroup)
7627 {
7628     // basic and aggregate types
7629     generateBufferBackedVariableAggregateTypeCases(context, parentStructure, targetGroup,
7630                                                    PROGRAMINTERFACE_BUFFER_VARIABLE, TargetProp, glu::TYPE_FLOAT_VEC4,
7631                                                    "", 3);
7632 
7633     // basic and aggregate types in an unsized array
7634     {
7635         const ResourceDefinition::Node::SharedPtr unsized(
7636             new ResourceDefinition::ArrayElement(parentStructure, ResourceDefinition::ArrayElement::UNSIZED_ARRAY));
7637 
7638         generateBufferBackedVariableAggregateTypeCases(context, unsized, targetGroup, PROGRAMINTERFACE_BUFFER_VARIABLE,
7639                                                        TargetProp, glu::TYPE_FLOAT_VEC4, "_unsized_array", 2);
7640     }
7641 }
7642 
generateBufferVariableTypeBasicTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,int expandLevel)7643 static void generateBufferVariableTypeBasicTypeCases(Context &context,
7644                                                      const ResourceDefinition::Node::SharedPtr &parentStructure,
7645                                                      tcu::TestCaseGroup *targetGroup, int expandLevel)
7646 {
7647     static const struct
7648     {
7649         int level;
7650         glu::DataType dataType;
7651     } variableTypes[] = {
7652         {0, glu::TYPE_FLOAT},        {1, glu::TYPE_INT},          {1, glu::TYPE_UINT},
7653         {1, glu::TYPE_BOOL},
7654 
7655         {3, glu::TYPE_FLOAT_VEC2},   {1, glu::TYPE_FLOAT_VEC3},   {1, glu::TYPE_FLOAT_VEC4},
7656 
7657         {3, glu::TYPE_INT_VEC2},     {2, glu::TYPE_INT_VEC3},     {3, glu::TYPE_INT_VEC4},
7658 
7659         {3, glu::TYPE_UINT_VEC2},    {2, glu::TYPE_UINT_VEC3},    {3, glu::TYPE_UINT_VEC4},
7660 
7661         {3, glu::TYPE_BOOL_VEC2},    {2, glu::TYPE_BOOL_VEC3},    {3, glu::TYPE_BOOL_VEC4},
7662 
7663         {2, glu::TYPE_FLOAT_MAT2},   {3, glu::TYPE_FLOAT_MAT2X3}, {3, glu::TYPE_FLOAT_MAT2X4},
7664         {2, glu::TYPE_FLOAT_MAT3X2}, {2, glu::TYPE_FLOAT_MAT3},   {3, glu::TYPE_FLOAT_MAT3X4},
7665         {2, glu::TYPE_FLOAT_MAT4X2}, {3, glu::TYPE_FLOAT_MAT4X3}, {2, glu::TYPE_FLOAT_MAT4},
7666     };
7667 
7668     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(variableTypes); ++ndx)
7669     {
7670         if (variableTypes[ndx].level <= expandLevel)
7671         {
7672             const ResourceDefinition::Node::SharedPtr variable(
7673                 new ResourceDefinition::Variable(parentStructure, variableTypes[ndx].dataType));
7674             targetGroup->addChild(new ResourceTestCase(
7675                 context, variable,
7676                 ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, PROGRAMRESOURCEPROP_TYPE)));
7677         }
7678     }
7679 }
7680 
generateBufferVariableTypeCases(Context & context,const ResourceDefinition::Node::SharedPtr & parentStructure,tcu::TestCaseGroup * targetGroup,int depth=3)7681 static void generateBufferVariableTypeCases(Context &context,
7682                                             const ResourceDefinition::Node::SharedPtr &parentStructure,
7683                                             tcu::TestCaseGroup *targetGroup, int depth = 3)
7684 {
7685     // .basic_type
7686     if (depth > 0)
7687     {
7688         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "basic_type", "Basic type");
7689         targetGroup->addChild(blockGroup);
7690         generateBufferVariableTypeBasicTypeCases(context, parentStructure, blockGroup, depth);
7691     }
7692     else
7693     {
7694         // flatten bottom-level
7695         generateBufferVariableTypeBasicTypeCases(context, parentStructure, targetGroup, depth);
7696     }
7697 
7698     // .array
7699     if (depth > 0)
7700     {
7701         const ResourceDefinition::Node::SharedPtr arrayElement(new ResourceDefinition::ArrayElement(parentStructure));
7702         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "array", "Arrays");
7703 
7704         targetGroup->addChild(blockGroup);
7705         generateBufferVariableTypeCases(context, arrayElement, blockGroup, depth - 1);
7706     }
7707 
7708     // .struct
7709     if (depth > 0)
7710     {
7711         const ResourceDefinition::Node::SharedPtr structMember(new ResourceDefinition::StructMember(parentStructure));
7712         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(context, "struct", "Structs");
7713 
7714         targetGroup->addChild(blockGroup);
7715         generateBufferVariableTypeCases(context, structMember, blockGroup, depth - 1);
7716     }
7717 }
7718 
generateBufferVariableTypeBlock(Context & context,tcu::TestCaseGroup * targetGroup,glu::GLSLVersion glslVersion)7719 static void generateBufferVariableTypeBlock(Context &context, tcu::TestCaseGroup *targetGroup,
7720                                             glu::GLSLVersion glslVersion)
7721 {
7722     const ResourceDefinition::Node::SharedPtr program(new ResourceDefinition::Program());
7723     const ResourceDefinition::Node::SharedPtr shader(
7724         new ResourceDefinition::Shader(program, glu::SHADERTYPE_COMPUTE, glslVersion));
7725     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
7726     const ResourceDefinition::Node::SharedPtr buffer(
7727         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_BUFFER));
7728     const ResourceDefinition::Node::SharedPtr block(new ResourceDefinition::InterfaceBlock(buffer, true));
7729 
7730     generateBufferVariableTypeCases(context, block, targetGroup);
7731 }
7732 
generateBufferVariableRandomCase(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion,int index,bool onlyExtensionStages)7733 static void generateBufferVariableRandomCase(Context &context, tcu::TestCaseGroup *const targetGroup,
7734                                              glu::GLSLVersion glslVersion, int index, bool onlyExtensionStages)
7735 {
7736     de::Random rnd(index * 0x12345);
7737     const ResourceDefinition::Node::SharedPtr shader = generateRandomShaderSet(rnd, glslVersion, onlyExtensionStages);
7738     const glu::DataType type                         = generateRandomDataType(rnd, true);
7739     const glu::Layout layout                         = generateRandomVariableLayout(rnd, type, true);
7740     const bool namedBlock                            = rnd.getBool();
7741     const ResourceDefinition::Node::SharedPtr defaultBlock(new ResourceDefinition::DefaultBlock(shader));
7742     const ResourceDefinition::Node::SharedPtr buffer(
7743         new ResourceDefinition::StorageQualifier(defaultBlock, glu::STORAGE_BUFFER));
7744     ResourceDefinition::Node::SharedPtr currentStructure(
7745         new ResourceDefinition::LayoutQualifier(buffer, generateRandomBufferBlockLayout(rnd)));
7746 
7747     if (namedBlock && rnd.getBool())
7748         currentStructure = ResourceDefinition::Node::SharedPtr(new ResourceDefinition::ArrayElement(currentStructure));
7749     currentStructure =
7750         ResourceDefinition::Node::SharedPtr(new ResourceDefinition::InterfaceBlock(currentStructure, namedBlock));
7751 
7752     currentStructure =
7753         ResourceDefinition::Node::SharedPtr(new ResourceDefinition::LayoutQualifier(currentStructure, layout));
7754     currentStructure = generateRandomVariableDefinition(rnd, currentStructure, type, layout, true);
7755 
7756     targetGroup->addChild(new ResourceTestCase(
7757         context, currentStructure,
7758         ProgramResourceQueryTestTarget(PROGRAMINTERFACE_BUFFER_VARIABLE, PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK),
7759         de::toString(index).c_str()));
7760 }
7761 
generateBufferVariableRandomCases(Context & context,tcu::TestCaseGroup * const targetGroup,glu::GLSLVersion glslVersion)7762 static void generateBufferVariableRandomCases(Context &context, tcu::TestCaseGroup *const targetGroup,
7763                                               glu::GLSLVersion glslVersion)
7764 {
7765     const int numBasicCases   = 40;
7766     const int numTessGeoCases = 40;
7767 
7768     for (int ndx = 0; ndx < numBasicCases; ++ndx)
7769         generateBufferVariableRandomCase(context, targetGroup, glslVersion, ndx, false);
7770     for (int ndx = 0; ndx < numTessGeoCases; ++ndx)
7771         generateBufferVariableRandomCase(context, targetGroup, glslVersion, numBasicCases + ndx, true);
7772 }
7773 
7774 class BufferVariableTestGroup : public TestCaseGroup
7775 {
7776 public:
7777     BufferVariableTestGroup(Context &context);
7778     void init(void);
7779 };
7780 
BufferVariableTestGroup(Context & context)7781 BufferVariableTestGroup::BufferVariableTestGroup(Context &context)
7782     : TestCaseGroup(context, "buffer_variable", "Buffer variable")
7783 {
7784 }
7785 
init(void)7786 void BufferVariableTestGroup::init(void)
7787 {
7788     const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
7789 
7790     // .resource_list
7791     {
7792         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "resource_list", "Resource list");
7793         addChild(blockGroup);
7794         generateBufferVariableBufferCaseBlocks(m_context, blockGroup, glslVersion,
7795                                                generateBufferVariableResourceListBlockContentsProxy);
7796     }
7797 
7798     // .array_size
7799     {
7800         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "array_size", "Array size");
7801         addChild(blockGroup);
7802         generateBufferVariableBufferCaseBlocks(m_context, blockGroup, glslVersion,
7803                                                generateBufferVariableArrayCases<PROGRAMRESOURCEPROP_ARRAY_SIZE>);
7804     }
7805 
7806     // .array_stride
7807     {
7808         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "array_stride", "Array stride");
7809         addChild(blockGroup);
7810         generateBufferVariableBufferCaseBlocks(m_context, blockGroup, glslVersion,
7811                                                generateBufferVariableArrayCases<PROGRAMRESOURCEPROP_ARRAY_STRIDE>);
7812     }
7813 
7814     // .block_index
7815     {
7816         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "block_index", "Block index");
7817         addChild(blockGroup);
7818         generateBufferVariableBlockIndexCases(m_context, glslVersion, blockGroup);
7819     }
7820 
7821     // .is_row_major
7822     {
7823         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "is_row_major", "Is row major");
7824         addChild(blockGroup);
7825         generateBufferVariableMatrixCaseBlocks(m_context, blockGroup, glslVersion,
7826                                                generateBufferVariableMatrixCases<PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR>);
7827     }
7828 
7829     // .matrix_stride
7830     {
7831         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "matrix_stride", "Matrix stride");
7832         addChild(blockGroup);
7833         generateBufferVariableMatrixCaseBlocks(m_context, blockGroup, glslVersion,
7834                                                generateBufferVariableMatrixCases<PROGRAMRESOURCEPROP_MATRIX_STRIDE>);
7835     }
7836 
7837     // .name_length
7838     {
7839         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "name_length", "Name length");
7840         addChild(blockGroup);
7841         generateBufferVariableBufferCaseBlocks(m_context, blockGroup, glslVersion,
7842                                                generateBufferVariableNameLengthCases);
7843     }
7844 
7845     // .offset
7846     {
7847         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "offset", "Offset");
7848         addChild(blockGroup);
7849         generateBufferVariableBufferCaseBlocks(m_context, blockGroup, glslVersion, generateBufferVariableOffsetCases);
7850     }
7851 
7852     // .referenced_by
7853     {
7854         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "referenced_by", "Referenced by");
7855         addChild(blockGroup);
7856         generateReferencedByShaderCaseBlocks(m_context, blockGroup, glslVersion,
7857                                              generateBufferVariableReferencedByBlockContents);
7858     }
7859 
7860     // .top_level_array_size
7861     {
7862         tcu::TestCaseGroup *const blockGroup =
7863             new TestCaseGroup(m_context, "top_level_array_size", "Top-level array size");
7864         addChild(blockGroup);
7865         generateBufferVariableBufferCaseBlocks(
7866             m_context, blockGroup, glslVersion,
7867             generateBufferVariableTopLevelCases<PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE>);
7868     }
7869 
7870     // .top_level_array_stride
7871     {
7872         tcu::TestCaseGroup *const blockGroup =
7873             new TestCaseGroup(m_context, "top_level_array_stride", "Top-level array stride");
7874         addChild(blockGroup);
7875         generateBufferVariableBufferCaseBlocks(
7876             m_context, blockGroup, glslVersion,
7877             generateBufferVariableTopLevelCases<PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE>);
7878     }
7879 
7880     // .type
7881     {
7882         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "type", "Type");
7883         addChild(blockGroup);
7884         generateBufferVariableTypeBlock(m_context, blockGroup, glslVersion);
7885     }
7886 
7887     // .random
7888     {
7889         tcu::TestCaseGroup *const blockGroup = new TestCaseGroup(m_context, "random", "Random");
7890         addChild(blockGroup);
7891         generateBufferVariableRandomCases(m_context, blockGroup, glslVersion);
7892     }
7893 }
7894 
7895 } // namespace
7896 
ProgramInterfaceQueryTests(Context & context,bool is_GL45)7897 ProgramInterfaceQueryTests::ProgramInterfaceQueryTests(Context &context, bool is_GL45)
7898     : TestCaseGroup(context, "program_interface_query", "Program interface query tests")
7899     , m_isGL45(is_GL45)
7900 {
7901 }
7902 
~ProgramInterfaceQueryTests(void)7903 ProgramInterfaceQueryTests::~ProgramInterfaceQueryTests(void)
7904 {
7905 }
7906 
init(void)7907 void ProgramInterfaceQueryTests::init(void)
7908 {
7909     // Misc queries
7910 
7911     // .buffer_limited_query
7912     {
7913         tcu::TestCaseGroup *const group =
7914             new tcu::TestCaseGroup(m_testCtx, "buffer_limited_query", "Queries limited by the buffer size");
7915 
7916         addChild(group);
7917 
7918         group->addChild(new ResourceNameBufferLimitCase(m_context, "resource_name_query",
7919                                                         "Test GetProgramResourceName with too small a buffer"));
7920         group->addChild(new ResourceQueryBufferLimitCase(m_context, "resource_query",
7921                                                          "Test GetProgramResourceiv with too small a buffer"));
7922     }
7923 
7924     // Interfaces
7925 
7926     // .uniform
7927     addChild(new UniformInterfaceTestGroup(m_context));
7928 
7929     // .uniform_block
7930     addChild(new BufferBackedBlockInterfaceTestGroup(m_context, glu::STORAGE_UNIFORM));
7931 
7932     // .atomic_counter_buffer
7933     addChild(new AtomicCounterTestGroup(m_context));
7934 
7935     // .program_input
7936     addChild(new ProgramInputTestGroup(m_context, m_isGL45));
7937 
7938     // .program_output
7939     addChild(new ProgramOutputTestGroup(m_context, m_isGL45));
7940 
7941     // .transform_feedback_varying
7942     addChild(new TransformFeedbackVaryingTestGroup(m_context));
7943 
7944     // .buffer_variable
7945     addChild(new BufferVariableTestGroup(m_context));
7946 
7947     // .shader_storage_block
7948     addChild(new BufferBackedBlockInterfaceTestGroup(m_context, glu::STORAGE_BUFFER));
7949 }
7950 
7951 } // namespace Functional
7952 } // namespace gles31
7953 } // namespace deqp
7954