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