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