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