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