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