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