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