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