• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 test case
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fProgramInterfaceQueryTestCase.hpp"
25 #include "es31fProgramInterfaceDefinitionUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "gluVarTypeUtil.hpp"
28 #include "gluStrUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "glwFunctions.hpp"
32 #include "glwEnums.hpp"
33 #include "deString.h"
34 #include "deStringUtil.hpp"
35 #include "deSTLUtil.hpp"
36 
37 namespace deqp
38 {
39 namespace gles31
40 {
41 namespace Functional
42 {
43 namespace
44 {
45 
46 using ProgramInterfaceDefinition::VariablePathComponent;
47 using ProgramInterfaceDefinition::VariableSearchFilter;
48 
getProgramDefaultBlockInterfaceFromStorage(glu::Storage storage)49 static glw::GLenum getProgramDefaultBlockInterfaceFromStorage (glu::Storage storage)
50 {
51 	switch (storage)
52 	{
53 		case glu::STORAGE_IN:
54 		case glu::STORAGE_PATCH_IN:
55 			return GL_PROGRAM_INPUT;
56 
57 		case glu::STORAGE_OUT:
58 		case glu::STORAGE_PATCH_OUT:
59 			return GL_PROGRAM_OUTPUT;
60 
61 		case glu::STORAGE_UNIFORM:
62 			return GL_UNIFORM;
63 
64 		default:
65 			DE_ASSERT(false);
66 			return 0;
67 	}
68 }
69 
isBufferBackedInterfaceBlockStorage(glu::Storage storage)70 static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage)
71 {
72 	return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM;
73 }
74 
getRequiredExtensionForStage(glu::ShaderType stage)75 const char* getRequiredExtensionForStage (glu::ShaderType stage)
76 {
77 	switch (stage)
78 	{
79 		case glu::SHADERTYPE_COMPUTE:
80 		case glu::SHADERTYPE_VERTEX:
81 		case glu::SHADERTYPE_FRAGMENT:
82 			return DE_NULL;
83 
84 		case glu::SHADERTYPE_GEOMETRY:
85 			return "GL_EXT_geometry_shader";
86 
87 		case glu::SHADERTYPE_TESSELLATION_CONTROL:
88 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
89 			return "GL_EXT_tessellation_shader";
90 
91 		default:
92 			DE_ASSERT(false);
93 			return DE_NULL;
94 	}
95 }
96 
getTypeSize(glu::DataType type)97 static int getTypeSize (glu::DataType type)
98 {
99 	if (type == glu::TYPE_FLOAT)
100 		return 4;
101 	else if (type == glu::TYPE_INT || type == glu::TYPE_UINT)
102 		return 4;
103 	else if (type == glu::TYPE_BOOL)
104 		return 4; // uint
105 
106 	DE_ASSERT(false);
107 	return 0;
108 }
109 
getVarTypeSize(const glu::VarType & type)110 static int getVarTypeSize (const glu::VarType& type)
111 {
112 	if (type.isBasicType())
113 	{
114 		// return in basic machine units
115 		return glu::getDataTypeScalarSize(type.getBasicType()) * getTypeSize(glu::getDataTypeScalarType(type.getBasicType()));
116 	}
117 	else if (type.isStructType())
118 	{
119 		int size = 0;
120 		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
121 			size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType());
122 		return size;
123 	}
124 	else if (type.isArrayType())
125 	{
126 		// unsized arrays are handled as if they had only one element
127 		if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY)
128 			return getVarTypeSize(type.getElementType());
129 		else
130 			return type.getArraySize() * getVarTypeSize(type.getElementType());
131 	}
132 	else
133 	{
134 		DE_ASSERT(false);
135 		return 0;
136 	}
137 }
138 
getMatrixOrderFromPath(const std::vector<VariablePathComponent> & path)139 static glu::MatrixOrder getMatrixOrderFromPath (const std::vector<VariablePathComponent>& path)
140 {
141 	glu::MatrixOrder order = glu::MATRIXORDER_LAST;
142 
143 	// inherit majority
144 	for (int pathNdx = 0; pathNdx < (int)path.size(); ++pathNdx)
145 	{
146 		glu::MatrixOrder matOrder;
147 
148 		if (path[pathNdx].isInterfaceBlock())
149 			matOrder = path[pathNdx].getInterfaceBlock()->layout.matrixOrder;
150 		else if (path[pathNdx].isDeclaration())
151 			matOrder = path[pathNdx].getDeclaration()->layout.matrixOrder;
152 		else if (path[pathNdx].isVariableType())
153 			matOrder = glu::MATRIXORDER_LAST;
154 		else
155 		{
156 			DE_ASSERT(false);
157 			return glu::MATRIXORDER_LAST;
158 		}
159 
160 		if (matOrder != glu::MATRIXORDER_LAST)
161 			order = matOrder;
162 	}
163 
164 	return order;
165 }
166 
167 class PropValidator
168 {
169 public:
170 									PropValidator					(Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension);
171 
172 	virtual std::string				getHumanReadablePropertyString	(glw::GLint propVal) const;
173 	virtual void					validate						(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
174 
175 	bool							isSupported						(void) const;
176 	bool							isSelected						(deUint32 caseFlags) const;
177 
178 protected:
179 	void							setError						(const std::string& err) const;
180 
181 	tcu::TestContext&				m_testCtx;
182 	const glu::RenderContext&		m_renderContext;
183 
184 private:
185 	const glu::ContextInfo&			m_contextInfo;
186 	const char*						m_extension;
187 	const ProgramResourcePropFlags	m_validationProp;
188 };
189 
PropValidator(Context & context,ProgramResourcePropFlags validationProp,const char * requiredExtension)190 PropValidator::PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension)
191 	: m_testCtx			(context.getTestContext())
192 	, m_renderContext	(context.getRenderContext())
193 	, m_contextInfo		(context.getContextInfo())
194 	, m_extension		(requiredExtension)
195 	, m_validationProp	(validationProp)
196 {
197 }
198 
getHumanReadablePropertyString(glw::GLint propVal) const199 std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const
200 {
201 	return de::toString(propVal);
202 }
203 
isSupported(void) const204 bool PropValidator::isSupported (void) const
205 {
206 	return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension);
207 }
208 
isSelected(deUint32 caseFlags) const209 bool PropValidator::isSelected (deUint32 caseFlags) const
210 {
211 	return (caseFlags & (deUint32)m_validationProp) != 0;
212 }
213 
setError(const std::string & err) const214 void PropValidator::setError (const std::string& err) const
215 {
216 	// don't overwrite earlier errors
217 	if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
218 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, err.c_str());
219 }
220 
221 class SingleVariableValidator : public PropValidator
222 {
223 public:
224 					SingleVariableValidator	(Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
225 
226 	void			validate				(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
227 	virtual void	validateSingleVariable	(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
228 	virtual void	validateBuiltinVariable	(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
229 
230 protected:
231 	const VariableSearchFilter	m_filter;
232 	const glw::GLuint			m_programID;
233 };
234 
SingleVariableValidator(Context & context,ProgramResourcePropFlags validationProp,glw::GLuint programID,const VariableSearchFilter & filter,const char * requiredExtension)235 SingleVariableValidator::SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
236 	: PropValidator	(context, validationProp, requiredExtension)
237 	, m_filter		(filter)
238 	, m_programID	(programID)
239 {
240 }
241 
validate(const ProgramInterfaceDefinition::Program * program,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const242 void SingleVariableValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
243 {
244 	std::vector<VariablePathComponent> path;
245 
246 	if (findProgramVariablePathByPathName(path, program, resource, m_filter))
247 	{
248 		const glu::VarType* variable = (path.back().isVariableType()) ? (path.back().getVariableType()) : (DE_NULL);
249 
250 		if (!variable || !variable->isBasicType())
251 		{
252 			m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource name \"" << resource << "\" refers to a non-basic type." << tcu::TestLog::EndMessage;
253 			setError("resource not basic type");
254 		}
255 		else
256 			validateSingleVariable(path, resource, propValue, implementationName);
257 
258 		// finding matching variable in any shader is sufficient
259 		return;
260 	}
261 	else if (deStringBeginsWith(resource.c_str(), "gl_"))
262 	{
263 		// special case for builtins
264 		validateBuiltinVariable(resource, propValue, implementationName);
265 		return;
266 	}
267 
268 	// we are only supplied good names, generated by ourselves
269 	DE_ASSERT(false);
270 	throw tcu::InternalError("Resource name consistency error");
271 }
272 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const273 void SingleVariableValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
274 {
275 	DE_UNREF(resource);
276 	DE_UNREF(propValue);
277 	DE_UNREF(implementationName);
278 	DE_ASSERT(false);
279 }
280 
281 class SingleBlockValidator : public PropValidator
282 {
283 public:
284 								SingleBlockValidator	(Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
285 
286 	void						validate				(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
287 	virtual void				validateSingleBlock		(const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
288 
289 protected:
290 	const VariableSearchFilter	m_filter;
291 	const glw::GLuint			m_programID;
292 };
293 
SingleBlockValidator(Context & context,ProgramResourcePropFlags validationProp,glw::GLuint programID,const VariableSearchFilter & filter,const char * requiredExtension)294 SingleBlockValidator::SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
295 	: PropValidator	(context, validationProp, requiredExtension)
296 	, m_filter		(filter)
297 	, m_programID	(programID)
298 {
299 }
300 
validate(const ProgramInterfaceDefinition::Program * program,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const301 void SingleBlockValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
302 {
303 	glu::VarTokenizer	tokenizer		(resource.c_str());
304 	const std::string	blockName		= tokenizer.getIdentifier();
305 	std::vector<int>	instanceIndex;
306 
307 	tokenizer.advance();
308 
309 	// array index
310 	while (tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
311 	{
312 		tokenizer.advance();
313 		DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_NUMBER);
314 
315 		instanceIndex.push_back(tokenizer.getNumber());
316 
317 		tokenizer.advance();
318 		DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_RIGHT_BRACKET);
319 
320 		tokenizer.advance();
321 	}
322 
323 	// no trailing garbage
324 	DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_END);
325 
326 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
327 	{
328 		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
329 		if (!m_filter.matchesFilter(shader))
330 			continue;
331 
332 		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
333 		{
334 			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
335 
336 			if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
337 			{
338 				// dimensions match
339 				DE_ASSERT(instanceIndex.size() == block.dimensions.size());
340 
341 				validateSingleBlock(block, instanceIndex, resource, propValue, implementationName);
342 				return;
343 			}
344 		}
345 	}
346 
347 	// we are only supplied good names, generated by ourselves
348 	DE_ASSERT(false);
349 	throw tcu::InternalError("Resource name consistency error");
350 }
351 
352 class TypeValidator : public SingleVariableValidator
353 {
354 public:
355 				TypeValidator					(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
356 
357 	std::string	getHumanReadablePropertyString	(glw::GLint propVal) const;
358 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
359 	void		validateBuiltinVariable			(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
360 };
361 
TypeValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)362 TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
363 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL)
364 {
365 }
366 
getHumanReadablePropertyString(glw::GLint propVal) const367 std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const
368 {
369 	return de::toString(glu::getShaderVarTypeStr(propVal));
370 }
371 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const372 void TypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
373 {
374 	const glu::VarType* variable = path.back().getVariableType();
375 
376 	DE_UNREF(resource);
377 	DE_UNREF(implementationName);
378 
379 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(variable->getBasicType()) << tcu::TestLog::EndMessage;
380 
381 	if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue))
382 	{
383 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
384 		setError("resource type invalid");
385 	}
386 }
387 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const388 void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
389 {
390 	DE_UNREF(implementationName);
391 
392 	static const struct
393 	{
394 		const char*		name;
395 		glu::DataType	type;
396 	} builtins[] =
397 	{
398 		{ "gl_Position",				glu::TYPE_FLOAT_VEC4	},
399 		{ "gl_FragCoord",				glu::TYPE_FLOAT_VEC4	},
400 		{ "gl_PerVertex.gl_Position",	glu::TYPE_FLOAT_VEC4	},
401 		{ "gl_VertexID",				glu::TYPE_INT			},
402 		{ "gl_InvocationID",			glu::TYPE_INT			},
403 		{ "gl_NumWorkGroups",			glu::TYPE_UINT_VEC3		},
404 		{ "gl_FragDepth",				glu::TYPE_FLOAT			},
405 		{ "gl_TessLevelOuter[0]",		glu::TYPE_FLOAT			},
406 		{ "gl_TessLevelInner[0]",		glu::TYPE_FLOAT			},
407 	};
408 
409 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
410 	{
411 		if (resource == builtins[ndx].name)
412 		{
413 			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(builtins[ndx].type) << tcu::TestLog::EndMessage;
414 
415 			if (glu::getDataTypeFromGLType(propValue) != builtins[ndx].type)
416 			{
417 				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
418 				setError("resource type invalid");
419 			}
420 			return;
421 		}
422 	}
423 
424 	DE_ASSERT(false);
425 }
426 
427 class ArraySizeValidator : public SingleVariableValidator
428 {
429 public:
430 				ArraySizeValidator				(Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter);
431 
432 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
433 	void		validateBuiltinVariable			(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
434 
435 private:
436 	const int	m_unsizedArraySize;
437 };
438 
ArraySizeValidator(Context & context,glw::GLuint programID,int unsizedArraySize,const VariableSearchFilter & filter)439 ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter)
440 	: SingleVariableValidator	(context, PROGRAMRESOURCEPROP_ARRAY_SIZE, programID, filter, DE_NULL)
441 	, m_unsizedArraySize		(unsizedArraySize)
442 {
443 }
444 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const445 void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
446 {
447 	const VariablePathComponent		nullComponent;
448 	const VariablePathComponent&	enclosingcomponent	= (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
449 
450 	const bool						isArray				= enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
451 	const bool						inUnsizedArray		= isArray && (enclosingcomponent.getVariableType()->getArraySize() == glu::VarType::UNSIZED_ARRAY);
452 	const int						arraySize			= (!isArray) ? (1) : (inUnsizedArray) ? (m_unsizedArraySize) : (enclosingcomponent.getVariableType()->getArraySize());
453 
454 	DE_ASSERT(arraySize >= 0);
455 	DE_UNREF(resource);
456 	DE_UNREF(implementationName);
457 
458 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
459 
460 	if (arraySize != propValue)
461 	{
462 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
463 		setError("resource array size invalid");
464 	}
465 }
466 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const467 void ArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
468 {
469 	DE_UNREF(implementationName);
470 
471 	static const struct
472 	{
473 		const char*		name;
474 		int				arraySize;
475 	} builtins[] =
476 	{
477 		{ "gl_Position",				1	},
478 		{ "gl_VertexID",				1	},
479 		{ "gl_FragCoord",				1	},
480 		{ "gl_PerVertex.gl_Position",	1	},
481 		{ "gl_InvocationID",			1	},
482 		{ "gl_NumWorkGroups",			1	},
483 		{ "gl_FragDepth",				1	},
484 		{ "gl_TessLevelOuter[0]",		4	},
485 		{ "gl_TessLevelInner[0]",		2	},
486 	};
487 
488 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
489 	{
490 		if (resource == builtins[ndx].name)
491 		{
492 			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << builtins[ndx].arraySize << tcu::TestLog::EndMessage;
493 
494 			if (propValue != builtins[ndx].arraySize)
495 			{
496 				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
497 				setError("resource array size invalid");
498 			}
499 			return;
500 		}
501 	}
502 
503 	DE_ASSERT(false);
504 }
505 
506 class ArrayStrideValidator : public SingleVariableValidator
507 {
508 public:
509 				ArrayStrideValidator			(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
510 
511 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
512 };
513 
ArrayStrideValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)514 ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
515 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL)
516 {
517 }
518 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const519 void ArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
520 {
521 	const VariablePathComponent		nullComponent;
522 	const VariablePathComponent&	component			= path.back();
523 	const VariablePathComponent&	enclosingcomponent	= (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
524 	const VariablePathComponent&	firstComponent		= path.front();
525 
526 	const bool						isBufferBlock		= firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
527 	const bool						isArray				= enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
528 	const bool						isAtomicCounter		= glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType()); // atomic counters are buffer backed with a stride of 4 basic machine units
529 
530 	DE_UNREF(resource);
531 	DE_UNREF(implementationName);
532 
533 	// Layout tests will verify layouts of buffer backed arrays properly. Here we just check values are greater or equal to the element size
534 	if (isBufferBlock && isArray)
535 	{
536 		const int elementSize = glu::getDataTypeScalarSize(component.getVariableType()->getBasicType()) * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
537 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting greater or equal to " << elementSize << tcu::TestLog::EndMessage;
538 
539 		if (propValue < elementSize)
540 		{
541 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
542 			setError("resource array stride invalid");
543 		}
544 	}
545 	else
546 	{
547 		// Atomics are buffer backed with stride of 4 even though they are not in an interface block
548 		const int arrayStride = (isAtomicCounter && isArray) ? (4) : (!isBufferBlock && !isAtomicCounter) ? (-1) : (0);
549 
550 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting " << arrayStride << tcu::TestLog::EndMessage;
551 
552 		if (arrayStride != propValue)
553 		{
554 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
555 			setError("resource array stride invalid");
556 		}
557 	}
558 }
559 
560 class BlockIndexValidator : public SingleVariableValidator
561 {
562 public:
563 				BlockIndexValidator				(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
564 
565 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
566 };
567 
BlockIndexValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)568 BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
569 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL)
570 {
571 }
572 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const573 void BlockIndexValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
574 {
575 	const VariablePathComponent& firstComponent = path.front();
576 
577 	DE_UNREF(resource);
578 	DE_UNREF(implementationName);
579 
580 	if (!firstComponent.isInterfaceBlock())
581 	{
582 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting -1" << tcu::TestLog::EndMessage;
583 
584 		if (propValue != -1)
585 		{
586 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
587 			setError("resource block index invalid");
588 		}
589 	}
590 	else
591 	{
592 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting a valid block index" << tcu::TestLog::EndMessage;
593 
594 		if (propValue == -1)
595 		{
596 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
597 			setError("resource block index invalid");
598 		}
599 		else
600 		{
601 			const glw::Functions&	gl			= m_renderContext.getFunctions();
602 			const glw::GLenum		interface	= (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM_BLOCK) :
603 												  (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_BUFFER) ? (GL_SHADER_STORAGE_BLOCK) :
604 												  (0);
605 			glw::GLint				written		= 0;
606 			std::vector<char>		nameBuffer	(firstComponent.getInterfaceBlock()->interfaceName.size() + 3 * firstComponent.getInterfaceBlock()->dimensions.size() + 2, '\0'); // +3 for appended "[N]", +1 for '\0' and +1 just for safety
607 
608 			gl.getProgramResourceName(m_programID, interface, propValue, (int)nameBuffer.size() - 1, &written, &nameBuffer[0]);
609 			GLU_EXPECT_NO_ERROR(gl.getError(), "query block name");
610 			TCU_CHECK(written < (int)nameBuffer.size());
611 			TCU_CHECK(nameBuffer.back() == '\0');
612 
613 			{
614 				const std::string	blockName		(&nameBuffer[0], written);
615 				std::ostringstream	expectedName;
616 
617 				expectedName << firstComponent.getInterfaceBlock()->interfaceName;
618 				for (int dimensionNdx = 0; dimensionNdx < (int)firstComponent.getInterfaceBlock()->dimensions.size(); ++dimensionNdx)
619 					expectedName << "[0]";
620 
621 				m_testCtx.getLog() << tcu::TestLog::Message << "Block name with index " << propValue << " is \"" << blockName << "\"" << tcu::TestLog::EndMessage;
622 				if (blockName != expectedName.str())
623 				{
624 					m_testCtx.getLog() << tcu::TestLog::Message << "\tError, expected " << expectedName.str() << tcu::TestLog::EndMessage;
625 					setError("resource block index invalid");
626 				}
627 			}
628 		}
629 	}
630 }
631 
632 class IsRowMajorValidator : public SingleVariableValidator
633 {
634 public:
635 				IsRowMajorValidator				(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
636 
637 	std::string getHumanReadablePropertyString	(glw::GLint propVal) const;
638 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
639 };
640 
IsRowMajorValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)641 IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
642 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL)
643 {
644 }
645 
getHumanReadablePropertyString(glw::GLint propVal) const646 std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const
647 {
648 	return de::toString(glu::getBooleanStr(propVal));
649 }
650 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const651 void IsRowMajorValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
652 {
653 	const VariablePathComponent&	component			= path.back();
654 	const VariablePathComponent&	firstComponent		= path.front();
655 
656 	const bool						isBufferBlock		= firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
657 	const bool						isMatrix			= glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
658 	const int						expected			= (isBufferBlock && isMatrix && getMatrixOrderFromPath(path) == glu::MATRIXORDER_ROW_MAJOR) ? (1) : (0);
659 
660 	DE_UNREF(resource);
661 	DE_UNREF(implementationName);
662 
663 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix order, expecting IS_ROW_MAJOR = " << expected << tcu::TestLog::EndMessage;
664 
665 	if (propValue != expected)
666 	{
667 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
668 		setError("resource matrix order invalid");
669 	}
670 }
671 
672 class MatrixStrideValidator : public SingleVariableValidator
673 {
674 public:
675 				MatrixStrideValidator			(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
676 
677 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
678 };
679 
MatrixStrideValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)680 MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
681 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL)
682 {
683 }
684 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const685 void MatrixStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
686 {
687 	const VariablePathComponent&	component			= path.back();
688 	const VariablePathComponent&	firstComponent		= path.front();
689 
690 	const bool						isBufferBlock		= firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
691 	const bool						isMatrix			= glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
692 
693 	DE_UNREF(resource);
694 	DE_UNREF(implementationName);
695 
696 	// Layout tests will verify layouts of buffer backed arrays properly. Here we just check the stride is is greater or equal to the row/column size
697 	if (isBufferBlock && isMatrix)
698 	{
699 		const bool	columnMajor			= getMatrixOrderFromPath(path) != glu::MATRIXORDER_ROW_MAJOR;
700 		const int	numMajorElements	= (columnMajor) ? (glu::getDataTypeMatrixNumRows(component.getVariableType()->getBasicType())) : (glu::getDataTypeMatrixNumColumns(component.getVariableType()->getBasicType()));
701 		const int	majorSize			= numMajorElements * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
702 
703 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting greater or equal to " << majorSize << tcu::TestLog::EndMessage;
704 
705 		if (propValue < majorSize)
706 		{
707 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
708 			setError("resource matrix stride invalid");
709 		}
710 	}
711 	else
712 	{
713 		const int matrixStride = (!isBufferBlock && !glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType())) ? (-1) : (0);
714 
715 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting " << matrixStride << tcu::TestLog::EndMessage;
716 
717 		if (matrixStride != propValue)
718 		{
719 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
720 			setError("resource matrix stride invalid");
721 		}
722 	}
723 }
724 
725 class AtomicCounterBufferIndexVerifier : public SingleVariableValidator
726 {
727 public:
728 				AtomicCounterBufferIndexVerifier	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
729 
730 	void		validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
731 };
732 
AtomicCounterBufferIndexVerifier(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)733 AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
734 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL)
735 {
736 }
737 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const738 void AtomicCounterBufferIndexVerifier::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
739 {
740 	DE_UNREF(resource);
741 	DE_UNREF(implementationName);
742 
743 	if (!glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()))
744 	{
745 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting -1" << tcu::TestLog::EndMessage;
746 
747 		if (propValue != -1)
748 		{
749 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
750 			setError("resource atomic counter buffer index invalid");
751 		}
752 	}
753 	else
754 	{
755 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting a valid index" << tcu::TestLog::EndMessage;
756 
757 		if (propValue == -1)
758 		{
759 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
760 			setError("resource atomic counter buffer index invalid");
761 		}
762 		else
763 		{
764 			const glw::Functions&	gl					= m_renderContext.getFunctions();
765 			glw::GLint				numActiveResources	= 0;
766 
767 			gl.getProgramInterfaceiv(m_programID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numActiveResources);
768 			GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInterfaceiv(..., GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, ...)");
769 
770 			if (propValue >= numActiveResources)
771 			{
772 				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << ", GL_ACTIVE_RESOURCES = " << numActiveResources << tcu::TestLog::EndMessage;
773 				setError("resource atomic counter buffer index invalid");
774 			}
775 		}
776 	}
777 }
778 
779 class LocationValidator : public SingleVariableValidator
780 {
781 public:
782 				LocationValidator		(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
783 
784 	void		validateSingleVariable	(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
785 	void		validateBuiltinVariable	(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
786 };
787 
LocationValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)788 LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
789 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL)
790 {
791 }
792 
getVariableLocationLength(const glu::VarType & type)793 static int getVariableLocationLength (const glu::VarType& type)
794 {
795 	if (type.isBasicType())
796 	{
797 		if (glu::isDataTypeMatrix(type.getBasicType()))
798 			return glu::getDataTypeMatrixNumColumns(type.getBasicType());
799 		else
800 			return 1;
801 	}
802 	else if (type.isStructType())
803 	{
804 		int size = 0;
805 		for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
806 			size += getVariableLocationLength(type.getStructPtr()->getMember(ndx).getType());
807 		return size;
808 	}
809 	else if (type.isArrayType())
810 		return type.getArraySize() * getVariableLocationLength(type.getElementType());
811 	else
812 	{
813 		DE_ASSERT(false);
814 		return 0;
815 	}
816 }
817 
getIOSubVariableLocation(const std::vector<VariablePathComponent> & path,int startNdx,int currentLocation)818 static int getIOSubVariableLocation (const std::vector<VariablePathComponent>& path, int startNdx, int currentLocation)
819 {
820 	if (currentLocation == -1)
821 		return -1;
822 
823 	if (path[startNdx].getVariableType()->isBasicType())
824 		return currentLocation;
825 	else if (path[startNdx].getVariableType()->isArrayType())
826 		return getIOSubVariableLocation(path, startNdx+1, currentLocation);
827 	else if (path[startNdx].getVariableType()->isStructType())
828 	{
829 		for (int ndx = 0; ndx < path[startNdx].getVariableType()->getStructPtr()->getNumMembers(); ++ndx)
830 		{
831 			if (&path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType() == path[startNdx + 1].getVariableType())
832 				return getIOSubVariableLocation(path, startNdx + 1, currentLocation);
833 
834 			if (currentLocation != -1)
835 				currentLocation += getVariableLocationLength(path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType());
836 		}
837 
838 		// could not find member, never happens
839 		DE_ASSERT(false);
840 		return -1;
841 	}
842 	else
843 	{
844 		DE_ASSERT(false);
845 		return -1;
846 	}
847 }
848 
getIOBlockVariableLocation(const std::vector<VariablePathComponent> & path)849 static int getIOBlockVariableLocation (const std::vector<VariablePathComponent>& path)
850 {
851 	const glu::InterfaceBlock*	block			= path.front().getInterfaceBlock();
852 	int							currentLocation	= block->layout.location;
853 
854 	// Find the block member
855 	for (int memberNdx = 0; memberNdx < (int)block->variables.size(); ++memberNdx)
856 	{
857 		if (block->variables[memberNdx].layout.location != -1)
858 			currentLocation = block->variables[memberNdx].layout.location;
859 
860 		if (&block->variables[memberNdx] == path[1].getDeclaration())
861 			break;
862 
863 		// unspecified + unspecified = unspecified
864 		if (currentLocation != -1)
865 			currentLocation += getVariableLocationLength(block->variables[memberNdx].varType);
866 	}
867 
868 	// Find subtype location in the complex type
869 	return getIOSubVariableLocation(path, 2, currentLocation);
870 }
871 
getExplicitLocationFromPath(const std::vector<VariablePathComponent> & path)872 static int getExplicitLocationFromPath (const std::vector<VariablePathComponent>& path)
873 {
874 	const glu::VariableDeclaration* varDecl = (path[0].isInterfaceBlock()) ? (path[1].getDeclaration()) : (path[0].getDeclaration());
875 
876 	if (path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM)
877 	{
878 		// inside uniform block
879 		return -1;
880 	}
881 	else if (path.front().isInterfaceBlock() && (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN		||
882 												 path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT		||
883 												 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_IN	||
884 												 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_OUT))
885 	{
886 		// inside ioblock
887 		return getIOBlockVariableLocation(path);
888 	}
889 	else if (varDecl->storage == glu::STORAGE_UNIFORM)
890 	{
891 		// default block uniform
892 		return varDecl->layout.location;
893 	}
894 	else if (varDecl->storage == glu::STORAGE_IN		||
895 			 varDecl->storage == glu::STORAGE_OUT		||
896 			 varDecl->storage == glu::STORAGE_PATCH_IN	||
897 			 varDecl->storage == glu::STORAGE_PATCH_OUT)
898 	{
899 		// default block input/output
900 		return getIOSubVariableLocation(path, 1, varDecl->layout.location);
901 	}
902 	else
903 	{
904 		DE_ASSERT(false);
905 		return -1;
906 	}
907 }
908 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const909 void LocationValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
910 {
911 	const bool			isAtomicCounterUniform	= glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
912 	const bool			isUniformBlockVariable	= path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM;
913 	const bool			isVertexShader			= m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_VERTEX);
914 	const bool			isFragmentShader		= m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_FRAGMENT);
915 	const glu::Storage	storage					= (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
916 	const bool			isInputVariable			= (storage == glu::STORAGE_IN || storage == glu::STORAGE_PATCH_IN);
917 	const bool			isOutputVariable		= (storage == glu::STORAGE_OUT || storage == glu::STORAGE_PATCH_OUT);
918 	const int			explicitLayoutLocation	= getExplicitLocationFromPath(path);
919 
920 	bool				expectLocation;
921 	std::string			reasonStr;
922 
923 	DE_UNREF(resource);
924 
925 	if (isAtomicCounterUniform)
926 	{
927 		expectLocation = false;
928 		reasonStr = "Atomic counter uniforms have effective location of -1";
929 	}
930 	else if (isUniformBlockVariable)
931 	{
932 		expectLocation = false;
933 		reasonStr = "Uniform block variables have effective location of -1";
934 	}
935 	else if (isInputVariable && !isVertexShader && explicitLayoutLocation == -1)
936 	{
937 		expectLocation = false;
938 		reasonStr = "Inputs (except for vertex shader inputs) not declared with a location layout qualifier have effective location of -1";
939 	}
940 	else if (isOutputVariable && !isFragmentShader && explicitLayoutLocation == -1)
941 	{
942 		expectLocation = false;
943 		reasonStr = "Outputs (except for fragment shader outputs) not declared with a location layout qualifier have effective location of -1";
944 	}
945 	else
946 	{
947 		expectLocation = true;
948 	}
949 
950 	if (!expectLocation)
951 	{
952 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform location, expecting -1. (" << reasonStr << ")" << tcu::TestLog::EndMessage;
953 
954 		if (propValue != -1)
955 		{
956 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
957 			setError("resource location invalid");
958 		}
959 	}
960 	else
961 	{
962 		bool locationOk;
963 
964 		if (explicitLayoutLocation == -1)
965 		{
966 			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting a valid location" << tcu::TestLog::EndMessage;
967 			locationOk = (propValue != -1);
968 		}
969 		else
970 		{
971 			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting " << explicitLayoutLocation << tcu::TestLog::EndMessage;
972 			locationOk = (propValue == explicitLayoutLocation);
973 		}
974 
975 		if (!locationOk)
976 		{
977 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
978 			setError("resource location invalid");
979 		}
980 		else
981 		{
982 			const VariablePathComponent		nullComponent;
983 			const VariablePathComponent&	enclosingcomponent	= (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
984 			const bool						isArray				= enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
985 
986 			const glw::Functions&			gl					= m_renderContext.getFunctions();
987 			const glw::GLenum				interface			= getProgramDefaultBlockInterfaceFromStorage(storage);
988 
989 			m_testCtx.getLog() << tcu::TestLog::Message << "Comparing location to the values returned by GetProgramResourceLocation" << tcu::TestLog::EndMessage;
990 
991 			// Test all bottom-level array elements
992 			if (isArray)
993 			{
994 				const std::string arrayResourceName = (implementationName.size() > 3) ? (implementationName.substr(0, implementationName.size() - 3)) : (""); // chop "[0]"
995 
996 				for (int arrayElementNdx = 0; arrayElementNdx < enclosingcomponent.getVariableType()->getArraySize(); ++arrayElementNdx)
997 				{
998 					const std::string	elementResourceName	= arrayResourceName + "[" + de::toString(arrayElementNdx) + "]";
999 					const glw::GLint	location			= gl.getProgramResourceLocation(m_programID, interface, elementResourceName.c_str());
1000 
1001 					if (location != propValue+arrayElementNdx)
1002 					{
1003 						m_testCtx.getLog()
1004 							<< tcu::TestLog::Message
1005 							<< "\tError, getProgramResourceLocation (resource=\"" << elementResourceName << "\") returned location " << location
1006 							<< ", expected " << (propValue+arrayElementNdx)
1007 							<< tcu::TestLog::EndMessage;
1008 						setError("resource location invalid");
1009 					}
1010 					else
1011 						m_testCtx.getLog() << tcu::TestLog::Message << "\tLocation of \"" << elementResourceName << "\":\t" << location << tcu::TestLog::EndMessage;
1012 				}
1013 			}
1014 			else
1015 			{
1016 				const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, implementationName.c_str());
1017 
1018 				if (location != propValue)
1019 				{
1020 					m_testCtx.getLog() << tcu::TestLog::Message << "\tError, getProgramResourceLocation returned location " << location << ", expected " << propValue << tcu::TestLog::EndMessage;
1021 					setError("resource location invalid");
1022 				}
1023 			}
1024 
1025 		}
1026 	}
1027 }
1028 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1029 void LocationValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1030 {
1031 	DE_UNREF(resource);
1032 	DE_UNREF(implementationName);
1033 
1034 	// built-ins have no location
1035 
1036 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting -1" << tcu::TestLog::EndMessage;
1037 
1038 	if (propValue != -1)
1039 	{
1040 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1041 		setError("resource location invalid");
1042 	}
1043 }
1044 
1045 class VariableNameLengthValidator : public SingleVariableValidator
1046 {
1047 public:
1048 				VariableNameLengthValidator	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1049 
1050 	void		validateSingleVariable		(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1051 	void		validateBuiltinVariable		(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1052 	void		validateNameLength			(const std::string& implementationName, glw::GLint propValue) const;
1053 };
1054 
VariableNameLengthValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)1055 VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1056 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
1057 {
1058 }
1059 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1060 void VariableNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1061 {
1062 	DE_UNREF(path);
1063 	DE_UNREF(resource);
1064 	validateNameLength(implementationName, propValue);
1065 }
1066 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1067 void VariableNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1068 {
1069 	DE_UNREF(resource);
1070 	validateNameLength(implementationName, propValue);
1071 }
1072 
validateNameLength(const std::string & implementationName,glw::GLint propValue) const1073 void VariableNameLengthValidator::validateNameLength (const std::string& implementationName, glw::GLint propValue) const
1074 {
1075 	const int expected = (int)implementationName.length() + 1; // includes null byte
1076 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1077 
1078 	if (propValue != expected)
1079 	{
1080 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1081 		setError("name length invalid");
1082 	}
1083 }
1084 
1085 class OffsetValidator : public SingleVariableValidator
1086 {
1087 public:
1088 				OffsetValidator			(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1089 
1090 	void		validateSingleVariable	(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1091 };
1092 
OffsetValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)1093 OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1094 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL)
1095 {
1096 }
1097 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1098 void OffsetValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1099 {
1100 	const bool isAtomicCounterUniform		= glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
1101 	const bool isBufferBackedBlockStorage	= path.front().isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(path.front().getInterfaceBlock()->storage);
1102 
1103 	DE_UNREF(resource);
1104 	DE_UNREF(implementationName);
1105 
1106 	if (!isAtomicCounterUniform && !isBufferBackedBlockStorage)
1107 	{
1108 		// Not buffer backed
1109 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting -1" << tcu::TestLog::EndMessage;
1110 
1111 		if (propValue != -1)
1112 		{
1113 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1114 			setError("offset invalid");
1115 		}
1116 	}
1117 	else
1118 	{
1119 		// Expect a valid offset
1120 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting a valid offset" << tcu::TestLog::EndMessage;
1121 
1122 		if (propValue < 0)
1123 		{
1124 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1125 			setError("offset invalid");
1126 		}
1127 	}
1128 }
1129 
1130 class VariableReferencedByShaderValidator : public PropValidator
1131 {
1132 public:
1133 								VariableReferencedByShaderValidator	(Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
1134 
1135 	std::string					getHumanReadablePropertyString		(glw::GLint propVal) const;
1136 	void						validate							(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1137 
1138 private:
1139 	const VariableSearchFilter	m_filter;
1140 	const glu::ShaderType		m_shaderType;
1141 };
1142 
VariableReferencedByShaderValidator(Context & context,glu::ShaderType shaderType,const VariableSearchFilter & searchFilter)1143 VariableReferencedByShaderValidator::VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1144 	: PropValidator	(context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1145 	, m_filter		(VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1146 	, m_shaderType	(shaderType)
1147 {
1148 	DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
1149 }
1150 
getHumanReadablePropertyString(glw::GLint propVal) const1151 std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1152 {
1153 	return de::toString(glu::getBooleanStr(propVal));
1154 }
1155 
validate(const ProgramInterfaceDefinition::Program * program,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1156 void VariableReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1157 {
1158 	DE_UNREF(implementationName);
1159 
1160 	std::vector<VariablePathComponent>	dummyPath;
1161 	const bool							referencedByShader = findProgramVariablePathByPathName(dummyPath, program, resource, m_filter);
1162 
1163 	m_testCtx.getLog()
1164 		<< tcu::TestLog::Message
1165 		<< "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
1166 		<< ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1167 		<< tcu::TestLog::EndMessage;
1168 
1169 	if (propValue != ((referencedByShader) ? (1) : (0)))
1170 	{
1171 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1172 		setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
1173 	}
1174 }
1175 
1176 class BlockNameLengthValidator : public SingleBlockValidator
1177 {
1178 public:
1179 			BlockNameLengthValidator	(Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1180 
1181 	void	validateSingleBlock			(const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1182 };
1183 
BlockNameLengthValidator(Context & context,const glw::GLuint programID,const VariableSearchFilter & filter)1184 BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1185 	: SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
1186 {
1187 }
1188 
validateSingleBlock(const glu::InterfaceBlock & block,const std::vector<int> & instanceIndex,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1189 void BlockNameLengthValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1190 {
1191 	DE_UNREF(instanceIndex);
1192 	DE_UNREF(block);
1193 	DE_UNREF(resource);
1194 
1195 	const int expected = (int)implementationName.length() + 1; // includes null byte
1196 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1197 
1198 	if (propValue != expected)
1199 	{
1200 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1201 		setError("name length invalid");
1202 	}
1203 }
1204 
1205 class BufferBindingValidator : public SingleBlockValidator
1206 {
1207 public:
1208 			BufferBindingValidator	(Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1209 
1210 	void	validateSingleBlock		(const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1211 };
1212 
BufferBindingValidator(Context & context,const glw::GLuint programID,const VariableSearchFilter & filter)1213 BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1214 	: SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL)
1215 {
1216 }
1217 
validateSingleBlock(const glu::InterfaceBlock & block,const std::vector<int> & instanceIndex,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1218 void BufferBindingValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1219 {
1220 	DE_UNREF(resource);
1221 	DE_UNREF(implementationName);
1222 
1223 	if (block.layout.binding != -1)
1224 	{
1225 		int flatIndex		= 0;
1226 		int dimensionSize	= 1;
1227 
1228 		for (int dimensionNdx = (int)(block.dimensions.size()) - 1; dimensionNdx >= 0; --dimensionNdx)
1229 		{
1230 			flatIndex += dimensionSize * instanceIndex[dimensionNdx];
1231 			dimensionSize *= block.dimensions[dimensionNdx];
1232 		}
1233 
1234 		const int expected = (block.dimensions.empty()) ? (block.layout.binding) : (block.layout.binding + flatIndex);
1235 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block binding, expecting " << expected << tcu::TestLog::EndMessage;
1236 
1237 		if (propValue != expected)
1238 		{
1239 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1240 			setError("buffer binding invalid");
1241 		}
1242 	}
1243 	else
1244 	{
1245 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying buffer binding, expecting a valid binding" << tcu::TestLog::EndMessage;
1246 
1247 		if (propValue < 0)
1248 		{
1249 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1250 			setError("buffer binding invalid");
1251 		}
1252 	}
1253 }
1254 
1255 class BlockReferencedByShaderValidator : public PropValidator
1256 {
1257 public:
1258 								BlockReferencedByShaderValidator	(Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
1259 
1260 	std::string					getHumanReadablePropertyString		(glw::GLint propVal) const;
1261 	void						validate							(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1262 
1263 private:
1264 	const VariableSearchFilter	m_filter;
1265 	const glu::ShaderType		m_shaderType;
1266 };
1267 
BlockReferencedByShaderValidator(Context & context,glu::ShaderType shaderType,const VariableSearchFilter & searchFilter)1268 BlockReferencedByShaderValidator::BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1269 	: PropValidator	(context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1270 	, m_filter		(VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1271 	, m_shaderType	(shaderType)
1272 {
1273 	DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
1274 }
1275 
getHumanReadablePropertyString(glw::GLint propVal) const1276 std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1277 {
1278 	return de::toString(glu::getBooleanStr(propVal));
1279 }
1280 
validate(const ProgramInterfaceDefinition::Program * program,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1281 void BlockReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1282 {
1283 	const std::string	blockName			= glu::parseVariableName(resource.c_str());
1284 	bool				referencedByShader	= false;
1285 
1286 	DE_UNREF(implementationName);
1287 
1288 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1289 	{
1290 		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1291 		if (!m_filter.matchesFilter(shader))
1292 			continue;
1293 
1294 		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1295 		{
1296 			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1297 
1298 			if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
1299 				referencedByShader = true;
1300 		}
1301 	}
1302 
1303 	m_testCtx.getLog()
1304 		<< tcu::TestLog::Message
1305 		<< "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
1306 		<< ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1307 		<< tcu::TestLog::EndMessage;
1308 
1309 	if (propValue != ((referencedByShader) ? (1) : (0)))
1310 	{
1311 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1312 		setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
1313 	}
1314 }
1315 
1316 class TopLevelArraySizeValidator : public SingleVariableValidator
1317 {
1318 public:
1319 				TopLevelArraySizeValidator	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1320 
1321 	void		validateSingleVariable		(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1322 };
1323 
TopLevelArraySizeValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)1324 TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1325 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL)
1326 {
1327 }
1328 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1329 void TopLevelArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1330 {
1331 	int			expected;
1332 	std::string	reason;
1333 
1334 	DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1335 	DE_UNREF(resource);
1336 	DE_UNREF(implementationName);
1337 
1338 	if (!path[1].getDeclaration()->varType.isArrayType())
1339 	{
1340 		expected = 1;
1341 		reason = "Top-level block member is not an array";
1342 	}
1343 	else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1344 	{
1345 		expected = 1;
1346 		reason = "Top-level block member is not an array of an aggregate type";
1347 	}
1348 	else if (path[1].getDeclaration()->varType.getArraySize() == glu::VarType::UNSIZED_ARRAY)
1349 	{
1350 		expected = 0;
1351 		reason = "Top-level block member is an unsized top-level array";
1352 	}
1353 	else
1354 	{
1355 		expected = path[1].getDeclaration()->varType.getArraySize();
1356 		reason = "Top-level block member is a sized top-level array";
1357 	}
1358 
1359 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array size, expecting " << expected << ". (" << reason << ")." << tcu::TestLog::EndMessage;
1360 
1361 	if (propValue != expected)
1362 	{
1363 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array size, got " << propValue << tcu::TestLog::EndMessage;
1364 		setError("top level array size invalid");
1365 	}
1366 }
1367 
1368 class TopLevelArrayStrideValidator : public SingleVariableValidator
1369 {
1370 public:
1371 				TopLevelArrayStrideValidator	(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1372 
1373 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1374 };
1375 
TopLevelArrayStrideValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)1376 TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1377 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL)
1378 {
1379 }
1380 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1381 void TopLevelArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1382 {
1383 	DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1384 	DE_UNREF(resource);
1385 	DE_UNREF(implementationName);
1386 
1387 	if (!path[1].getDeclaration()->varType.isArrayType())
1388 	{
1389 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array)." << tcu::TestLog::EndMessage;
1390 
1391 		if (propValue != 0)
1392 		{
1393 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1394 			setError("top level array stride invalid");
1395 		}
1396 	}
1397 	else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1398 	{
1399 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array of an aggregate type)." << tcu::TestLog::EndMessage;
1400 
1401 		if (propValue != 0)
1402 		{
1403 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1404 			setError("top level array stride invalid");
1405 		}
1406 	}
1407 	else
1408 	{
1409 		const int minimumStride = getVarTypeSize(path[1].getDeclaration()->varType.getElementType());
1410 
1411 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting greater or equal to " << minimumStride << "." << tcu::TestLog::EndMessage;
1412 
1413 		if (propValue < minimumStride)
1414 		{
1415 			m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1416 			setError("top level array stride invalid");
1417 		}
1418 	}
1419 }
1420 
1421 class TransformFeedbackResourceValidator : public PropValidator
1422 {
1423 public:
1424 					TransformFeedbackResourceValidator	(Context& context, ProgramResourcePropFlags validationProp);
1425 
1426 	void			validate							(const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1427 
1428 private:
1429 	virtual void	validateBuiltinVariable				(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1430 	virtual void	validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1431 };
1432 
1433 
TransformFeedbackResourceValidator(Context & context,ProgramResourcePropFlags validationProp)1434 TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp)
1435 	: PropValidator(context, validationProp, DE_NULL)
1436 {
1437 }
1438 
validate(const ProgramInterfaceDefinition::Program * program,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1439 void TransformFeedbackResourceValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1440 {
1441 	if (deStringBeginsWith(resource.c_str(), "gl_"))
1442 	{
1443 		validateBuiltinVariable(resource, propValue, implementationName);
1444 	}
1445 	else
1446 	{
1447 		// Check resource name is a xfb output. (sanity check)
1448 #if defined(DE_DEBUG)
1449 		bool generatorFound = false;
1450 
1451 		// Check the resource name is a valid transform feedback resource and find the name generating resource
1452 		for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1453 		{
1454 			const std::string					varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1455 			std::vector<VariablePathComponent>	path;
1456 			std::vector<std::string>			resources;
1457 
1458 			if (!findProgramVariablePathByPathName(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1459 			{
1460 				// program does not contain feedback varying, not valid program
1461 				DE_ASSERT(false);
1462 				return;
1463 			}
1464 
1465 			generateVariableTypeResourceNames(resources, varyingName, *path.back().getVariableType(), RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
1466 
1467 			if (de::contains(resources.begin(), resources.end(), resource))
1468 			{
1469 				generatorFound = true;
1470 				break;
1471 			}
1472 		}
1473 
1474 		// resource name was not found, should never happen
1475 		DE_ASSERT(generatorFound);
1476 		DE_UNREF(generatorFound);
1477 #endif
1478 
1479 		// verify resource
1480 		{
1481 			std::vector<VariablePathComponent> path;
1482 
1483 			if (!findProgramVariablePathByPathName(path, program, resource, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
1484 				DE_ASSERT(false);
1485 
1486 			validateSingleVariable(path, resource, propValue, implementationName);
1487 		}
1488 	}
1489 }
1490 
1491 class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator
1492 {
1493 public:
1494 				TransformFeedbackArraySizeValidator	(Context& context);
1495 
1496 	void		validateBuiltinVariable				(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1497 	void		validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1498 };
1499 
TransformFeedbackArraySizeValidator(Context & context)1500 TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context)
1501 	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE)
1502 {
1503 }
1504 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1505 void TransformFeedbackArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1506 {
1507 	DE_UNREF(implementationName);
1508 
1509 	int arraySize = 0;
1510 
1511 	if (resource == "gl_Position")
1512 		arraySize = 1;
1513 	else
1514 		DE_ASSERT(false);
1515 
1516 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1517 	if (arraySize != propValue)
1518 	{
1519 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1520 		setError("resource array size invalid");
1521 	}
1522 }
1523 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1524 void TransformFeedbackArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1525 {
1526 	DE_UNREF(resource);
1527 	DE_UNREF(implementationName);
1528 
1529 	const int arraySize = (path.back().getVariableType()->isArrayType()) ? (path.back().getVariableType()->getArraySize()) : (1);
1530 
1531 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1532 	if (arraySize != propValue)
1533 	{
1534 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1535 		setError("resource array size invalid");
1536 	}
1537 }
1538 
1539 class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator
1540 {
1541 public:
1542 				TransformFeedbackNameLengthValidator	(Context& context);
1543 
1544 private:
1545 	void		validateBuiltinVariable					(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1546 	void		validateSingleVariable					(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1547 	void		validateVariable						(const std::string& implementationName, glw::GLint propValue) const;
1548 };
1549 
TransformFeedbackNameLengthValidator(Context & context)1550 TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context)
1551 	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH)
1552 {
1553 }
1554 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1555 void TransformFeedbackNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1556 {
1557 	DE_UNREF(resource);
1558 	validateVariable(implementationName, propValue);
1559 }
1560 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1561 void TransformFeedbackNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1562 {
1563 	DE_UNREF(path);
1564 	DE_UNREF(resource);
1565 	validateVariable(implementationName, propValue);
1566 }
1567 
validateVariable(const std::string & implementationName,glw::GLint propValue) const1568 void TransformFeedbackNameLengthValidator::validateVariable (const std::string& implementationName, glw::GLint propValue) const
1569 {
1570 	const int expected = (int)implementationName.length() + 1; // includes null byte
1571 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1572 
1573 	if (propValue != expected)
1574 	{
1575 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1576 		setError("name length invalid");
1577 	}
1578 }
1579 
1580 class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator
1581 {
1582 public:
1583 				TransformFeedbackTypeValidator		(Context& context);
1584 
1585 	void		validateBuiltinVariable				(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1586 	void		validateSingleVariable				(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1587 };
1588 
TransformFeedbackTypeValidator(Context & context)1589 TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context)
1590 	: TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE)
1591 {
1592 }
1593 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1594 void TransformFeedbackTypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1595 {
1596 	DE_UNREF(implementationName);
1597 
1598 	glu::DataType varType = glu::TYPE_INVALID;
1599 
1600 	if (resource == "gl_Position")
1601 		varType = glu::TYPE_FLOAT_VEC4;
1602 	else
1603 		DE_ASSERT(false);
1604 
1605 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(varType) << tcu::TestLog::EndMessage;
1606 	if (glu::getDataTypeFromGLType(propValue) != varType)
1607 	{
1608 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1609 		setError("resource type invalid");
1610 	}
1611 	return;
1612 }
1613 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1614 void TransformFeedbackTypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1615 {
1616 	DE_UNREF(resource);
1617 	DE_UNREF(implementationName);
1618 
1619 	// Unlike other interfaces, xfb program interface uses just variable name to refer to arrays of basic types. (Others use "variable[0]")
1620 	// Thus we might end up querying a type for an array. In this case, return the type of an array element.
1621 	const glu::VarType& variable    = *path.back().getVariableType();
1622 	const glu::VarType& elementType = (variable.isArrayType()) ? (variable.getElementType()) : (variable);
1623 
1624 	DE_ASSERT(elementType.isBasicType());
1625 
1626 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(elementType.getBasicType()) << tcu::TestLog::EndMessage;
1627 	if (elementType.getBasicType() != glu::getDataTypeFromGLType(propValue))
1628 	{
1629 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1630 		setError("resource type invalid");
1631 	}
1632 }
1633 
1634 class PerPatchValidator : public SingleVariableValidator
1635 {
1636 public:
1637 				PerPatchValidator				(Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1638 
1639 	std::string getHumanReadablePropertyString	(glw::GLint propVal) const;
1640 	void		validateSingleVariable			(const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1641 	void		validateBuiltinVariable			(const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1642 };
1643 
PerPatchValidator(Context & context,glw::GLuint programID,const VariableSearchFilter & filter)1644 PerPatchValidator::PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1645 	: SingleVariableValidator(context, PROGRAMRESOURCEPROP_IS_PER_PATCH, programID, filter, "GL_EXT_tessellation_shader")
1646 {
1647 }
1648 
getHumanReadablePropertyString(glw::GLint propVal) const1649 std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1650 {
1651 	return de::toString(glu::getBooleanStr(propVal));
1652 }
1653 
validateSingleVariable(const std::vector<VariablePathComponent> & path,const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1654 void PerPatchValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1655 {
1656 	const glu::Storage	storage		= (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
1657 	const int			expected	= (storage == glu::STORAGE_PATCH_IN || storage == glu::STORAGE_PATCH_OUT) ? (1) : (0);
1658 
1659 	DE_UNREF(resource);
1660 	DE_UNREF(implementationName);
1661 
1662 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << expected << tcu::TestLog::EndMessage;
1663 
1664 	if (propValue != expected)
1665 	{
1666 		m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1667 		setError("resource is per patch invalid");
1668 	}
1669 }
1670 
validateBuiltinVariable(const std::string & resource,glw::GLint propValue,const std::string & implementationName) const1671 void PerPatchValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1672 {
1673 	DE_UNREF(implementationName);
1674 
1675 	static const struct
1676 	{
1677 		const char*		name;
1678 		int				isPerPatch;
1679 	} builtins[] =
1680 	{
1681 		{ "gl_Position",				0	},
1682 		{ "gl_PerVertex.gl_Position",	0	},
1683 		{ "gl_InvocationID",			0	},
1684 		{ "gl_TessLevelOuter[0]",		1	},
1685 		{ "gl_TessLevelInner[0]",		1	},
1686 	};
1687 
1688 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
1689 	{
1690 		if (resource == builtins[ndx].name)
1691 		{
1692 			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << builtins[ndx].isPerPatch << tcu::TestLog::EndMessage;
1693 
1694 			if (propValue != builtins[ndx].isPerPatch)
1695 			{
1696 				m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1697 				setError("resource is per patch invalid");
1698 			}
1699 			return;
1700 		}
1701 	}
1702 
1703 	DE_ASSERT(false);
1704 }
1705 
1706 } // anonymous
1707 
ProgramResourceQueryTestTarget(ProgramInterface interface_,deUint32 propFlags_)1708 ProgramResourceQueryTestTarget::ProgramResourceQueryTestTarget (ProgramInterface interface_, deUint32 propFlags_)
1709 	: interface(interface_)
1710 	, propFlags(propFlags_)
1711 {
1712 	switch (interface)
1713 	{
1714 		case PROGRAMINTERFACE_UNIFORM:						DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK)			== propFlags);	break;
1715 		case PROGRAMINTERFACE_UNIFORM_BLOCK:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_BLOCK_INTERFACE_MASK)	== propFlags);	break;
1716 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:			DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_SHADER_STORAGE_BLOCK_MASK)		== propFlags);	break;
1717 		case PROGRAMINTERFACE_PROGRAM_INPUT:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_INPUT_MASK)				== propFlags);	break;
1718 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_OUTPUT_MASK)				== propFlags);	break;
1719 		case PROGRAMINTERFACE_BUFFER_VARIABLE:				DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK)			== propFlags);	break;
1720 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:	DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_TRANSFORM_FEEDBACK_VARYING_MASK)	== propFlags);	break;
1721 
1722 		default:
1723 			DE_ASSERT(false);
1724 	}
1725 }
1726 
ProgramInterfaceQueryTestCase(Context & context,const char * name,const char * description,ProgramResourceQueryTestTarget queryTarget)1727 ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget)
1728 	: TestCase		(context, name, description)
1729 	, m_queryTarget	(queryTarget)
1730 {
1731 }
1732 
~ProgramInterfaceQueryTestCase(void)1733 ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void)
1734 {
1735 }
1736 
getTargetInterface(void) const1737 ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const
1738 {
1739 	return m_queryTarget.interface;
1740 }
1741 
getGLInterfaceEnumValue(ProgramInterface interface)1742 static glw::GLenum getGLInterfaceEnumValue (ProgramInterface interface)
1743 {
1744 	switch (interface)
1745 	{
1746 		case PROGRAMINTERFACE_UNIFORM:						return GL_UNIFORM;
1747 		case PROGRAMINTERFACE_UNIFORM_BLOCK:				return GL_UNIFORM_BLOCK;
1748 		case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:		return GL_ATOMIC_COUNTER_BUFFER;
1749 		case PROGRAMINTERFACE_PROGRAM_INPUT:				return GL_PROGRAM_INPUT;
1750 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:				return GL_PROGRAM_OUTPUT;
1751 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:	return GL_TRANSFORM_FEEDBACK_VARYING;
1752 		case PROGRAMINTERFACE_BUFFER_VARIABLE:				return GL_BUFFER_VARIABLE;
1753 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:			return GL_SHADER_STORAGE_BLOCK;
1754 		default:
1755 			DE_ASSERT(false);
1756 			return 0;
1757 	};
1758 }
1759 
isInterfaceBlockInterfaceName(const ProgramInterfaceDefinition::Program * program,ProgramInterface interface,const std::string & blockInterfaceName)1760 static bool isInterfaceBlockInterfaceName (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& blockInterfaceName)
1761 {
1762 	deUint32 validStorageBits;
1763 	deUint32 searchStageBits;
1764 
1765 	DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1766 	DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1767 
1768 	switch (interface)
1769 	{
1770 		case PROGRAMINTERFACE_UNIFORM_BLOCK:
1771 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1772 		case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1773 			return false;
1774 
1775 		case PROGRAMINTERFACE_PROGRAM_INPUT:
1776 			validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1777 			searchStageBits = (1u << program->getFirstStage());
1778 			break;
1779 
1780 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1781 			validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1782 			searchStageBits = (1u << program->getLastStage());
1783 			break;
1784 
1785 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1786 			validStorageBits = (1u << glu::STORAGE_OUT);
1787 			searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1788 			break;
1789 
1790 		case PROGRAMINTERFACE_UNIFORM:
1791 			validStorageBits = (1u << glu::STORAGE_UNIFORM);
1792 			searchStageBits = 0xFFFFFFFFu;
1793 			break;
1794 
1795 		case PROGRAMINTERFACE_BUFFER_VARIABLE:
1796 			validStorageBits = (1u << glu::STORAGE_BUFFER);
1797 			searchStageBits = 0xFFFFFFFFu;
1798 			break;
1799 
1800 		default:
1801 			DE_ASSERT(false);
1802 			return false;
1803 	}
1804 
1805 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1806 	{
1807 		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1808 		if (((1u << shader->getType()) & searchStageBits) == 0)
1809 			continue;
1810 
1811 		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1812 		{
1813 			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1814 
1815 			if (((1u << block.storage) & validStorageBits) == 0)
1816 				continue;
1817 
1818 			if (block.interfaceName == blockInterfaceName)
1819 				return true;
1820 		}
1821 	}
1822 	return false;
1823 }
1824 
getInterfaceBlockInteraceNameByMember(const ProgramInterfaceDefinition::Program * program,ProgramInterface interface,const std::string & memberName)1825 static std::string getInterfaceBlockInteraceNameByMember (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& memberName)
1826 {
1827 	deUint32 validStorageBits;
1828 	deUint32 searchStageBits;
1829 
1830 	DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1831 	DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1832 
1833 	switch (interface)
1834 	{
1835 		case PROGRAMINTERFACE_UNIFORM_BLOCK:
1836 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1837 		case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1838 			return "";
1839 
1840 		case PROGRAMINTERFACE_PROGRAM_INPUT:
1841 			validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1842 			searchStageBits = (1u << program->getFirstStage());
1843 			break;
1844 
1845 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1846 			validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1847 			searchStageBits = (1u << program->getLastStage());
1848 			break;
1849 
1850 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1851 			validStorageBits = (1u << glu::STORAGE_OUT);
1852 			searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1853 			break;
1854 
1855 		case PROGRAMINTERFACE_UNIFORM:
1856 			validStorageBits = (1u << glu::STORAGE_UNIFORM);
1857 			searchStageBits = 0xFFFFFFFFu;
1858 			break;
1859 
1860 		case PROGRAMINTERFACE_BUFFER_VARIABLE:
1861 			validStorageBits = (1u << glu::STORAGE_BUFFER);
1862 			searchStageBits = 0xFFFFFFFFu;
1863 			break;
1864 
1865 		default:
1866 			DE_ASSERT(false);
1867 			return "";
1868 	}
1869 
1870 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1871 	{
1872 		const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1873 		if (((1u << shader->getType()) & searchStageBits) == 0)
1874 			continue;
1875 
1876 		for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1877 		{
1878 			const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1879 
1880 			if (((1u << block.storage) & validStorageBits) == 0)
1881 				continue;
1882 
1883 			for (int varNdx = 0; varNdx < (int)block.variables.size(); ++varNdx)
1884 			{
1885 				if (block.variables[varNdx].name == memberName)
1886 					return block.interfaceName;
1887 			}
1888 		}
1889 	}
1890 	return "";
1891 }
1892 
queryAndValidateProps(tcu::TestContext & testCtx,const glw::Functions & gl,glw::GLuint programID,ProgramInterface interface,const char * targetResourceName,const ProgramInterfaceDefinition::Program * programDefinition,const std::vector<glw::GLenum> & props,const std::vector<const PropValidator * > & validators)1893 static void queryAndValidateProps (tcu::TestContext&							testCtx,
1894 								   const glw::Functions&						gl,
1895 								   glw::GLuint									programID,
1896 								   ProgramInterface								interface,
1897 								   const char*									targetResourceName,
1898 								   const ProgramInterfaceDefinition::Program*	programDefinition,
1899 								   const std::vector<glw::GLenum>&				props,
1900 								   const std::vector<const PropValidator*>&		validators)
1901 {
1902 	const glw::GLenum			glInterface					= getGLInterfaceEnumValue(interface);
1903 	std::string					implementationResourceName	= targetResourceName;
1904 	glw::GLuint					resourceNdx;
1905 	glw::GLint					written						= -1;
1906 
1907 	// prefill result buffer with an invalid value. -1 might be valid sometimes, avoid it. Make buffer one larger
1908 	// to allow detection of too many return values
1909 	std::vector<glw::GLint>		propValues		(props.size() + 1, -2);
1910 
1911 	DE_ASSERT(props.size() == validators.size());
1912 
1913 	// query
1914 
1915 	resourceNdx = gl.getProgramResourceIndex(programID, glInterface, targetResourceName);
1916 	GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
1917 
1918 	if (resourceNdx == GL_INVALID_INDEX)
1919 	{
1920 		static const struct
1921 		{
1922 			bool removeTrailingArray;	// convert from "target[0]" -> "target"
1923 			bool removeTrailingMember;	// convert from "target.member" -> "target"
1924 			bool removeIOBlock;			// convert from "InterfaceName.target" -> "target"
1925 			bool addIOBlock;			// convert from "target" -> "InterfaceName.target"
1926 			bool addIOBlockArray;		// convert from "target" -> "InterfaceName[0].target"
1927 		} recoveryStrategies[] =
1928 		{
1929 			// try one patch
1930 			{ true,		false,	false,	false,	false	},
1931 			{ false,	true,	false,	false,	false	},
1932 			{ false,	false,	true,	false,	false	},
1933 			{ false,	false,	false,	true,	false	},
1934 			{ false,	false,	false,	false,	true	},
1935 			// patch both ends
1936 			{ true,		false,	true,	false,	false	},
1937 			{ true,		false,	false,	true,	false	},
1938 			{ true,		false,	false,	false,	true	},
1939 			{ false,	true,	true,	false,	false	},
1940 			{ false,	true,	false,	true,	false	},
1941 			{ false,	true,	false,	false,	true	},
1942 		};
1943 
1944 		// The resource name generation in the GL implementations is very commonly broken. Try to
1945 		// keep the tests producing useful data even in these cases by attempting to recover from
1946 		// common naming bugs. Set test result to failure even if recovery succeeded to signal
1947 		// incorrect name generation.
1948 
1949 		testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceIndex returned GL_INVALID_INDEX for \"" << targetResourceName << "\"" << tcu::TestLog::EndMessage;
1950 		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource");
1951 
1952 		for (int strategyNdx = 0; strategyNdx < DE_LENGTH_OF_ARRAY(recoveryStrategies); ++strategyNdx)
1953 		{
1954 			const std::string	resourceName			= std::string(targetResourceName);
1955 			const size_t		rootNameEnd				= resourceName.find_first_of(".[");
1956 			const std::string	rootName				= resourceName.substr(0, rootNameEnd);
1957 			std::string			simplifiedResourceName;
1958 
1959 			if (recoveryStrategies[strategyNdx].removeTrailingArray)
1960 			{
1961 				if (de::endsWith(resourceName, "[0]"))
1962 					simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3);
1963 				else
1964 					continue;
1965 			}
1966 
1967 			if (recoveryStrategies[strategyNdx].removeTrailingMember)
1968 			{
1969 				const size_t lastMember = resourceName.find_last_of('.');
1970 				if (lastMember != std::string::npos)
1971 					simplifiedResourceName = resourceName.substr(0, lastMember);
1972 				else
1973 					continue;
1974 			}
1975 
1976 			if (recoveryStrategies[strategyNdx].removeIOBlock)
1977 			{
1978 				if (deStringBeginsWith(resourceName.c_str(), "gl_PerVertex."))
1979 				{
1980 					// builtin interface bock, remove block name
1981 					simplifiedResourceName = resourceName.substr(13);
1982 				}
1983 				else if (isInterfaceBlockInterfaceName(programDefinition, interface, rootName))
1984 				{
1985 					// user-defined inteface block, remove name
1986 					const size_t accessorEnd = resourceName.find('.'); // includes potential array accessor
1987 
1988 					if (accessorEnd != std::string::npos)
1989 						simplifiedResourceName = resourceName.substr(0, accessorEnd+1);
1990 					else
1991 						continue;
1992 				}
1993 				else
1994 				{
1995 					// recovery not applicable
1996 					continue;
1997 				}
1998 			}
1999 
2000 			if (recoveryStrategies[strategyNdx].addIOBlock || recoveryStrategies[strategyNdx].addIOBlockArray)
2001 			{
2002 				const std::string arrayAccessor = (recoveryStrategies[strategyNdx].addIOBlockArray) ? ("[0]") : ("");
2003 
2004 				if (deStringBeginsWith(resourceName.c_str(), "gl_") && resourceName.find('.') == std::string::npos)
2005 				{
2006 					// free builtin variable, add block name
2007 					simplifiedResourceName = "gl_PerVertex" + arrayAccessor + "." + resourceName;
2008 				}
2009 				else
2010 				{
2011 					const std::string interafaceName = getInterfaceBlockInteraceNameByMember(programDefinition, interface, rootName);
2012 
2013 					if (!interafaceName.empty())
2014 					{
2015 						// free user variable, add block name
2016 						simplifiedResourceName = interafaceName + arrayAccessor + "." + resourceName;
2017 					}
2018 					else
2019 					{
2020 						// recovery not applicable
2021 						continue;
2022 					}
2023 				}
2024 			}
2025 
2026 			if (simplifiedResourceName.empty())
2027 				continue;
2028 
2029 			resourceNdx = gl.getProgramResourceIndex(programID, glInterface, simplifiedResourceName.c_str());
2030 			GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
2031 
2032 			// recovery succeeded
2033 			if (resourceNdx != GL_INVALID_INDEX)
2034 			{
2035 				implementationResourceName = simplifiedResourceName;
2036 				testCtx.getLog() << tcu::TestLog::Message << "\tResource not found, continuing anyway using index obtained for resource \"" << simplifiedResourceName << "\"" << tcu::TestLog::EndMessage;
2037 				break;
2038 			}
2039 		}
2040 
2041 		if (resourceNdx == GL_INVALID_INDEX)
2042 			return;
2043 	}
2044 
2045 	gl.getProgramResourceiv(programID, glInterface, resourceNdx, (int)props.size(), &props[0], (int)propValues.size(), &written, &propValues[0]);
2046 	GLU_EXPECT_NO_ERROR(gl.getError(), "get props");
2047 
2048 	if (written != (int)props.size())
2049 	{
2050 		testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv returned unexpected number of values, expected " << (int)props.size() << ", got " << written << tcu::TestLog::EndMessage;
2051 		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2052 		return;
2053 	}
2054 
2055 	if (propValues.back() != -2)
2056 	{
2057 		testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv post write buffer guard value was modified, too many return values" << tcu::TestLog::EndMessage;
2058 		testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2059 		return;
2060 	}
2061 	propValues.pop_back();
2062 	DE_ASSERT(validators.size() == propValues.size());
2063 
2064 	// log
2065 
2066 	{
2067 		tcu::MessageBuilder message(&testCtx.getLog());
2068 		message << "For resource index " << resourceNdx << " (\"" << targetResourceName << "\") got following properties:\n";
2069 
2070 		for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2071 			message << "\t" << glu::getProgramResourcePropertyName(props[propNdx]) << ":\t" << validators[propNdx]->getHumanReadablePropertyString(propValues[propNdx]) << "\n";
2072 
2073 		message << tcu::TestLog::EndMessage;
2074 	}
2075 
2076 	// validate
2077 
2078 	for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2079 		validators[propNdx]->validate(programDefinition, targetResourceName, propValues[propNdx], implementationResourceName);
2080 }
2081 
getAndCheckProgramDefinition(void)2082 const ProgramInterfaceDefinition::Program* ProgramInterfaceQueryTestCase::getAndCheckProgramDefinition (void)
2083 {
2084 	const ProgramInterfaceDefinition::Program* programDefinition = getProgramDefinition();
2085 	DE_ASSERT(programDefinition->isValid());
2086 
2087 	if (programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
2088 		programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
2089 	{
2090 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2091 			throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2092 	}
2093 
2094 	// Testing IS_PER_PATCH as a part of a larger set is ok, since the extension is checked
2095 	// before query. However, we don't want IS_PER_PATCH-specific tests to become noop and pass.
2096 	if (m_queryTarget.propFlags == PROGRAMRESOURCEPROP_IS_PER_PATCH)
2097 	{
2098 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2099 			throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2100 	}
2101 
2102 	if (programDefinition->hasStage(glu::SHADERTYPE_GEOMETRY))
2103 	{
2104 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2105 			throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
2106 	}
2107 
2108 	if (programContainsIOBlocks(programDefinition))
2109 	{
2110 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_io_blocks"))
2111 			throw tcu::NotSupportedError("Test requires GL_EXT_shader_io_blocks extension");
2112 	}
2113 
2114 	return programDefinition;
2115 }
2116 
getMaxPatchVertices(void)2117 int ProgramInterfaceQueryTestCase::getMaxPatchVertices (void)
2118 {
2119 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
2120 	glw::GLint				maxPatchVertices	= 0;
2121 
2122 	gl.getIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
2123 	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_PATCH_VERTICES)");
2124 	return maxPatchVertices;
2125 }
2126 
iterate(void)2127 ProgramInterfaceQueryTestCase::IterateResult ProgramInterfaceQueryTestCase::iterate (void)
2128 {
2129 	struct TestProperty
2130 	{
2131 		glw::GLenum				prop;
2132 		const PropValidator*	validator;
2133 	};
2134 
2135 	const ProgramInterfaceDefinition::Program*	programDefinition	= getAndCheckProgramDefinition();
2136 	const std::vector<std::string>				targetResources		= getQueryTargetResources();
2137 	glu::ShaderProgram							program				(m_context.getRenderContext(), generateProgramInterfaceProgramSources(programDefinition));
2138 
2139 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2140 
2141 	// Log program
2142 	{
2143 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
2144 
2145 		// Feedback varyings
2146 		if (!programDefinition->getTransformFeedbackVaryings().empty())
2147 		{
2148 			tcu::MessageBuilder builder(&m_testCtx.getLog());
2149 			builder << "Transform feedback varyings: {";
2150 			for (int ndx = 0; ndx < (int)programDefinition->getTransformFeedbackVaryings().size(); ++ndx)
2151 			{
2152 				if (ndx)
2153 					builder << ", ";
2154 				builder << "\"" << programDefinition->getTransformFeedbackVaryings()[ndx] << "\"";
2155 			}
2156 			builder << "}" << tcu::TestLog::EndMessage;
2157 		}
2158 
2159 		m_testCtx.getLog() << program;
2160 		if (!program.isOk())
2161 		{
2162 			m_testCtx.getLog() << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits" << tcu::TestLog::EndMessage;
2163 			checkProgramResourceUsage(programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2164 
2165 			// within limits
2166 			throw tcu::TestError("could not build program");
2167 		}
2168 	}
2169 
2170 	// Check interface props
2171 
2172 	switch (m_queryTarget.interface)
2173 	{
2174 		case PROGRAMINTERFACE_UNIFORM:
2175 		{
2176 			const VariableSearchFilter					uniformFilter						= VariableSearchFilter::createStorageFilter(glu::STORAGE_UNIFORM);
2177 
2178 			const TypeValidator							typeValidator						(m_context, program.getProgram(),						uniformFilter);
2179 			const ArraySizeValidator					arraySizeValidator					(m_context, program.getProgram(),						-1,					uniformFilter);
2180 			const ArrayStrideValidator					arrayStrideValidator				(m_context, program.getProgram(),						uniformFilter);
2181 			const BlockIndexValidator					blockIndexValidator					(m_context, program.getProgram(),						uniformFilter);
2182 			const IsRowMajorValidator					isRowMajorValidator					(m_context, program.getProgram(),						uniformFilter);
2183 			const MatrixStrideValidator					matrixStrideValidator				(m_context, program.getProgram(),						uniformFilter);
2184 			const AtomicCounterBufferIndexVerifier		atomicCounterBufferIndexVerifier	(m_context, program.getProgram(),						uniformFilter);
2185 			const LocationValidator						locationValidator					(m_context, program.getProgram(),						uniformFilter);
2186 			const VariableNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						uniformFilter);
2187 			const OffsetValidator						offsetVerifier						(m_context, program.getProgram(),						uniformFilter);
2188 			const VariableReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						uniformFilter);
2189 			const VariableReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					uniformFilter);
2190 			const VariableReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					uniformFilter);
2191 			const VariableReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					uniformFilter);
2192 			const VariableReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		uniformFilter);
2193 			const VariableReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	uniformFilter);
2194 
2195 			const TestProperty allProperties[] =
2196 			{
2197 				{ GL_ARRAY_SIZE,							&arraySizeValidator					},
2198 				{ GL_ARRAY_STRIDE,							&arrayStrideValidator				},
2199 				{ GL_ATOMIC_COUNTER_BUFFER_INDEX,			&atomicCounterBufferIndexVerifier	},
2200 				{ GL_BLOCK_INDEX,							&blockIndexValidator				},
2201 				{ GL_IS_ROW_MAJOR,							&isRowMajorValidator				},
2202 				{ GL_LOCATION,								&locationValidator					},
2203 				{ GL_MATRIX_STRIDE,							&matrixStrideValidator				},
2204 				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2205 				{ GL_OFFSET,								&offsetVerifier						},
2206 				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2207 				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2208 				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2209 				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2210 				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2211 				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2212 				{ GL_TYPE,									&typeValidator						},
2213 			};
2214 
2215 			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2216 			{
2217 				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "UniformResource", "Uniform resource \"" +  targetResources[targetResourceNdx] + "\"");
2218 				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2219 				std::vector<glw::GLenum>			props;
2220 				std::vector<const PropValidator*>	validators;
2221 
2222 				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2223 				{
2224 					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2225 						allProperties[propNdx].validator->isSupported())
2226 					{
2227 						props.push_back(allProperties[propNdx].prop);
2228 						validators.push_back(allProperties[propNdx].validator);
2229 					}
2230 				}
2231 
2232 				DE_ASSERT(!props.empty());
2233 
2234 				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2235 			}
2236 
2237 			break;
2238 		}
2239 
2240 		case PROGRAMINTERFACE_UNIFORM_BLOCK:
2241 		case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
2242 		{
2243 			const glu::Storage						storage								= (m_queryTarget.interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
2244 			const VariableSearchFilter				blockFilter							= VariableSearchFilter::createStorageFilter(storage);
2245 
2246 			const BlockNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						blockFilter);
2247 			const BlockReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						blockFilter);
2248 			const BlockReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					blockFilter);
2249 			const BlockReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					blockFilter);
2250 			const BlockReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					blockFilter);
2251 			const BlockReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		blockFilter);
2252 			const BlockReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	blockFilter);
2253 			const BufferBindingValidator			bufferBindingValidator				(m_context, program.getProgram(),						blockFilter);
2254 
2255 			const TestProperty allProperties[] =
2256 			{
2257 				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2258 				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2259 				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2260 				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2261 				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2262 				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2263 				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2264 				{ GL_BUFFER_BINDING,						&bufferBindingValidator				},
2265 			};
2266 
2267 			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2268 			{
2269 				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "BlockResource", "Interface block \"" +  targetResources[targetResourceNdx] + "\"");
2270 				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2271 				std::vector<glw::GLenum>			props;
2272 				std::vector<const PropValidator*>	validators;
2273 
2274 				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2275 				{
2276 					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2277 						allProperties[propNdx].validator->isSupported())
2278 					{
2279 						props.push_back(allProperties[propNdx].prop);
2280 						validators.push_back(allProperties[propNdx].validator);
2281 					}
2282 				}
2283 
2284 				DE_ASSERT(!props.empty());
2285 
2286 				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2287 			}
2288 
2289 			break;
2290 		}
2291 
2292 		case PROGRAMINTERFACE_PROGRAM_INPUT:
2293 		case PROGRAMINTERFACE_PROGRAM_OUTPUT:
2294 		{
2295 			const bool									isInputCase							= (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT);
2296 			const glu::Storage							varyingStorage						= (isInputCase) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
2297 			const glu::Storage							patchStorage						= (isInputCase) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT);
2298 			const glu::ShaderType						shaderType							= (isInputCase) ? (programDefinition->getFirstStage()) : (programDefinition->getLastStage());
2299 			const int									unsizedArraySize					= (isInputCase && shaderType == glu::SHADERTYPE_GEOMETRY)					? (1)															// input points
2300 																							: (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)		? (getMaxPatchVertices())										// input batch size
2301 																							: (!isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)		? (programDefinition->getTessellationNumOutputPatchVertices())	// output batch size
2302 																							: (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION)	? (getMaxPatchVertices())										// input batch size
2303 																							: (-1);
2304 			const VariableSearchFilter					variableFilter						= VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType),
2305 																															   VariableSearchFilter::logicalOr(VariableSearchFilter::createStorageFilter(varyingStorage),
2306 																																							   VariableSearchFilter::createStorageFilter(patchStorage)));
2307 
2308 			const TypeValidator							typeValidator						(m_context, program.getProgram(),						variableFilter);
2309 			const ArraySizeValidator					arraySizeValidator					(m_context, program.getProgram(),						unsizedArraySize,		variableFilter);
2310 			const LocationValidator						locationValidator					(m_context, program.getProgram(),						variableFilter);
2311 			const VariableNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						variableFilter);
2312 			const VariableReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						variableFilter);
2313 			const VariableReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					variableFilter);
2314 			const VariableReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					variableFilter);
2315 			const VariableReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					variableFilter);
2316 			const VariableReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		variableFilter);
2317 			const VariableReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	variableFilter);
2318 			const PerPatchValidator						perPatchValidator					(m_context, program.getProgram(),						variableFilter);
2319 
2320 			const TestProperty allProperties[] =
2321 			{
2322 				{ GL_ARRAY_SIZE,							&arraySizeValidator					},
2323 				{ GL_LOCATION,								&locationValidator					},
2324 				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2325 				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2326 				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2327 				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2328 				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2329 				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2330 				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2331 				{ GL_TYPE,									&typeValidator						},
2332 				{ GL_IS_PER_PATCH,							&perPatchValidator					},
2333 			};
2334 
2335 			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2336 			{
2337 				const std::string					resourceInterfaceName	= (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? ("Input") : ("Output");
2338 				const tcu::ScopedLogSection			section					(m_testCtx.getLog(), "BlockResource", resourceInterfaceName + " resource \"" +  targetResources[targetResourceNdx] + "\"");
2339 				const glw::Functions&				gl						= m_context.getRenderContext().getFunctions();
2340 				std::vector<glw::GLenum>			props;
2341 				std::vector<const PropValidator*>	validators;
2342 
2343 				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2344 				{
2345 					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2346 						allProperties[propNdx].validator->isSupported())
2347 					{
2348 						props.push_back(allProperties[propNdx].prop);
2349 						validators.push_back(allProperties[propNdx].validator);
2350 					}
2351 				}
2352 
2353 				DE_ASSERT(!props.empty());
2354 
2355 				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2356 			}
2357 
2358 			break;
2359 		}
2360 
2361 		case PROGRAMINTERFACE_BUFFER_VARIABLE:
2362 		{
2363 			const VariableSearchFilter					variableFilter						= VariableSearchFilter::createStorageFilter(glu::STORAGE_BUFFER);
2364 
2365 			const TypeValidator							typeValidator						(m_context, program.getProgram(),						variableFilter);
2366 			const ArraySizeValidator					arraySizeValidator					(m_context, program.getProgram(),						0,					variableFilter);
2367 			const ArrayStrideValidator					arrayStrideValidator				(m_context, program.getProgram(),						variableFilter);
2368 			const BlockIndexValidator					blockIndexValidator					(m_context, program.getProgram(),						variableFilter);
2369 			const IsRowMajorValidator					isRowMajorValidator					(m_context, program.getProgram(),						variableFilter);
2370 			const MatrixStrideValidator					matrixStrideValidator				(m_context, program.getProgram(),						variableFilter);
2371 			const OffsetValidator						offsetValidator						(m_context, program.getProgram(),						variableFilter);
2372 			const VariableNameLengthValidator			nameLengthValidator					(m_context, program.getProgram(),						variableFilter);
2373 			const VariableReferencedByShaderValidator	referencedByVertexVerifier			(m_context, glu::SHADERTYPE_VERTEX,						variableFilter);
2374 			const VariableReferencedByShaderValidator	referencedByFragmentVerifier		(m_context, glu::SHADERTYPE_FRAGMENT,					variableFilter);
2375 			const VariableReferencedByShaderValidator	referencedByComputeVerifier			(m_context, glu::SHADERTYPE_COMPUTE,					variableFilter);
2376 			const VariableReferencedByShaderValidator	referencedByGeometryVerifier		(m_context, glu::SHADERTYPE_GEOMETRY,					variableFilter);
2377 			const VariableReferencedByShaderValidator	referencedByTessControlVerifier		(m_context, glu::SHADERTYPE_TESSELLATION_CONTROL,		variableFilter);
2378 			const VariableReferencedByShaderValidator	referencedByTessEvaluationVerifier	(m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION,	variableFilter);
2379 			const TopLevelArraySizeValidator			topLevelArraySizeValidator			(m_context, program.getProgram(),						variableFilter);
2380 			const TopLevelArrayStrideValidator			topLevelArrayStrideValidator		(m_context, program.getProgram(),						variableFilter);
2381 
2382 			const TestProperty allProperties[] =
2383 			{
2384 				{ GL_ARRAY_SIZE,							&arraySizeValidator					},
2385 				{ GL_ARRAY_STRIDE,							&arrayStrideValidator				},
2386 				{ GL_BLOCK_INDEX,							&blockIndexValidator				},
2387 				{ GL_IS_ROW_MAJOR,							&isRowMajorValidator				},
2388 				{ GL_MATRIX_STRIDE,							&matrixStrideValidator				},
2389 				{ GL_NAME_LENGTH,							&nameLengthValidator				},
2390 				{ GL_OFFSET,								&offsetValidator					},
2391 				{ GL_REFERENCED_BY_VERTEX_SHADER,			&referencedByVertexVerifier			},
2392 				{ GL_REFERENCED_BY_FRAGMENT_SHADER,			&referencedByFragmentVerifier		},
2393 				{ GL_REFERENCED_BY_COMPUTE_SHADER,			&referencedByComputeVerifier		},
2394 				{ GL_REFERENCED_BY_GEOMETRY_SHADER,			&referencedByGeometryVerifier		},
2395 				{ GL_REFERENCED_BY_TESS_CONTROL_SHADER,		&referencedByTessControlVerifier	},
2396 				{ GL_REFERENCED_BY_TESS_EVALUATION_SHADER,	&referencedByTessEvaluationVerifier	},
2397 				{ GL_TOP_LEVEL_ARRAY_SIZE,					&topLevelArraySizeValidator			},
2398 				{ GL_TOP_LEVEL_ARRAY_STRIDE,				&topLevelArrayStrideValidator		},
2399 				{ GL_TYPE,									&typeValidator						},
2400 			};
2401 
2402 			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2403 			{
2404 				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "BufferVariableResource", "Buffer variable \"" +  targetResources[targetResourceNdx] + "\"");
2405 				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2406 				std::vector<glw::GLenum>			props;
2407 				std::vector<const PropValidator*>	validators;
2408 
2409 				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2410 				{
2411 					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2412 						allProperties[propNdx].validator->isSupported())
2413 					{
2414 						props.push_back(allProperties[propNdx].prop);
2415 						validators.push_back(allProperties[propNdx].validator);
2416 					}
2417 				}
2418 
2419 				DE_ASSERT(!props.empty());
2420 
2421 				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2422 			}
2423 
2424 			break;
2425 		}
2426 
2427 		case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
2428 		{
2429 			const TransformFeedbackTypeValidator		typeValidator			(m_context);
2430 			const TransformFeedbackArraySizeValidator	arraySizeValidator		(m_context);
2431 			const TransformFeedbackNameLengthValidator	nameLengthValidator		(m_context);
2432 
2433 			const TestProperty allProperties[] =
2434 			{
2435 				{ GL_ARRAY_SIZE,					&arraySizeValidator				},
2436 				{ GL_NAME_LENGTH,					&nameLengthValidator			},
2437 				{ GL_TYPE,							&typeValidator					},
2438 			};
2439 
2440 			for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2441 			{
2442 				const tcu::ScopedLogSection			section			(m_testCtx.getLog(), "XFBVariableResource", "Transform feedback varying \"" +  targetResources[targetResourceNdx] + "\"");
2443 				const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
2444 				std::vector<glw::GLenum>			props;
2445 				std::vector<const PropValidator*>	validators;
2446 
2447 				for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2448 				{
2449 					if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2450 						allProperties[propNdx].validator->isSupported())
2451 					{
2452 						props.push_back(allProperties[propNdx].prop);
2453 						validators.push_back(allProperties[propNdx].validator);
2454 					}
2455 				}
2456 
2457 				DE_ASSERT(!props.empty());
2458 
2459 				queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2460 			}
2461 
2462 			break;
2463 		}
2464 
2465 		default:
2466 			DE_ASSERT(false);
2467 	}
2468 
2469 	return STOP;
2470 }
2471 
checkLimit(glw::GLenum pname,int usage,const glw::Functions & gl,tcu::TestLog & log)2472 static bool checkLimit (glw::GLenum pname, int usage, const glw::Functions& gl, tcu::TestLog& log)
2473 {
2474 	if (usage > 0)
2475 	{
2476 		glw::GLint limit = 0;
2477 		gl.getIntegerv(pname, &limit);
2478 		GLU_EXPECT_NO_ERROR(gl.getError(), "query limits");
2479 
2480 		log << tcu::TestLog::Message << "\t" << glu::getGettableStateStr(pname) << " = " << limit << ", test requires " << usage << tcu::TestLog::EndMessage;
2481 
2482 		if (limit < usage)
2483 		{
2484 			log << tcu::TestLog::Message << "\t\tLimit exceeded" << tcu::TestLog::EndMessage;
2485 			return false;
2486 		}
2487 	}
2488 
2489 	return true;
2490 }
2491 
checkShaderResourceUsage(const ProgramInterfaceDefinition::Program * program,const ProgramInterfaceDefinition::Shader * shader,const glw::Functions & gl,tcu::TestLog & log)2492 static bool checkShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader, const glw::Functions& gl, tcu::TestLog& log)
2493 {
2494 	const ProgramInterfaceDefinition::ShaderResourceUsage usage = getShaderResourceUsage(program, shader);
2495 
2496 	switch (shader->getType())
2497 	{
2498 		case glu::SHADERTYPE_VERTEX:
2499 		{
2500 			const struct
2501 			{
2502 				glw::GLenum	pname;
2503 				int			usage;
2504 			} restrictions[] =
2505 			{
2506 				{ GL_MAX_VERTEX_ATTRIBS,						usage.numInputVectors					},
2507 				{ GL_MAX_VERTEX_UNIFORM_COMPONENTS,				usage.numDefaultBlockUniformComponents	},
2508 				{ GL_MAX_VERTEX_UNIFORM_VECTORS,				usage.numUniformVectors					},
2509 				{ GL_MAX_VERTEX_UNIFORM_BLOCKS,					usage.numUniformBlocks					},
2510 				{ GL_MAX_VERTEX_OUTPUT_COMPONENTS,				usage.numOutputComponents				},
2511 				{ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,			usage.numSamplers						},
2512 				{ GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,			usage.numAtomicCounterBuffers			},
2513 				{ GL_MAX_VERTEX_ATOMIC_COUNTERS,				usage.numAtomicCounters					},
2514 				{ GL_MAX_VERTEX_IMAGE_UNIFORMS,					usage.numImages							},
2515 				{ GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,	usage.numCombinedUniformComponents		},
2516 				{ GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks			},
2517 			};
2518 
2519 			bool allOk = true;
2520 
2521 			log << tcu::TestLog::Message << "Vertex shader:" << tcu::TestLog::EndMessage;
2522 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2523 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2524 
2525 			return allOk;
2526 		}
2527 
2528 		case glu::SHADERTYPE_FRAGMENT:
2529 		{
2530 			const struct
2531 			{
2532 				glw::GLenum	pname;
2533 				int			usage;
2534 			} restrictions[] =
2535 			{
2536 				{ GL_MAX_FRAGMENT_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents		},
2537 				{ GL_MAX_FRAGMENT_UNIFORM_VECTORS,				usage.numUniformVectors						},
2538 				{ GL_MAX_FRAGMENT_UNIFORM_BLOCKS,				usage.numUniformBlocks						},
2539 				{ GL_MAX_FRAGMENT_INPUT_COMPONENTS,				usage.numInputComponents					},
2540 				{ GL_MAX_TEXTURE_IMAGE_UNITS,					usage.numSamplers							},
2541 				{ GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers				},
2542 				{ GL_MAX_FRAGMENT_ATOMIC_COUNTERS,				usage.numAtomicCounters						},
2543 				{ GL_MAX_FRAGMENT_IMAGE_UNIFORMS,				usage.numImages								},
2544 				{ GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,	usage.numCombinedUniformComponents			},
2545 				{ GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,		usage.numShaderStorageBlocks				},
2546 			};
2547 
2548 			bool allOk = true;
2549 
2550 			log << tcu::TestLog::Message << "Fragment shader:" << tcu::TestLog::EndMessage;
2551 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2552 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2553 
2554 			return allOk;
2555 		}
2556 
2557 		case glu::SHADERTYPE_COMPUTE:
2558 		{
2559 			const struct
2560 			{
2561 				glw::GLenum	pname;
2562 				int			usage;
2563 			} restrictions[] =
2564 			{
2565 				{ GL_MAX_COMPUTE_UNIFORM_BLOCKS,				usage.numUniformBlocks					},
2566 				{ GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS,			usage.numSamplers						},
2567 				{ GL_MAX_COMPUTE_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents	},
2568 				{ GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers			},
2569 				{ GL_MAX_COMPUTE_ATOMIC_COUNTERS,				usage.numAtomicCounters					},
2570 				{ GL_MAX_COMPUTE_IMAGE_UNIFORMS,				usage.numImages							},
2571 				{ GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS,	usage.numCombinedUniformComponents		},
2572 				{ GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks			},
2573 			};
2574 
2575 			bool allOk = true;
2576 
2577 			log << tcu::TestLog::Message << "Compute shader:" << tcu::TestLog::EndMessage;
2578 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2579 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2580 
2581 			return allOk;
2582 		}
2583 
2584 		case glu::SHADERTYPE_GEOMETRY:
2585 		{
2586 			const int totalOutputComponents = program->getGeometryNumOutputVertices() * usage.numOutputComponents;
2587 			const struct
2588 			{
2589 				glw::GLenum	pname;
2590 				int			usage;
2591 			} restrictions[] =
2592 			{
2593 				{ GL_MAX_GEOMETRY_UNIFORM_COMPONENTS,				usage.numDefaultBlockUniformComponents			},
2594 				{ GL_MAX_GEOMETRY_UNIFORM_BLOCKS,					usage.numUniformBlocks							},
2595 				{ GL_MAX_GEOMETRY_INPUT_COMPONENTS,					usage.numInputComponents						},
2596 				{ GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,				usage.numOutputComponents						},
2597 				{ GL_MAX_GEOMETRY_OUTPUT_VERTICES,					(int)program->getGeometryNumOutputVertices()	},
2598 				{ GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,			totalOutputComponents							},
2599 				{ GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,				usage.numSamplers								},
2600 				{ GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,			usage.numAtomicCounterBuffers					},
2601 				{ GL_MAX_GEOMETRY_ATOMIC_COUNTERS,					usage.numAtomicCounters							},
2602 				{ GL_MAX_GEOMETRY_IMAGE_UNIFORMS,					usage.numImages									},
2603 				{ GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks					},
2604 			};
2605 
2606 			bool allOk = true;
2607 
2608 			log << tcu::TestLog::Message << "Geometry shader:" << tcu::TestLog::EndMessage;
2609 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2610 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2611 
2612 			return allOk;
2613 		}
2614 
2615 		case glu::SHADERTYPE_TESSELLATION_CONTROL:
2616 		{
2617 			const int totalOutputComponents = program->getTessellationNumOutputPatchVertices() * usage.numOutputComponents + usage.numPatchOutputComponents;
2618 			const struct
2619 			{
2620 				glw::GLenum	pname;
2621 				int			usage;
2622 			} restrictions[] =
2623 			{
2624 				{ GL_MAX_PATCH_VERTICES,								(int)program->getTessellationNumOutputPatchVertices()	},
2625 				{ GL_MAX_TESS_PATCH_COMPONENTS,							usage.numPatchOutputComponents							},
2626 				{ GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS,				usage.numDefaultBlockUniformComponents					},
2627 				{ GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,					usage.numUniformBlocks									},
2628 				{ GL_MAX_TESS_CONTROL_INPUT_COMPONENTS,					usage.numInputComponents								},
2629 				{ GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS,				usage.numOutputComponents								},
2630 				{ GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS,			totalOutputComponents									},
2631 				{ GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,				usage.numSamplers										},
2632 				{ GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,			usage.numAtomicCounterBuffers							},
2633 				{ GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,					usage.numAtomicCounters									},
2634 				{ GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,					usage.numImages											},
2635 				{ GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks							},
2636 			};
2637 
2638 			bool allOk = true;
2639 
2640 			log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage;
2641 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2642 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2643 
2644 			return allOk;
2645 		}
2646 
2647 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
2648 		{
2649 			const struct
2650 			{
2651 				glw::GLenum	pname;
2652 				int			usage;
2653 			} restrictions[] =
2654 			{
2655 				{ GL_MAX_PATCH_VERTICES,								(int)program->getTessellationNumOutputPatchVertices()	},
2656 				{ GL_MAX_TESS_PATCH_COMPONENTS,							usage.numPatchInputComponents							},
2657 				{ GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,			usage.numDefaultBlockUniformComponents					},
2658 				{ GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,				usage.numUniformBlocks									},
2659 				{ GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,				usage.numInputComponents								},
2660 				{ GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,				usage.numOutputComponents								},
2661 				{ GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,			usage.numSamplers										},
2662 				{ GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,		usage.numAtomicCounterBuffers							},
2663 				{ GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,				usage.numAtomicCounters									},
2664 				{ GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,				usage.numImages											},
2665 				{ GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,			usage.numShaderStorageBlocks							},
2666 			};
2667 
2668 			bool allOk = true;
2669 
2670 			log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage;
2671 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2672 				allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2673 
2674 			return allOk;
2675 		}
2676 
2677 		default:
2678 			DE_ASSERT(false);
2679 			return false;
2680 	}
2681 }
2682 
checkProgramCombinedResourceUsage(const ProgramInterfaceDefinition::Program * program,const glw::Functions & gl,tcu::TestLog & log)2683 static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2684 {
2685 	const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program);
2686 
2687 	const struct
2688 	{
2689 		glw::GLenum	pname;
2690 		int			usage;
2691 	} restrictions[] =
2692 	{
2693 		{ GL_MAX_UNIFORM_BUFFER_BINDINGS,						usage.uniformBufferMaxBinding+1					},
2694 		{ GL_MAX_UNIFORM_BLOCK_SIZE,							usage.uniformBufferMaxSize						},
2695 		{ GL_MAX_COMBINED_UNIFORM_BLOCKS,						usage.numUniformBlocks							},
2696 		{ GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,			usage.numCombinedVertexUniformComponents		},
2697 		{ GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS,			usage.numCombinedFragmentUniformComponents		},
2698 		{ GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS,			usage.numCombinedGeometryUniformComponents		},
2699 		{ GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,		usage.numCombinedTessControlUniformComponents	},
2700 		{ GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,	usage.numCombinedTessEvalUniformComponents		},
2701 		{ GL_MAX_VARYING_COMPONENTS,							usage.numVaryingComponents						},
2702 		{ GL_MAX_VARYING_VECTORS,								usage.numVaryingVectors							},
2703 		{ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,					usage.numCombinedSamplers						},
2704 		{ GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES,				usage.numCombinedOutputResources				},
2705 		{ GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,				usage.atomicCounterBufferMaxBinding+1			},
2706 		{ GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE,					usage.atomicCounterBufferMaxSize				},
2707 		{ GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,				usage.numAtomicCounterBuffers					},
2708 		{ GL_MAX_COMBINED_ATOMIC_COUNTERS,						usage.numAtomicCounters							},
2709 		{ GL_MAX_IMAGE_UNITS,									usage.maxImageBinding+1							},
2710 		{ GL_MAX_COMBINED_IMAGE_UNIFORMS,						usage.numCombinedImages							},
2711 		{ GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,				usage.shaderStorageBufferMaxBinding+1			},
2712 		{ GL_MAX_SHADER_STORAGE_BLOCK_SIZE,						usage.shaderStorageBufferMaxSize				},
2713 		{ GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS,				usage.numShaderStorageBlocks					},
2714 		{ GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,		usage.numXFBInterleavedComponents				},
2715 		{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,			usage.numXFBSeparateAttribs						},
2716 		{ GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,		usage.numXFBSeparateComponents					},
2717 		{ GL_MAX_DRAW_BUFFERS,									usage.fragmentOutputMaxBinding+1				},
2718 	};
2719 
2720 	bool allOk = true;
2721 
2722 	log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage;
2723 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2724 		allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2725 
2726 	return allOk;
2727 }
2728 
checkProgramResourceUsage(const ProgramInterfaceDefinition::Program * program,const glw::Functions & gl,tcu::TestLog & log)2729 void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2730 {
2731 	bool limitExceeded = false;
2732 
2733 	for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
2734 		limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log);
2735 
2736 	limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log);
2737 
2738 	if (limitExceeded)
2739 	{
2740 		log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage;
2741 		throw tcu::NotSupportedError("one or more resource limits exceeded");
2742 	}
2743 }
2744 
2745 } // Functional
2746 } // gles31
2747 } // deqp
2748