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