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