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