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