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