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