blob: 382328ebfd06593bc0ec87ac600422b59c7b7c4c [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001/*-------------------------------------------------------------------------
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
37namespace deqp
38{
39namespace gles31
40{
41namespace Functional
42{
43namespace
44{
45
46using ProgramInterfaceDefinition::VariablePathComponent;
47using ProgramInterfaceDefinition::VariableSearchFilter;
48
49static bool stringEndsWith (const std::string& str, const std::string& suffix)
50{
51 if (suffix.length() > str.length())
52 return false;
53 else
54 return str.substr(str.length() - suffix.length()) == suffix;
55}
56
57static glw::GLenum getProgramDefaultBlockInterfaceFromStorage (glu::Storage storage)
58{
59 switch (storage)
60 {
61 case glu::STORAGE_IN: return GL_PROGRAM_INPUT;
62 case glu::STORAGE_OUT: return GL_PROGRAM_OUTPUT;
63 case glu::STORAGE_UNIFORM: return GL_UNIFORM;
64 default:
65 DE_ASSERT(false);
66 return 0;
67 }
68}
69
70static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage)
71{
72 return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM;
73}
74
75static int getTypeSize (glu::DataType type)
76{
77 if (type == glu::TYPE_FLOAT)
78 return 4;
79 else if (type == glu::TYPE_INT || type == glu::TYPE_UINT)
80 return 4;
81 else if (type == glu::TYPE_BOOL)
82 return 4; // uint
83
84 DE_ASSERT(false);
85 return 0;
86}
87
88static int getVarTypeSize (const glu::VarType& type)
89{
90 if (type.isBasicType())
91 {
92 // return in basic machine units
93 return glu::getDataTypeScalarSize(type.getBasicType()) * getTypeSize(glu::getDataTypeScalarType(type.getBasicType()));
94 }
95 else if (type.isStructType())
96 {
97 int size = 0;
98 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
99 size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType());
100 return size;
101 }
102 else if (type.isArrayType())
103 {
104 // unsized arrays are handled as if they had only one element
105 if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY)
106 return getVarTypeSize(type.getElementType());
107 else
108 return type.getArraySize() * getVarTypeSize(type.getElementType());
109 }
110 else
111 {
112 DE_ASSERT(false);
113 return 0;
114 }
115}
116
117static glu::MatrixOrder getMatrixOrderFromPath (const std::vector<VariablePathComponent>& path)
118{
119 glu::MatrixOrder order = glu::MATRIXORDER_LAST;
120
121 // inherit majority
122 for (int pathNdx = 0; pathNdx < (int)path.size(); ++pathNdx)
123 {
124 glu::MatrixOrder matOrder;
125
126 if (path[pathNdx].isInterfaceBlock())
127 matOrder = path[pathNdx].getInterfaceBlock()->layout.matrixOrder;
128 else if (path[pathNdx].isDeclaration())
129 matOrder = path[pathNdx].getDeclaration()->layout.matrixOrder;
130 else if (path[pathNdx].isVariableType())
131 matOrder = glu::MATRIXORDER_LAST;
132 else
133 {
134 DE_ASSERT(false);
135 return glu::MATRIXORDER_LAST;
136 }
137
138 if (matOrder != glu::MATRIXORDER_LAST)
139 order = matOrder;
140 }
141
142 return order;
143}
144
145class PropValidator
146{
147public:
148 PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension = "");
149
150 virtual std::string getHumanReadablePropertyString (glw::GLint propVal) const;
151 virtual void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const = 0;
152
153 bool isSupported (void) const;
154 bool isSelected (deUint32 caseFlags) const;
155
156protected:
157 void setError (const std::string& err) const;
158
159 tcu::TestContext& m_testCtx;
160 const glu::RenderContext& m_renderContext;
161
162private:
163 const glu::ContextInfo& m_contextInfo;
164 const std::string m_extension;
165 const ProgramResourcePropFlags m_validationProp;
166};
167
168PropValidator::PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension)
169 : m_testCtx (context.getTestContext())
170 , m_renderContext (context.getRenderContext())
171 , m_contextInfo (context.getContextInfo())
172 , m_extension (requiredExtension)
173 , m_validationProp (validationProp)
174{
175}
176
177std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const
178{
179 return de::toString(propVal);
180}
181
182bool PropValidator::isSupported (void) const
183{
184 return m_extension.empty() || m_contextInfo.isExtensionSupported(m_extension.c_str());
185}
186
187bool PropValidator::isSelected (deUint32 caseFlags) const
188{
189 return (caseFlags & (deUint32)m_validationProp) != 0;
190}
191
192void PropValidator::setError (const std::string& err) const
193{
194 // don't overwrite earlier errors
195 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
196 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, err.c_str());
197}
198
199class SingleVariableValidator : public PropValidator
200{
201public:
202 SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension = "");
203
204 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const;
205 virtual void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const = 0;
206 virtual void validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const;
207
208protected:
209 const VariableSearchFilter m_filter;
210 const glw::GLuint m_programID;
211};
212
213SingleVariableValidator::SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
214 : PropValidator (context, validationProp, requiredExtension)
215 , m_filter (filter)
216 , m_programID (programID)
217{
218}
219
220void SingleVariableValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const
221{
222 std::vector<VariablePathComponent> path;
223
224 if (findProgramVariablePathByPathName(path, program, resource, m_filter))
225 {
226 const glu::VarType* variable = (path.back().isVariableType()) ? (path.back().getVariableType()) : (DE_NULL);
227
228 if (!variable || !variable->isBasicType())
229 {
230 m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource name \"" << resource << "\" refers to a non-basic type." << tcu::TestLog::EndMessage;
231 setError("resource not basic type");
232 }
233 else
234 validateSingleVariable(path, resource, propValue);
235
236 // finding matching variable in any shader is sufficient
237 return;
238 }
239 else if (deStringBeginsWith(resource.c_str(), "gl_"))
240 {
241 // special case for builtins
242 validateBuiltinVariable(resource, propValue);
243 return;
244 }
245
246 m_testCtx.getLog() << tcu::TestLog::Message << "Error, could not find resource \"" << resource << "\" in the program" << tcu::TestLog::EndMessage;
247 setError("could not find resource");
248}
249
250void SingleVariableValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const
251{
252 DE_UNREF(propValue);
253
254 m_testCtx.getLog() << tcu::TestLog::Message << "Error, could not find builtin resource \"" << resource << "\" in the program" << tcu::TestLog::EndMessage;
255 setError("could not find builtin resource");
256}
257
258class SingleBlockValidator : public PropValidator
259{
260public:
261 SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension = "");
262
263 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const;
264 virtual void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue) const = 0;
265
266protected:
267 const VariableSearchFilter m_filter;
268 const glw::GLuint m_programID;
269};
270
271SingleBlockValidator::SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
272 : PropValidator (context, validationProp, requiredExtension)
273 , m_filter (filter)
274 , m_programID (programID)
275{
276}
277
278void SingleBlockValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const
279{
280 glu::VarTokenizer tokenizer (resource.c_str());
281 const std::string blockName = tokenizer.getIdentifier();
282 std::vector<int> instanceIndex;
283
284 tokenizer.advance();
285
286 // array index
287 while (tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
288 {
289 tokenizer.advance();
290 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_NUMBER);
291
292 instanceIndex.push_back(tokenizer.getNumber());
293
294 tokenizer.advance();
295 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_RIGHT_BRACKET);
296
297 tokenizer.advance();
298 }
299
300 // no trailing garbage
301 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_END);
302
303 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
304 {
305 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
306 if (!m_filter.matchesFilter(shader))
307 continue;
308
309 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
310 {
311 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
312
313 if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
314 {
315 // dimensions match
316 DE_ASSERT(instanceIndex.size() == block.dimensions.size());
317
318 validateSingleBlock(block, instanceIndex, resource, propValue);
319 return;
320 }
321 }
322 }
323 m_testCtx.getLog() << tcu::TestLog::Message << "Error, could not find resource \"" << resource << "\" in the program" << tcu::TestLog::EndMessage;
324 setError("could not find resource");
325}
326
327class TypeValidator : public SingleVariableValidator
328{
329public:
330 TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
331
332 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
333 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
334 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const;
335};
336
337TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
338 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter)
339{
340}
341
342std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const
343{
344 return de::toString(glu::getShaderVarTypeStr(propVal));
345}
346
347void TypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
348{
349 const glu::VarType* variable = path.back().getVariableType();
350
351 DE_UNREF(resource);
352
353 if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue))
354 {
355 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeFromGLType(propValue) << tcu::TestLog::EndMessage;
356 setError("resource type invalid");
357 }
358}
359
360void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const
361{
362 if (resource == "gl_Position")
363 {
364 if (glu::getDataTypeFromGLType(propValue) != glu::TYPE_FLOAT_VEC4)
365 {
366 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeFromGLType(propValue) << tcu::TestLog::EndMessage;
367 setError("resource type invalid");
368 }
369 }
370 else
371 DE_ASSERT(false);
372}
373
374class ArraySizeValidator : public SingleVariableValidator
375{
376public:
377 ArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
378 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
379};
380
381ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
382 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE, programID, filter)
383{
384}
385
386void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
387{
388 const VariablePathComponent nullComponent;
389 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
390
391 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
392 const bool inUnsizedArray = isArray && (enclosingcomponent.getVariableType()->getArraySize() == glu::VarType::UNSIZED_ARRAY);
393 const int arraySize = (!isArray) ? (1) : (inUnsizedArray) ? (0) : (enclosingcomponent.getVariableType()->getArraySize());
394
395 DE_UNREF(resource);
396
397 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
398
399 if (arraySize != propValue)
400 {
401 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
402 setError("resource array size invalid");
403 }
404}
405
406class ArrayStrideValidator : public SingleVariableValidator
407{
408public:
409 ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
410 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
411};
412
413ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
414 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter)
415{
416}
417
418void ArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
419{
420 const VariablePathComponent nullComponent;
421 const VariablePathComponent& component = path.back();
422 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
423 const VariablePathComponent& firstComponent = path.front();
424
425 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
426 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
427 const bool isAtomicCounter = glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType()); // atomic counters are buffer backed with a stride of 4 basic machine units
428
429 DE_UNREF(resource);
430
431 // Layout tests will verify layouts of buffer backed arrays properly. Here we just check values are greater or equal to the element size
432 if (isBufferBlock && isArray)
433 {
434 const int elementSize = glu::getDataTypeScalarSize(component.getVariableType()->getBasicType()) * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
435 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting greater or equal to " << elementSize << tcu::TestLog::EndMessage;
436
437 if (propValue < elementSize)
438 {
439 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
440 setError("resource array stride invalid");
441 }
442 }
443 else
444 {
445 // Atomics are buffer backed with stride of 4 even though they are not in an interface block
446 const int arrayStride = (isAtomicCounter && isArray) ? (4) : (!isBufferBlock && !isAtomicCounter) ? (-1) : (0);
447
448 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting " << arrayStride << tcu::TestLog::EndMessage;
449
450 if (arrayStride != propValue)
451 {
452 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
453 setError("resource array stride invalid");
454 }
455 }
456}
457
458class BlockIndexValidator : public SingleVariableValidator
459{
460public:
461 BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
462 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
463};
464
465BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
466 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter)
467{
468}
469
470void BlockIndexValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
471{
472 const VariablePathComponent& firstComponent = path.front();
473
474 DE_UNREF(resource);
475
476 if (!firstComponent.isInterfaceBlock())
477 {
478 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting -1" << tcu::TestLog::EndMessage;
479
480 if (propValue != -1)
481 {
482 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
483 setError("resource block index invalid");
484 }
485 }
486 else
487 {
488 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting a valid block index" << tcu::TestLog::EndMessage;
489
490 if (propValue == -1)
491 {
492 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
493 setError("resource block index invalid");
494 }
495 else
496 {
497 const glw::Functions& gl = m_renderContext.getFunctions();
498 const glw::GLenum interface = (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM_BLOCK) :
499 (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_BUFFER) ? (GL_SHADER_STORAGE_BLOCK) :
500 (0);
501 glw::GLint written = 0;
502 std::vector<char> nameBuffer (firstComponent.getInterfaceBlock()->interfaceName.size() + 3 * firstComponent.getInterfaceBlock()->dimensions.size() + 2, '\0'); // +3 for appended "[N]", +1 for '\0' and +1 just for safety
503
504 gl.getProgramResourceName(m_programID, interface, propValue, (int)nameBuffer.size() - 1, &written, &nameBuffer[0]);
505 GLU_EXPECT_NO_ERROR(gl.getError(), "query block name");
506 TCU_CHECK(written < (int)nameBuffer.size());
507 TCU_CHECK(nameBuffer.back() == '\0');
508
509 {
510 const std::string blockName (&nameBuffer[0], written);
511 std::ostringstream expectedName;
512
513 expectedName << firstComponent.getInterfaceBlock()->interfaceName;
514 for (int dimensionNdx = 0; dimensionNdx < (int)firstComponent.getInterfaceBlock()->dimensions.size(); ++dimensionNdx)
515 expectedName << "[0]";
516
517 m_testCtx.getLog() << tcu::TestLog::Message << "Block name with index " << propValue << " is \"" << blockName << "\"" << tcu::TestLog::EndMessage;
518 if (blockName != expectedName.str())
519 {
520 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, expected " << expectedName.str() << tcu::TestLog::EndMessage;
521 setError("resource block index invalid");
522 }
523 }
524 }
525 }
526}
527
528class IsRowMajorValidator : public SingleVariableValidator
529{
530public:
531 IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
532
533 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
534 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
535};
536
537IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
538 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter)
539{
540}
541
542std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const
543{
544 return de::toString(glu::getBooleanStr(propVal));
545}
546
547void IsRowMajorValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
548{
549 const VariablePathComponent& component = path.back();
550 const VariablePathComponent& firstComponent = path.front();
551
552 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
553 const bool isMatrix = glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
554 const int expected = (isBufferBlock && isMatrix && getMatrixOrderFromPath(path) == glu::MATRIXORDER_ROW_MAJOR) ? (1) : (0);
555
556 DE_UNREF(resource);
557
558 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix order, expecting IS_ROW_MAJOR = " << expected << tcu::TestLog::EndMessage;
559
560 if (propValue != expected)
561 {
562 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
563 setError("resource matrix order invalid");
564 }
565}
566
567class MatrixStrideValidator : public SingleVariableValidator
568{
569public:
570 MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
571 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
572};
573
574MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
575 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter)
576{
577}
578
579void MatrixStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
580{
581 const VariablePathComponent& component = path.back();
582 const VariablePathComponent& firstComponent = path.front();
583
584 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
585 const bool isMatrix = glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
586
587 DE_UNREF(resource);
588
589 // 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
590 if (isBufferBlock && isMatrix)
591 {
592 const bool columnMajor = getMatrixOrderFromPath(path) != glu::MATRIXORDER_ROW_MAJOR;
593 const int numMajorElements = (columnMajor) ? (glu::getDataTypeMatrixNumRows(component.getVariableType()->getBasicType())) : (glu::getDataTypeMatrixNumColumns(component.getVariableType()->getBasicType()));
594 const int majorSize = numMajorElements * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
595
596 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting greater or equal to " << majorSize << tcu::TestLog::EndMessage;
597
598 if (propValue < majorSize)
599 {
600 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
601 setError("resource matrix stride invalid");
602 }
603 }
604 else
605 {
606 const int matrixStride = (!isBufferBlock && !glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType())) ? (-1) : (0);
607
608 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting " << matrixStride << tcu::TestLog::EndMessage;
609
610 if (matrixStride != propValue)
611 {
612 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
613 setError("resource matrix stride invalid");
614 }
615 }
616}
617
618class AtomicCounterBufferIndexVerifier : public SingleVariableValidator
619{
620public:
621 AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
622 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
623};
624
625AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
626 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter)
627{
628}
629
630void AtomicCounterBufferIndexVerifier::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
631{
632 DE_UNREF(resource);
633
634 if (!glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()))
635 {
636 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting -1" << tcu::TestLog::EndMessage;
637
638 if (propValue != -1)
639 {
640 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
641 setError("resource atomic counter buffer index invalid");
642 }
643 }
644 else
645 {
646 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting a valid index" << tcu::TestLog::EndMessage;
647
648 if (propValue == -1)
649 {
650 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
651 setError("resource atomic counter buffer index invalid");
652 }
653 else
654 {
655 const glw::Functions& gl = m_renderContext.getFunctions();
656 glw::GLint numActiveResources = 0;
657
658 gl.getProgramInterfaceiv(m_programID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numActiveResources);
659 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInterfaceiv(..., GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, ...)");
660
661 if (propValue >= numActiveResources)
662 {
663 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << ", GL_ACTIVE_RESOURCES = " << numActiveResources << tcu::TestLog::EndMessage;
664 setError("resource atomic counter buffer index invalid");
665 }
666 }
667 }
668}
669
670class LocationValidator : public SingleVariableValidator
671{
672public:
673 LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
674 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
675};
676
677LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
678 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter)
679{
680}
681
682static int getVariableLocationLength (const glu::VarType& type)
683{
684 if (type.isBasicType())
685 {
686 if (glu::isDataTypeMatrix(type.getBasicType()))
687 return glu::getDataTypeMatrixNumColumns(type.getBasicType());
688 else
689 return 1;
690 }
691 else if (type.isStructType())
692 {
693 int size = 0;
694 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
695 size += getVariableLocationLength(type.getStructPtr()->getMember(ndx).getType());
696 return size;
697 }
698 else if (type.isArrayType())
699 return type.getArraySize() * getVariableLocationLength(type.getElementType());
700 else
701 {
702 DE_ASSERT(false);
703 return 0;
704 }
705}
706
707static int getIOSubVariableLocation (const std::vector<VariablePathComponent>& path, int startNdx, int currentLocation)
708{
709 if (currentLocation == -1)
710 return -1;
711
712 if (path[startNdx].getVariableType()->isBasicType())
713 return currentLocation;
714 else if (path[startNdx].getVariableType()->isArrayType())
715 return getIOSubVariableLocation(path, startNdx+1, currentLocation);
716 else if (path[startNdx].getVariableType()->isStructType())
717 {
718 for (int ndx = 0; ndx < path[startNdx].getVariableType()->getStructPtr()->getNumMembers(); ++ndx)
719 {
720 if (&path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType() == path[startNdx + 1].getVariableType())
721 return getIOSubVariableLocation(path, startNdx + 1, currentLocation);
722
723 if (currentLocation != -1)
724 currentLocation += getVariableLocationLength(path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType());
725 }
726
727 // could not find member, never happens
728 DE_ASSERT(false);
729 return -1;
730 }
731 else
732 {
733 DE_ASSERT(false);
734 return -1;
735 }
736}
737
738static int getIOBlockVariableLocation (const std::vector<VariablePathComponent>& path)
739{
740 const glu::InterfaceBlock* block = path.front().getInterfaceBlock();
741 int currentLocation = block->layout.location;
742
743 // Find the block member
744 for (int memberNdx = 0; memberNdx < (int)block->variables.size(); ++memberNdx)
745 {
746 if (&block->variables[memberNdx] == path[1].getDeclaration())
747 break;
748
749 if (block->variables[memberNdx].layout.location != -1)
750 currentLocation = block->variables[memberNdx].layout.location;
751
752 currentLocation += getVariableLocationLength(block->variables[memberNdx].varType);
753 }
754
755 // Find subtype location in the complex type
756 return getIOSubVariableLocation(path, 2, currentLocation);
757}
758
759static int getExplicitLocationFromPath (const std::vector<VariablePathComponent>& path)
760{
761 const glu::VariableDeclaration* varDecl = (path[0].isInterfaceBlock()) ? (path[1].getDeclaration()) : (path[0].getDeclaration());
762
763 if (path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM)
764 {
765 // inside uniform block
766 return -1;
767 }
768 else if (path.front().isInterfaceBlock() && (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN || path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT))
769 {
770 // inside ioblock
771 return getIOBlockVariableLocation(path);
772 }
773 else if (varDecl->storage == glu::STORAGE_UNIFORM)
774 {
775 // default block uniform
776 return varDecl->layout.location;
777 }
778 else if (varDecl->storage == glu::STORAGE_IN || varDecl->storage == glu::STORAGE_OUT)
779 {
780 // default block input/output
781 return getIOSubVariableLocation(path, 1, varDecl->layout.location);
782 }
783 else
784 {
785 DE_ASSERT(false);
786 return -1;
787 }
788}
789
790void LocationValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
791{
792 const bool isAtomicCounterUniform = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
793 const bool isUniformBlockVariable = path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM;
794 const bool isVertexShader = m_filter.getShaderTypeFilter() == glu::SHADERTYPE_VERTEX;
795 const bool isFragmentShader = m_filter.getShaderTypeFilter() == glu::SHADERTYPE_FRAGMENT;
796 const bool isInputVariable = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN) : (path.front().getDeclaration()->storage == glu::STORAGE_IN);
797 const bool isOutputVariable = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT) : (path.front().getDeclaration()->storage == glu::STORAGE_OUT);
798 const int explicitLayoutLocation = getExplicitLocationFromPath(path);
799
800 bool expectLocation;
801 std::string reasonStr;
802
803 if (isAtomicCounterUniform)
804 {
805 expectLocation = false;
806 reasonStr = "Atomic counter uniforms have effective location of -1";
807 }
808 else if (isUniformBlockVariable)
809 {
810 expectLocation = false;
811 reasonStr = "Uniform block variables have effective location of -1";
812 }
813 else if (isInputVariable && !isVertexShader && explicitLayoutLocation == -1)
814 {
815 expectLocation = false;
816 reasonStr = "Inputs (except for vertex shader inputs) not declared with a location layout qualifier have effective location of -1";
817 }
818 else if (isOutputVariable && !isFragmentShader && explicitLayoutLocation == -1)
819 {
820 expectLocation = false;
821 reasonStr = "Outputs (except for fragment shader outputs) not declared with a location layout qualifier have effective location of -1";
822 }
823 else
824 {
825 expectLocation = true;
826 }
827
828 if (!expectLocation)
829 {
830 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform location, expecting -1. (" << reasonStr << ")" << tcu::TestLog::EndMessage;
831
832 if (propValue != -1)
833 {
834 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
835 setError("resource location invalid");
836 }
837 }
838 else
839 {
840 bool locationOk;
841
842 if (explicitLayoutLocation == -1)
843 {
844 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting a valid location" << tcu::TestLog::EndMessage;
845 locationOk = (propValue != -1);
846 }
847 else
848 {
849 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting " << explicitLayoutLocation << tcu::TestLog::EndMessage;
850 locationOk = (propValue == explicitLayoutLocation);
851 }
852
853 if (!locationOk)
854 {
855 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
856 setError("resource location invalid");
857 }
858 else
859 {
860 const VariablePathComponent nullComponent;
861 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
862 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
863
864 const glw::Functions& gl = m_renderContext.getFunctions();
865 const glu::Storage storage = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
866 const glw::GLenum interface = getProgramDefaultBlockInterfaceFromStorage(storage);
867
868 m_testCtx.getLog() << tcu::TestLog::Message << "Comparing location to the values returned by GetProgramResourceLocation" << tcu::TestLog::EndMessage;
869
870 // Test all bottom-level array elements
871 if (isArray)
872 {
873 const std::string arrayResourceName = (resource.size() > 3) ? (resource.substr(0, resource.size() - 3)) : (""); // chop "[0]"
874
875 for (int arrayElementNdx = 0; arrayElementNdx < enclosingcomponent.getVariableType()->getArraySize(); ++arrayElementNdx)
876 {
877 const std::string elementResourceName = arrayResourceName + "[" + de::toString(arrayElementNdx) + "]";
878 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, elementResourceName.c_str());
879
880 if (location != propValue+arrayElementNdx)
881 {
882 m_testCtx.getLog()
883 << tcu::TestLog::Message
884 << "\tError, getProgramResourceLocation (resource=\"" << elementResourceName << "\") returned location " << location
885 << ", expected " << (propValue+arrayElementNdx)
886 << tcu::TestLog::EndMessage;
887 setError("resource location invalid");
888 }
889 else
890 m_testCtx.getLog() << tcu::TestLog::Message << "\tLocation of \"" << elementResourceName << "\":\t" << location << tcu::TestLog::EndMessage;
891 }
892 }
893 else
894 {
895 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, resource.c_str());
896
897 if (location != propValue)
898 {
899 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, getProgramResourceLocation returned location " << location << ", expected " << propValue << tcu::TestLog::EndMessage;
900 setError("resource location invalid");
901 }
902 }
903
904 }
905 }
906}
907
908class VariableNameLengthValidator : public SingleVariableValidator
909{
910public:
911 VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
912 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
913 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const;
914 void validateNameLength (const std::string& resource, glw::GLint propValue) const;
915};
916
917VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
918 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter)
919{
920}
921
922void VariableNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
923{
924 DE_UNREF(path);
925 validateNameLength(resource, propValue);
926}
927
928void VariableNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue) const
929{
930 validateNameLength(resource, propValue);
931}
932
933void VariableNameLengthValidator::validateNameLength (const std::string& resource, glw::GLint propValue) const
934{
935 const int expected = (int)resource.length() + 1; // includes null byte
936 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)resource.length() << " for \"" << resource << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
937
938 if (propValue != expected)
939 {
940 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
941 setError("name length invalid");
942 }
943}
944
945class OffsetValidator : public SingleVariableValidator
946{
947public:
948 OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
949 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
950};
951
952OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
953 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter)
954{
955}
956
957void OffsetValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
958{
959 const bool isAtomicCounterUniform = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
960 const bool isBufferBackedBlockStorage = path.front().isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(path.front().getInterfaceBlock()->storage);
961
962 DE_UNREF(resource);
963
964 if (!isAtomicCounterUniform && !isBufferBackedBlockStorage)
965 {
966 // Not buffer backed
967 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting -1" << tcu::TestLog::EndMessage;
968
969 if (propValue != -1)
970 {
971 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
972 setError("offset invalid");
973 }
974 }
975 else
976 {
977 // Expect a valid offset
978 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting a valid offset" << tcu::TestLog::EndMessage;
979
980 if (propValue < 0)
981 {
982 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
983 setError("offset invalid");
984 }
985 }
986}
987
988class VariableReferencedByShaderValidator : public PropValidator
989{
990public:
991 VariableReferencedByShaderValidator (Context& context, const VariableSearchFilter& searchFilter);
992
993 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
994 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const;
995
996private:
997 const VariableSearchFilter m_filter;
998};
999
1000VariableReferencedByShaderValidator::VariableReferencedByShaderValidator (Context& context, const VariableSearchFilter& searchFilter)
1001 : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER)
1002 , m_filter (searchFilter)
1003{
1004}
1005
1006std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1007{
1008 return de::toString(glu::getBooleanStr(propVal));
1009}
1010
1011void VariableReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const
1012{
1013 std::vector<VariablePathComponent> dummyPath;
1014 const bool referencedByShader = findProgramVariablePathByPathName(dummyPath, program, resource, m_filter);
1015
1016 m_testCtx.getLog()
1017 << tcu::TestLog::Message
1018 << "Verifying referenced by " << glu::getShaderTypeName(m_filter.getShaderTypeFilter()) << " shader, expecting "
1019 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1020 << tcu::TestLog::EndMessage;
1021
1022 if (propValue != ((referencedByShader) ? (1) : (0)))
1023 {
1024 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_filter.getShaderTypeFilter()) << ", got " << propValue << tcu::TestLog::EndMessage;
1025 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_filter.getShaderTypeFilter())) + " invalid");
1026 }
1027}
1028
1029class BlockNameLengthValidator : public SingleBlockValidator
1030{
1031public:
1032 BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1033 void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue) const;
1034};
1035
1036BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1037 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter)
1038{
1039}
1040
1041void BlockNameLengthValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue) const
1042{
1043 DE_UNREF(instanceIndex);
1044 DE_UNREF(block);
1045
1046 const int expected = (int)resource.length() + 1; // includes null byte
1047 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)resource.length() << " for \"" << resource << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
1048
1049 if (propValue != expected)
1050 {
1051 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1052 setError("name length invalid");
1053 }
1054}
1055
1056class BufferBindingValidator : public SingleBlockValidator
1057{
1058public:
1059 BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
1060 void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue) const;
1061};
1062
1063BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
1064 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter)
1065{
1066}
1067
1068void BufferBindingValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue) const
1069{
1070 DE_UNREF(resource);
1071
1072 if (block.layout.binding != -1)
1073 {
1074 int flatIndex = 0;
1075 int dimensionSize = 1;
1076
1077 for (int dimensionNdx = (int)(block.dimensions.size()) - 1; dimensionNdx >= 0; --dimensionNdx)
1078 {
1079 flatIndex += dimensionSize * instanceIndex[dimensionNdx];
1080 dimensionSize *= block.dimensions[dimensionNdx];
1081 }
1082
1083 const int expected = (block.dimensions.empty()) ? (block.layout.binding) : (block.layout.binding + flatIndex);
1084 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block binding, expecting " << expected << tcu::TestLog::EndMessage;
1085
1086 if (propValue != expected)
1087 {
1088 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1089 setError("buffer binding invalid");
1090 }
1091 }
1092 else
1093 {
1094 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying buffer binding, expecting a valid binding" << tcu::TestLog::EndMessage;
1095
1096 if (propValue < 0)
1097 {
1098 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1099 setError("buffer binding invalid");
1100 }
1101 }
1102}
1103
1104class BlockReferencedByShaderValidator : public PropValidator
1105{
1106public:
1107 BlockReferencedByShaderValidator (Context& context, const VariableSearchFilter& searchFilter);
1108
1109 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
1110 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const;
1111
1112private:
1113 const VariableSearchFilter m_filter;
1114};
1115
1116BlockReferencedByShaderValidator::BlockReferencedByShaderValidator (Context& context, const VariableSearchFilter& searchFilter)
1117 : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER)
1118 , m_filter (searchFilter)
1119{
1120}
1121
1122std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1123{
1124 return de::toString(glu::getBooleanStr(propVal));
1125}
1126
1127void BlockReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const
1128{
1129 const std::string blockName = glu::parseVariableName(resource.c_str());
1130 bool referencedByShader = false;
1131
1132 DE_UNREF(resource);
1133
1134 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1135 {
1136 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1137 if (!m_filter.matchesFilter(shader))
1138 continue;
1139
1140 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1141 {
1142 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1143
1144 if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
1145 referencedByShader = true;
1146 }
1147 }
1148
1149 m_testCtx.getLog()
1150 << tcu::TestLog::Message
1151 << "Verifying referenced by " << glu::getShaderTypeName(m_filter.getShaderTypeFilter()) << " shader, expecting "
1152 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1153 << tcu::TestLog::EndMessage;
1154
1155 if (propValue != ((referencedByShader) ? (1) : (0)))
1156 {
1157 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_filter.getShaderTypeFilter()) << ", got " << propValue << tcu::TestLog::EndMessage;
1158 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_filter.getShaderTypeFilter())) + " invalid");
1159 }
1160}
1161
1162class TopLevelArraySizeValidator : public SingleVariableValidator
1163{
1164public:
1165 TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1166 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
1167};
1168
1169TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1170 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter)
1171{
1172}
1173
1174void TopLevelArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
1175{
1176 int expected;
1177 std::string reason;
1178
1179 DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1180 DE_UNREF(resource);
1181
1182 if (!path[1].getDeclaration()->varType.isArrayType())
1183 {
1184 expected = 1;
1185 reason = "Top-level block member is not an array";
1186 }
1187 else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1188 {
1189 expected = 1;
1190 reason = "Top-level block member is not an array of an aggregate type";
1191 }
1192 else if (path[1].getDeclaration()->varType.getArraySize() == glu::VarType::UNSIZED_ARRAY)
1193 {
1194 expected = 0;
1195 reason = "Top-level block member is an unsized top-level array";
1196 }
1197 else
1198 {
1199 expected = path[1].getDeclaration()->varType.getArraySize();
1200 reason = "Top-level block member is a sized top-level array";
1201 }
1202
1203 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array size, expecting " << expected << ". (" << reason << ")." << tcu::TestLog::EndMessage;
1204
1205 if (propValue != expected)
1206 {
1207 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array size, got " << propValue << tcu::TestLog::EndMessage;
1208 setError("top level array size invalid");
1209 }
1210}
1211
1212class TopLevelArrayStrideValidator : public SingleVariableValidator
1213{
1214public:
1215 TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1216 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const;
1217};
1218
1219TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1220 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter)
1221{
1222}
1223
1224void TopLevelArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue) const
1225{
1226 DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1227 DE_UNREF(resource);
1228
1229 if (!path[1].getDeclaration()->varType.isArrayType())
1230 {
1231 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array)." << tcu::TestLog::EndMessage;
1232
1233 if (propValue != 0)
1234 {
1235 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1236 setError("top level array stride invalid");
1237 }
1238 }
1239 else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1240 {
1241 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array of an aggregate type)." << tcu::TestLog::EndMessage;
1242
1243 if (propValue != 0)
1244 {
1245 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1246 setError("top level array stride invalid");
1247 }
1248 }
1249 else
1250 {
1251 const int minimumStride = getVarTypeSize(path[1].getDeclaration()->varType.getElementType());
1252
1253 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting greater or equal to " << minimumStride << "." << tcu::TestLog::EndMessage;
1254
1255 if (propValue < minimumStride)
1256 {
1257 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1258 setError("top level array stride invalid");
1259 }
1260 }
1261}
1262
1263class TransformFeedbackArraySizeValidator : public PropValidator
1264{
1265public:
1266 TransformFeedbackArraySizeValidator (Context& context);
1267 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const;
1268};
1269
1270TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context)
1271 : PropValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE)
1272{
1273}
1274
1275void TransformFeedbackArraySizeValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue) const
1276{
1277 int arraySize = 0;
1278
1279 if (deStringBeginsWith(resource.c_str(), "gl_"))
1280 {
1281 if (resource == "gl_Position")
1282 arraySize = 1;
1283 else
1284 DE_ASSERT(false);
1285 }
1286 else if (!stringEndsWith(resource, "[0]"))
1287 {
1288 // user-defined non-array. Just check it exists
1289 std::vector<VariablePathComponent> path;
1290 if (!findProgramVariablePathByPathName(path, program, resource, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT)))
1291 {
1292 DE_ASSERT(false);
1293 return;
1294 }
1295
1296 arraySize = 1;
1297 }
1298 else
1299 {
1300 bool generatorFound = false;
1301
1302 // user-defined, array or array element. Find the generating varying declaration
1303 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1304 {
1305 const std::string varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
1306 std::vector<VariablePathComponent> path;
1307 std::vector<std::string> resources;
1308
1309 if (!findProgramVariablePathByPathName(path, program, varyingName, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT)))
1310 {
1311 // program does not contain feedback varying, not valid program
1312 DE_ASSERT(false);
1313 return;
1314 }
1315
1316 generateVariableTypeResourceNames(resources, varyingName, *path.back().getVariableType(), false);
1317
1318 if (de::contains(resources.begin(), resources.end(), resource))
1319 {
1320 arraySize = (path.back().getVariableType()->isArrayType()) ? (path.back().getVariableType()->getArraySize()) : (1);
1321 generatorFound = true;
1322 break;
1323 }
1324 }
1325
1326 if (!generatorFound)
1327 {
1328 DE_ASSERT(false);
1329 return;
1330 }
1331 }
1332
1333 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1334 if (arraySize != propValue)
1335 {
1336 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1337 setError("resource array size invalid");
1338 }
1339}
1340
1341} // anonymous
1342
1343ProgramResourceQueryTestTarget::ProgramResourceQueryTestTarget (ProgramInterface interface_, deUint32 propFlags_)
1344 : interface(interface_)
1345 , propFlags(propFlags_)
1346{
1347 switch (interface)
1348 {
1349 case PROGRAMINTERFACE_UNIFORM: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK) == propFlags); break;
1350 case PROGRAMINTERFACE_UNIFORM_BLOCK: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_BLOCK_INTERFACE_MASK) == propFlags); break;
1351 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_SHADER_STORAGE_BLOCK_MASK) == propFlags); break;
1352 case PROGRAMINTERFACE_PROGRAM_INPUT: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_INPUT_MASK) == propFlags); break;
1353 case PROGRAMINTERFACE_PROGRAM_OUTPUT: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_OUTPUT_MASK) == propFlags); break;
1354 case PROGRAMINTERFACE_BUFFER_VARIABLE: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK) == propFlags); break;
1355 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_TRANSFORM_FEEDBACK_VARYING_MASK) == propFlags); break;
1356
1357 default:
1358 DE_ASSERT(false);
1359 }
1360}
1361
1362ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget)
1363 : TestCase (context, name, description)
1364 , m_queryTarget (queryTarget)
1365{
1366}
1367
1368ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void)
1369{
1370}
1371
1372ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const
1373{
1374 return m_queryTarget.interface;
1375}
1376
1377static glw::GLenum getGLInterfaceEnumValue (ProgramInterface interface)
1378{
1379 switch (interface)
1380 {
1381 case PROGRAMINTERFACE_UNIFORM: return GL_UNIFORM;
1382 case PROGRAMINTERFACE_UNIFORM_BLOCK: return GL_UNIFORM_BLOCK;
1383 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER: return GL_ATOMIC_COUNTER_BUFFER;
1384 case PROGRAMINTERFACE_PROGRAM_INPUT: return GL_PROGRAM_INPUT;
1385 case PROGRAMINTERFACE_PROGRAM_OUTPUT: return GL_PROGRAM_OUTPUT;
1386 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: return GL_TRANSFORM_FEEDBACK_VARYING;
1387 case PROGRAMINTERFACE_BUFFER_VARIABLE: return GL_BUFFER_VARIABLE;
1388 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: return GL_SHADER_STORAGE_BLOCK;
1389 default:
1390 DE_ASSERT(false);
1391 return 0;
1392 };
1393}
1394
1395static void 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)
1396{
1397 const glw::GLenum glInterface = getGLInterfaceEnumValue(interface);
1398 glw::GLuint resourceNdx;
1399 glw::GLint written = -1;
1400 std::vector<glw::GLint> propValues (props.size() + 1, -2); // prefill result buffer with an invalid value. -1 might be valid sometimes, avoid it. Make buffer one larger to allow detection of too many return values
1401
1402 DE_ASSERT(props.size() == validators.size());
1403
1404 // query
1405
1406 resourceNdx = gl.getProgramResourceIndex(programID, glInterface, targetResourceName);
1407 GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
1408
1409 if (resourceNdx == GL_INVALID_INDEX)
1410 {
1411 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceIndex returned GL_INVALID_INDEX for \"" << targetResourceName << "\"" << tcu::TestLog::EndMessage;
1412 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource");
1413
1414 // try to recover but keep the test result as failure
1415 {
1416 const std::string resourceName = std::string(targetResourceName);
1417 std::string simplifiedResourceName;
1418
1419 if (stringEndsWith(resourceName, "[0]"))
1420 simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3);
1421 else
1422 {
1423 const size_t lastMember = resourceName.find_last_of('.');
1424 if (lastMember != std::string::npos)
1425 simplifiedResourceName = resourceName.substr(0, lastMember);
1426 }
1427
1428 if (simplifiedResourceName.empty())
1429 return;
1430
1431 resourceNdx = gl.getProgramResourceIndex(programID, glInterface, simplifiedResourceName.c_str());
1432 GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
1433
1434 if (resourceNdx == GL_INVALID_INDEX)
1435 return;
1436
1437 testCtx.getLog() << tcu::TestLog::Message << "\tResource not found, continuing anyway using index obtained for resource \"" << simplifiedResourceName << "\"" << tcu::TestLog::EndMessage;
1438 }
1439 }
1440
1441 gl.getProgramResourceiv(programID, glInterface, resourceNdx, (int)props.size(), &props[0], (int)propValues.size(), &written, &propValues[0]);
1442 GLU_EXPECT_NO_ERROR(gl.getError(), "get props");
1443
1444 if (written != (int)props.size())
1445 {
1446 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv returned unexpected number of values, expected " << (int)props.size() << ", got " << written << tcu::TestLog::EndMessage;
1447 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
1448 return;
1449 }
1450
1451 if (propValues.back() != -2)
1452 {
1453 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv post write buffer guard value was modified, too many return values" << tcu::TestLog::EndMessage;
1454 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
1455 return;
1456 }
1457 propValues.pop_back();
1458 DE_ASSERT(validators.size() == propValues.size());
1459
1460 // log
1461
1462 {
1463 tcu::MessageBuilder message(&testCtx.getLog());
1464 message << "For resource index " << resourceNdx << " (\"" << targetResourceName << "\") got following properties:\n";
1465
1466 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
1467 message << "\t" << glu::getProgramResourcePropertyName(props[propNdx]) << ":\t" << validators[propNdx]->getHumanReadablePropertyString(propValues[propNdx]) << "\n";
1468
1469 message << tcu::TestLog::EndMessage;
1470 }
1471
1472 // validate
1473
1474 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
1475 validators[propNdx]->validate(programDefinition, targetResourceName, propValues[propNdx]);
1476}
1477
1478ProgramInterfaceQueryTestCase::IterateResult ProgramInterfaceQueryTestCase::iterate (void)
1479{
1480 struct TestProperty
1481 {
1482 glw::GLenum prop;
1483 const PropValidator* validator;
1484 };
1485
1486 const ProgramInterfaceDefinition::Program* programDefinition = getProgramDefinition();
1487 const std::vector<std::string> targetResources = getQueryTargetResources();
1488 glu::ShaderProgram program (m_context.getRenderContext(), generateProgramInterfaceProgramSources(programDefinition));
1489
1490 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1491
1492 DE_ASSERT(programDefinition->isValid());
1493
1494 // Log program
1495 {
1496 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
1497
1498 // Feedback varyings
1499 if (!programDefinition->getTransformFeedbackVaryings().empty())
1500 {
1501 tcu::MessageBuilder builder(&m_testCtx.getLog());
1502 builder << "Transform feedback varyings: {";
1503 for (int ndx = 0; ndx < (int)programDefinition->getTransformFeedbackVaryings().size(); ++ndx)
1504 {
1505 if (ndx)
1506 builder << ", ";
1507 builder << "\"" << programDefinition->getTransformFeedbackVaryings()[ndx] << "\"";
1508 }
1509 builder << "}" << tcu::TestLog::EndMessage;
1510 }
1511
1512 m_testCtx.getLog() << program;
1513 if (!program.isOk())
1514 {
1515 m_testCtx.getLog() << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits" << tcu::TestLog::EndMessage;
1516 checkProgramResourceUsage(programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1517
1518 // within limits
1519 throw tcu::TestError("could not build program");
1520 }
1521 }
1522
1523 // Check interface props
1524
1525 switch (m_queryTarget.interface)
1526 {
1527 case PROGRAMINTERFACE_UNIFORM:
1528 {
1529 const VariableSearchFilter uniformFilter (glu::SHADERTYPE_LAST, glu::STORAGE_UNIFORM);
1530
1531 const TypeValidator typeValidator (m_context, program.getProgram(), uniformFilter);
1532 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), uniformFilter);
1533 const ArrayStrideValidator arrayStrideValidator (m_context, program.getProgram(), uniformFilter);
1534 const BlockIndexValidator blockIndexValidator (m_context, program.getProgram(), uniformFilter);
1535 const IsRowMajorValidator isRowMajorValidator (m_context, program.getProgram(), uniformFilter);
1536 const MatrixStrideValidator matrixStrideValidator (m_context, program.getProgram(), uniformFilter);
1537 const AtomicCounterBufferIndexVerifier atomicCounterBufferIndexVerifier (m_context, program.getProgram(), uniformFilter);
1538 const LocationValidator locationValidator (m_context, program.getProgram(), uniformFilter);
1539 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), uniformFilter);
1540 const OffsetValidator offsetVerifier (m_context, program.getProgram(), uniformFilter);
1541 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_UNIFORM));
1542 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_FRAGMENT, glu::STORAGE_UNIFORM));
1543 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_COMPUTE, glu::STORAGE_UNIFORM));
1544
1545 const TestProperty allProperties[] =
1546 {
1547 { GL_ARRAY_SIZE, &arraySizeValidator },
1548 { GL_ARRAY_STRIDE, &arrayStrideValidator },
1549 { GL_ATOMIC_COUNTER_BUFFER_INDEX, &atomicCounterBufferIndexVerifier },
1550 { GL_BLOCK_INDEX, &blockIndexValidator },
1551 { GL_IS_ROW_MAJOR, &isRowMajorValidator },
1552 { GL_LOCATION, &locationValidator },
1553 { GL_MATRIX_STRIDE, &matrixStrideValidator },
1554 { GL_NAME_LENGTH, &nameLengthValidator },
1555 { GL_OFFSET, &offsetVerifier },
1556 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
1557 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
1558 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
1559 { GL_TYPE, &typeValidator },
1560 };
1561
1562 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
1563 {
1564 const tcu::ScopedLogSection section (m_testCtx.getLog(), "UniformResource", "Uniform resource \"" + targetResources[targetResourceNdx] + "\"");
1565 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1566 std::vector<glw::GLenum> props;
1567 std::vector<const PropValidator*> validators;
1568
1569 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
1570 {
1571 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
1572 allProperties[propNdx].validator->isSupported())
1573 {
1574 props.push_back(allProperties[propNdx].prop);
1575 validators.push_back(allProperties[propNdx].validator);
1576 }
1577 }
1578
1579 DE_ASSERT(!props.empty());
1580
1581 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
1582 }
1583
1584 break;
1585 }
1586
1587 case PROGRAMINTERFACE_UNIFORM_BLOCK:
1588 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1589 {
1590 const glu::Storage storage = (m_queryTarget.interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
1591 const VariableSearchFilter blockFilter (glu::SHADERTYPE_LAST, storage);
1592
1593 const BlockNameLengthValidator nameLengthValidator (m_context, program.getProgram(), blockFilter);
1594 const BlockReferencedByShaderValidator referencedByVertexVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_VERTEX, storage));
1595 const BlockReferencedByShaderValidator referencedByFragmentVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_FRAGMENT, storage));
1596 const BlockReferencedByShaderValidator referencedByComputeVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_COMPUTE, storage));
1597 const BufferBindingValidator bufferBindingValidator (m_context, program.getProgram(), blockFilter);
1598
1599 const TestProperty allProperties[] =
1600 {
1601 { GL_NAME_LENGTH, &nameLengthValidator },
1602 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
1603 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
1604 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
1605 { GL_BUFFER_BINDING, &bufferBindingValidator },
1606 };
1607
1608 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
1609 {
1610 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BlockResource", "Interface block \"" + targetResources[targetResourceNdx] + "\"");
1611 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1612 std::vector<glw::GLenum> props;
1613 std::vector<const PropValidator*> validators;
1614
1615 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
1616 {
1617 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
1618 allProperties[propNdx].validator->isSupported())
1619 {
1620 props.push_back(allProperties[propNdx].prop);
1621 validators.push_back(allProperties[propNdx].validator);
1622 }
1623 }
1624
1625 DE_ASSERT(!props.empty());
1626
1627 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
1628 }
1629
1630 break;
1631 }
1632
1633 case PROGRAMINTERFACE_PROGRAM_INPUT:
1634 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1635 {
1636 const glu::Storage storage = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
1637 const glu::ShaderType shaderType = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (programDefinition->getFirstStage()) : (programDefinition->getLastStage());
1638 const VariableSearchFilter variableFilter (shaderType, storage);
1639
1640 const TypeValidator typeValidator (m_context, program.getProgram(), variableFilter);
1641 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), variableFilter);
1642 const LocationValidator locationValidator (m_context, program.getProgram(), variableFilter);
1643 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), variableFilter);
1644 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, VariableSearchFilter::intersection(VariableSearchFilter(glu::SHADERTYPE_VERTEX, storage), variableFilter));
1645 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, VariableSearchFilter::intersection(VariableSearchFilter(glu::SHADERTYPE_FRAGMENT, storage), variableFilter));
1646 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, VariableSearchFilter::intersection(VariableSearchFilter(glu::SHADERTYPE_COMPUTE, storage), variableFilter));
1647
1648 const TestProperty allProperties[] =
1649 {
1650 { GL_ARRAY_SIZE, &arraySizeValidator },
1651 { GL_LOCATION, &locationValidator },
1652 { GL_NAME_LENGTH, &nameLengthValidator },
1653 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
1654 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
1655 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
1656 { GL_TYPE, &typeValidator },
1657 };
1658
1659 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
1660 {
1661 const std::string resourceInterfaceName = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? ("Input") : ("Output");
1662 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BlockResource", resourceInterfaceName + " resource \"" + targetResources[targetResourceNdx] + "\"");
1663 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1664 std::vector<glw::GLenum> props;
1665 std::vector<const PropValidator*> validators;
1666
1667 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
1668 {
1669 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
1670 allProperties[propNdx].validator->isSupported())
1671 {
1672 props.push_back(allProperties[propNdx].prop);
1673 validators.push_back(allProperties[propNdx].validator);
1674 }
1675 }
1676
1677 DE_ASSERT(!props.empty());
1678
1679 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
1680 }
1681
1682 break;
1683 }
1684
1685 case PROGRAMINTERFACE_BUFFER_VARIABLE:
1686 {
1687 const VariableSearchFilter variableFilter (glu::SHADERTYPE_LAST, glu::STORAGE_BUFFER);
1688
1689 const TypeValidator typeValidator (m_context, program.getProgram(), variableFilter);
1690 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), variableFilter);
1691 const ArrayStrideValidator arrayStrideValidator (m_context, program.getProgram(), variableFilter);
1692 const BlockIndexValidator blockIndexValidator (m_context, program.getProgram(), variableFilter);
1693 const IsRowMajorValidator isRowMajorValidator (m_context, program.getProgram(), variableFilter);
1694 const MatrixStrideValidator matrixStrideValidator (m_context, program.getProgram(), variableFilter);
1695 const OffsetValidator offsetValidator (m_context, program.getProgram(), variableFilter);
1696 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), variableFilter);
1697 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_BUFFER));
1698 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_FRAGMENT, glu::STORAGE_BUFFER));
1699 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, VariableSearchFilter(glu::SHADERTYPE_COMPUTE, glu::STORAGE_BUFFER));
1700 const TopLevelArraySizeValidator topLevelArraySizeValidator (m_context, program.getProgram(), variableFilter);
1701 const TopLevelArrayStrideValidator topLevelArrayStrideValidator (m_context, program.getProgram(), variableFilter);
1702
1703 const TestProperty allProperties[] =
1704 {
1705 { GL_ARRAY_SIZE, &arraySizeValidator },
1706 { GL_ARRAY_STRIDE, &arrayStrideValidator },
1707 { GL_BLOCK_INDEX, &blockIndexValidator },
1708 { GL_IS_ROW_MAJOR, &isRowMajorValidator },
1709 { GL_MATRIX_STRIDE, &matrixStrideValidator },
1710 { GL_NAME_LENGTH, &nameLengthValidator },
1711 { GL_OFFSET, &offsetValidator },
1712 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
1713 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
1714 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
1715 { GL_TOP_LEVEL_ARRAY_SIZE, &topLevelArraySizeValidator },
1716 { GL_TOP_LEVEL_ARRAY_STRIDE, &topLevelArrayStrideValidator },
1717 { GL_TYPE, &typeValidator },
1718 };
1719
1720 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
1721 {
1722 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BufferVariableResource", "Buffer variable \"" + targetResources[targetResourceNdx] + "\"");
1723 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1724 std::vector<glw::GLenum> props;
1725 std::vector<const PropValidator*> validators;
1726
1727 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
1728 {
1729 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
1730 allProperties[propNdx].validator->isSupported())
1731 {
1732 props.push_back(allProperties[propNdx].prop);
1733 validators.push_back(allProperties[propNdx].validator);
1734 }
1735 }
1736
1737 DE_ASSERT(!props.empty());
1738
1739 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
1740 }
1741
1742 break;
1743 }
1744
1745 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1746 {
1747 const TypeValidator typeValidator (m_context, program.getProgram(), VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT));
1748 const TransformFeedbackArraySizeValidator arraySizeValidator (m_context);
1749 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), VariableSearchFilter(glu::SHADERTYPE_VERTEX, glu::STORAGE_OUT));
1750
1751 const TestProperty allProperties[] =
1752 {
1753 { GL_ARRAY_SIZE, &arraySizeValidator },
1754 { GL_NAME_LENGTH, &nameLengthValidator },
1755 { GL_TYPE, &typeValidator },
1756 };
1757
1758 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
1759 {
1760 const tcu::ScopedLogSection section (m_testCtx.getLog(), "XFBVariableResource", "Transform feedback varying \"" + targetResources[targetResourceNdx] + "\"");
1761 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1762 std::vector<glw::GLenum> props;
1763 std::vector<const PropValidator*> validators;
1764
1765 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
1766 {
1767 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
1768 allProperties[propNdx].validator->isSupported())
1769 {
1770 props.push_back(allProperties[propNdx].prop);
1771 validators.push_back(allProperties[propNdx].validator);
1772 }
1773 }
1774
1775 DE_ASSERT(!props.empty());
1776
1777 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
1778 }
1779
1780 break;
1781 }
1782
1783 default:
1784 DE_ASSERT(false);
1785 }
1786
1787 return STOP;
1788}
1789
1790static bool checkLimit (glw::GLenum pname, int usage, const glw::Functions& gl, tcu::TestLog& log)
1791{
1792 if (usage > 0)
1793 {
1794 glw::GLint limit = 0;
1795 gl.getIntegerv(pname, &limit);
1796 GLU_EXPECT_NO_ERROR(gl.getError(), "query limits");
1797
1798 log << tcu::TestLog::Message << "\t" << glu::getGettableStateStr(pname) << " = " << limit << ", test requires " << usage << tcu::TestLog::EndMessage;
1799
1800 if (limit < usage)
1801 {
1802 log << tcu::TestLog::Message << "\t\tLimit exceeded" << tcu::TestLog::EndMessage;
1803 return false;
1804 }
1805 }
1806
1807 return true;
1808}
1809
1810static bool checkShaderResourceUsage (const ProgramInterfaceDefinition::Shader* shader, const glw::Functions& gl, tcu::TestLog& log)
1811{
1812 const ProgramInterfaceDefinition::ShaderResourceUsage usage = getShaderResourceUsage(shader);
1813
1814 switch (shader->getType())
1815 {
1816 case glu::SHADERTYPE_VERTEX:
1817 {
1818 const struct
1819 {
1820 glw::GLenum pname;
1821 int usage;
1822 } restrictions[] =
1823 {
1824 { GL_MAX_VERTEX_ATTRIBS, usage.numInputVectors },
1825 { GL_MAX_VERTEX_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
1826 { GL_MAX_VERTEX_UNIFORM_VECTORS, usage.numUniformVectors },
1827 { GL_MAX_VERTEX_UNIFORM_BLOCKS, usage.numUniformBlocks },
1828 { GL_MAX_VERTEX_OUTPUT_COMPONENTS, usage.numOutputComponents },
1829 { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, usage.numSamplers },
1830 { GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
1831 { GL_MAX_VERTEX_ATOMIC_COUNTERS, usage.numAtomicCounters },
1832 { GL_MAX_VERTEX_IMAGE_UNIFORMS, usage.numImages },
1833 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents },
1834 { GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
1835 };
1836
1837 bool allOk = true;
1838
1839 log << tcu::TestLog::Message << "Vertex shader:" << tcu::TestLog::EndMessage;
1840 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
1841 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
1842
1843 return allOk;
1844 }
1845
1846 case glu::SHADERTYPE_FRAGMENT:
1847 {
1848 const struct
1849 {
1850 glw::GLenum pname;
1851 int usage;
1852 } restrictions[] =
1853 {
1854 { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
1855 { GL_MAX_FRAGMENT_UNIFORM_VECTORS, usage.numUniformVectors },
1856 { GL_MAX_FRAGMENT_UNIFORM_BLOCKS, usage.numUniformBlocks },
1857 { GL_MAX_FRAGMENT_INPUT_COMPONENTS, usage.numInputComponents },
1858 { GL_MAX_TEXTURE_IMAGE_UNITS, usage.numSamplers },
1859 { GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
1860 { GL_MAX_FRAGMENT_ATOMIC_COUNTERS, usage.numAtomicCounters },
1861 { GL_MAX_FRAGMENT_IMAGE_UNIFORMS, usage.numImages },
1862 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents },
1863 { GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
1864 };
1865
1866 bool allOk = true;
1867
1868 log << tcu::TestLog::Message << "Fragment shader:" << tcu::TestLog::EndMessage;
1869 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
1870 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
1871
1872 return allOk;
1873 }
1874
1875 case glu::SHADERTYPE_COMPUTE:
1876 {
1877 const struct
1878 {
1879 glw::GLenum pname;
1880 int usage;
1881 } restrictions[] =
1882 {
1883 { GL_MAX_COMPUTE_UNIFORM_BLOCKS, usage.numUniformBlocks },
1884 { GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, usage.numSamplers },
1885 { GL_MAX_COMPUTE_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
1886 { GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
1887 { GL_MAX_COMPUTE_ATOMIC_COUNTERS, usage.numAtomicCounters },
1888 { GL_MAX_COMPUTE_IMAGE_UNIFORMS, usage.numImages },
1889 { GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents },
1890 { GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
1891 };
1892
1893 bool allOk = true;
1894
1895 log << tcu::TestLog::Message << "Compute shader:" << tcu::TestLog::EndMessage;
1896 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
1897 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
1898
1899 return allOk;
1900 }
1901
1902 default:
1903 DE_ASSERT(false);
1904 return false;
1905 }
1906}
1907
1908static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
1909{
1910 const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program);
1911
1912 const struct
1913 {
1914 glw::GLenum pname;
1915 int usage;
1916 } restrictions[] =
1917 {
1918 { GL_MAX_UNIFORM_BUFFER_BINDINGS, usage.uniformBufferMaxBinding+1 },
1919 { GL_MAX_UNIFORM_BLOCK_SIZE, usage.uniformBufferMaxSize },
1920 { GL_MAX_COMBINED_UNIFORM_BLOCKS, usage.numUniformBlocks },
1921 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedVertexUniformComponents },
1922 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedFragmentUniformComponents },
1923 { GL_MAX_VARYING_COMPONENTS, usage.numVaryingComponents },
1924 { GL_MAX_VARYING_VECTORS, usage.numVaryingVectors },
1925 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, usage.numCombinedSamplers },
1926 { GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, usage.numCombinedOutputResources },
1927 { GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, usage.atomicCounterBufferMaxBinding+1 },
1928 { GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, usage.atomicCounterBufferMaxSize },
1929 { GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
1930 { GL_MAX_COMBINED_ATOMIC_COUNTERS, usage.numAtomicCounters },
1931 { GL_MAX_IMAGE_UNITS, usage.maxImageBinding },
1932 { GL_MAX_COMBINED_IMAGE_UNIFORMS, usage.numCombinedImages },
1933 { GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, usage.shaderStorageBufferMaxBinding+1 },
1934 { GL_MAX_SHADER_STORAGE_BLOCK_SIZE, usage.shaderStorageBufferMaxSize },
1935 { GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
1936 { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, usage.numXFBInterleavedComponents },
1937 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, usage.numXFBSeparateAttribs },
1938 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, usage.numXFBSeparateComponents },
1939 };
1940
1941 bool allOk = true;
1942
1943 log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage;
1944 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
1945 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
1946
1947 return allOk;
1948}
1949
1950void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
1951{
1952 bool limitExceeded = false;
1953
1954 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1955 limitExceeded |= !checkShaderResourceUsage(program->getShaders()[shaderNdx], gl, log);
1956
1957 limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log);
1958
1959 if (limitExceeded)
1960 {
1961 log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage;
1962 throw tcu::NotSupportedError("one or more resource limits exceeded");
1963 }
1964}
1965
1966} // Functional
1967} // gles31
1968} // deqp