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