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