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