blob: 604a94abdec64e096dead252441c035798eb523c [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 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -080061 case glu::STORAGE_IN:
62 case glu::STORAGE_PATCH_IN:
63 return GL_PROGRAM_INPUT;
64
65 case glu::STORAGE_OUT:
66 case glu::STORAGE_PATCH_OUT:
67 return GL_PROGRAM_OUTPUT;
68
69 case glu::STORAGE_UNIFORM:
70 return GL_UNIFORM;
71
Jarkko Poyry3c827362014-09-02 11:48:52 +030072 default:
73 DE_ASSERT(false);
74 return 0;
75 }
76}
77
78static bool isBufferBackedInterfaceBlockStorage (glu::Storage storage)
79{
80 return storage == glu::STORAGE_BUFFER || storage == glu::STORAGE_UNIFORM;
81}
82
Jarkko Pöyryc423ce62015-02-12 22:51:46 -080083const char* getRequiredExtensionForStage (glu::ShaderType stage)
84{
85 switch (stage)
86 {
87 case glu::SHADERTYPE_COMPUTE:
88 case glu::SHADERTYPE_VERTEX:
89 case glu::SHADERTYPE_FRAGMENT:
90 return DE_NULL;
91
92 case glu::SHADERTYPE_GEOMETRY:
93 return "GL_EXT_geometry_shader";
94
95 case glu::SHADERTYPE_TESSELLATION_CONTROL:
96 case glu::SHADERTYPE_TESSELLATION_EVALUATION:
97 return "GL_EXT_tessellation_shader";
98
99 default:
100 DE_ASSERT(false);
101 return DE_NULL;
102 }
103}
104
Jarkko Poyry3c827362014-09-02 11:48:52 +0300105static int getTypeSize (glu::DataType type)
106{
107 if (type == glu::TYPE_FLOAT)
108 return 4;
109 else if (type == glu::TYPE_INT || type == glu::TYPE_UINT)
110 return 4;
111 else if (type == glu::TYPE_BOOL)
112 return 4; // uint
113
114 DE_ASSERT(false);
115 return 0;
116}
117
118static int getVarTypeSize (const glu::VarType& type)
119{
120 if (type.isBasicType())
121 {
122 // return in basic machine units
123 return glu::getDataTypeScalarSize(type.getBasicType()) * getTypeSize(glu::getDataTypeScalarType(type.getBasicType()));
124 }
125 else if (type.isStructType())
126 {
127 int size = 0;
128 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
129 size += getVarTypeSize(type.getStructPtr()->getMember(ndx).getType());
130 return size;
131 }
132 else if (type.isArrayType())
133 {
134 // unsized arrays are handled as if they had only one element
135 if (type.getArraySize() == glu::VarType::UNSIZED_ARRAY)
136 return getVarTypeSize(type.getElementType());
137 else
138 return type.getArraySize() * getVarTypeSize(type.getElementType());
139 }
140 else
141 {
142 DE_ASSERT(false);
143 return 0;
144 }
145}
146
147static glu::MatrixOrder getMatrixOrderFromPath (const std::vector<VariablePathComponent>& path)
148{
149 glu::MatrixOrder order = glu::MATRIXORDER_LAST;
150
151 // inherit majority
152 for (int pathNdx = 0; pathNdx < (int)path.size(); ++pathNdx)
153 {
154 glu::MatrixOrder matOrder;
155
156 if (path[pathNdx].isInterfaceBlock())
157 matOrder = path[pathNdx].getInterfaceBlock()->layout.matrixOrder;
158 else if (path[pathNdx].isDeclaration())
159 matOrder = path[pathNdx].getDeclaration()->layout.matrixOrder;
160 else if (path[pathNdx].isVariableType())
161 matOrder = glu::MATRIXORDER_LAST;
162 else
163 {
164 DE_ASSERT(false);
165 return glu::MATRIXORDER_LAST;
166 }
167
168 if (matOrder != glu::MATRIXORDER_LAST)
169 order = matOrder;
170 }
171
172 return order;
173}
174
175class PropValidator
176{
177public:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800178 PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300179
180 virtual std::string getHumanReadablePropertyString (glw::GLint propVal) const;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800181 virtual void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300182
183 bool isSupported (void) const;
184 bool isSelected (deUint32 caseFlags) const;
185
186protected:
187 void setError (const std::string& err) const;
188
189 tcu::TestContext& m_testCtx;
190 const glu::RenderContext& m_renderContext;
191
192private:
193 const glu::ContextInfo& m_contextInfo;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800194 const char* m_extension;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300195 const ProgramResourcePropFlags m_validationProp;
196};
197
198PropValidator::PropValidator (Context& context, ProgramResourcePropFlags validationProp, const char* requiredExtension)
199 : m_testCtx (context.getTestContext())
200 , m_renderContext (context.getRenderContext())
201 , m_contextInfo (context.getContextInfo())
202 , m_extension (requiredExtension)
203 , m_validationProp (validationProp)
204{
205}
206
207std::string PropValidator::getHumanReadablePropertyString (glw::GLint propVal) const
208{
209 return de::toString(propVal);
210}
211
212bool PropValidator::isSupported (void) const
213{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800214 return m_extension == DE_NULL || m_contextInfo.isExtensionSupported(m_extension);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300215}
216
217bool PropValidator::isSelected (deUint32 caseFlags) const
218{
219 return (caseFlags & (deUint32)m_validationProp) != 0;
220}
221
222void PropValidator::setError (const std::string& err) const
223{
224 // don't overwrite earlier errors
225 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
226 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, err.c_str());
227}
228
229class SingleVariableValidator : public PropValidator
230{
231public:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800232 SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300233
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800234 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
235 virtual void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
236 virtual void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300237
238protected:
239 const VariableSearchFilter m_filter;
240 const glw::GLuint m_programID;
241};
242
243SingleVariableValidator::SingleVariableValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
244 : PropValidator (context, validationProp, requiredExtension)
245 , m_filter (filter)
246 , m_programID (programID)
247{
248}
249
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800250void SingleVariableValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300251{
252 std::vector<VariablePathComponent> path;
253
254 if (findProgramVariablePathByPathName(path, program, resource, m_filter))
255 {
256 const glu::VarType* variable = (path.back().isVariableType()) ? (path.back().getVariableType()) : (DE_NULL);
257
258 if (!variable || !variable->isBasicType())
259 {
260 m_testCtx.getLog() << tcu::TestLog::Message << "Error, resource name \"" << resource << "\" refers to a non-basic type." << tcu::TestLog::EndMessage;
261 setError("resource not basic type");
262 }
263 else
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800264 validateSingleVariable(path, resource, propValue, implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300265
266 // finding matching variable in any shader is sufficient
267 return;
268 }
269 else if (deStringBeginsWith(resource.c_str(), "gl_"))
270 {
271 // special case for builtins
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800272 validateBuiltinVariable(resource, propValue, implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300273 return;
274 }
275
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800276 // we are only supplied good names, generated by ourselves
277 DE_ASSERT(false);
278 throw tcu::InternalError("Resource name consistency error");
Jarkko Poyry3c827362014-09-02 11:48:52 +0300279}
280
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800281void SingleVariableValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300282{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800283 DE_UNREF(resource);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300284 DE_UNREF(propValue);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800285 DE_UNREF(implementationName);
286 DE_ASSERT(false);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300287}
288
289class SingleBlockValidator : public PropValidator
290{
291public:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800292 SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300293
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800294 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
295 virtual void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300296
297protected:
298 const VariableSearchFilter m_filter;
299 const glw::GLuint m_programID;
300};
301
302SingleBlockValidator::SingleBlockValidator (Context& context, ProgramResourcePropFlags validationProp, glw::GLuint programID, const VariableSearchFilter& filter, const char* requiredExtension)
303 : PropValidator (context, validationProp, requiredExtension)
304 , m_filter (filter)
305 , m_programID (programID)
306{
307}
308
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800309void SingleBlockValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300310{
311 glu::VarTokenizer tokenizer (resource.c_str());
312 const std::string blockName = tokenizer.getIdentifier();
313 std::vector<int> instanceIndex;
314
315 tokenizer.advance();
316
317 // array index
318 while (tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET)
319 {
320 tokenizer.advance();
321 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_NUMBER);
322
323 instanceIndex.push_back(tokenizer.getNumber());
324
325 tokenizer.advance();
326 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_RIGHT_BRACKET);
327
328 tokenizer.advance();
329 }
330
331 // no trailing garbage
332 DE_ASSERT(tokenizer.getToken() == glu::VarTokenizer::TOKEN_END);
333
334 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
335 {
336 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
337 if (!m_filter.matchesFilter(shader))
338 continue;
339
340 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
341 {
342 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
343
344 if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
345 {
346 // dimensions match
347 DE_ASSERT(instanceIndex.size() == block.dimensions.size());
348
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800349 validateSingleBlock(block, instanceIndex, resource, propValue, implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300350 return;
351 }
352 }
353 }
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800354
355 // we are only supplied good names, generated by ourselves
356 DE_ASSERT(false);
357 throw tcu::InternalError("Resource name consistency error");
Jarkko Poyry3c827362014-09-02 11:48:52 +0300358}
359
360class TypeValidator : public SingleVariableValidator
361{
362public:
363 TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
364
365 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800366 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
367 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300368};
369
370TypeValidator::TypeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800371 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TYPE, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300372{
373}
374
375std::string TypeValidator::getHumanReadablePropertyString (glw::GLint propVal) const
376{
377 return de::toString(glu::getShaderVarTypeStr(propVal));
378}
379
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800380void TypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300381{
382 const glu::VarType* variable = path.back().getVariableType();
383
384 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800385 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300386
Jarkko Poyry8852c822014-09-11 10:20:23 +0300387 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(variable->getBasicType()) << tcu::TestLog::EndMessage;
388
Jarkko Poyry3c827362014-09-02 11:48:52 +0300389 if (variable->getBasicType() != glu::getDataTypeFromGLType(propValue))
390 {
Jarkko Poyry8852c822014-09-11 10:20:23 +0300391 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300392 setError("resource type invalid");
393 }
394}
395
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800396void TypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300397{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800398 DE_UNREF(implementationName);
399
Jarkko Poyry8852c822014-09-11 10:20:23 +0300400 static const struct
Jarkko Poyry3c827362014-09-02 11:48:52 +0300401 {
Jarkko Poyry8852c822014-09-11 10:20:23 +0300402 const char* name;
403 glu::DataType type;
404 } builtins[] =
405 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800406 { "gl_Position", glu::TYPE_FLOAT_VEC4 },
407 { "gl_FragCoord", glu::TYPE_FLOAT_VEC4 },
408 { "gl_PerVertex.gl_Position", glu::TYPE_FLOAT_VEC4 },
409 { "gl_VertexID", glu::TYPE_INT },
410 { "gl_InvocationID", glu::TYPE_INT },
411 { "gl_NumWorkGroups", glu::TYPE_UINT_VEC3 },
412 { "gl_FragDepth", glu::TYPE_FLOAT },
413 { "gl_TessLevelOuter", glu::TYPE_FLOAT },
414 { "gl_TessLevelInner", glu::TYPE_FLOAT },
Jarkko Poyry8852c822014-09-11 10:20:23 +0300415 };
416
417 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
418 {
419 if (resource == builtins[ndx].name)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300420 {
Jarkko Poyry8852c822014-09-11 10:20:23 +0300421 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(builtins[ndx].type) << tcu::TestLog::EndMessage;
422
423 if (glu::getDataTypeFromGLType(propValue) != builtins[ndx].type)
424 {
425 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
426 setError("resource type invalid");
427 }
428 return;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300429 }
430 }
Jarkko Poyry8852c822014-09-11 10:20:23 +0300431
432 DE_ASSERT(false);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300433}
434
435class ArraySizeValidator : public SingleVariableValidator
436{
437public:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800438 ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter);
439
440 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
441 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
442
443private:
444 const int m_unsizedArraySize;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300445};
446
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800447ArraySizeValidator::ArraySizeValidator (Context& context, glw::GLuint programID, int unsizedArraySize, const VariableSearchFilter& filter)
448 : SingleVariableValidator (context, PROGRAMRESOURCEPROP_ARRAY_SIZE, programID, filter, DE_NULL)
449 , m_unsizedArraySize (unsizedArraySize)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300450{
451}
452
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800453void ArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300454{
455 const VariablePathComponent nullComponent;
456 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
457
458 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
459 const bool inUnsizedArray = isArray && (enclosingcomponent.getVariableType()->getArraySize() == glu::VarType::UNSIZED_ARRAY);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800460 const int arraySize = (!isArray) ? (1) : (inUnsizedArray) ? (m_unsizedArraySize) : (enclosingcomponent.getVariableType()->getArraySize());
Jarkko Poyry3c827362014-09-02 11:48:52 +0300461
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800462 DE_ASSERT(arraySize >= 0);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300463 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800464 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300465
466 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
467
468 if (arraySize != propValue)
469 {
470 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
471 setError("resource array size invalid");
472 }
473}
474
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800475void ArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry8852c822014-09-11 10:20:23 +0300476{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800477 DE_UNREF(implementationName);
Jarkko Poyry8852c822014-09-11 10:20:23 +0300478
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800479 static const struct
480 {
481 const char* name;
482 int arraySize;
483 } builtins[] =
484 {
485 { "gl_Position", 1 },
486 { "gl_VertexID", 1 },
487 { "gl_FragCoord", 1 },
488 { "gl_PerVertex.gl_Position", 1 },
489 { "gl_InvocationID", 1 },
490 { "gl_NumWorkGroups", 1 },
491 { "gl_FragDepth", 1 },
492 { "gl_TessLevelOuter", 4 },
493 { "gl_TessLevelInner", 2 },
494 };
495
496 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
497 {
498 if (resource == builtins[ndx].name)
Jarkko Poyry8852c822014-09-11 10:20:23 +0300499 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800500 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << builtins[ndx].arraySize << tcu::TestLog::EndMessage;
501
502 if (propValue != builtins[ndx].arraySize)
503 {
504 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
505 setError("resource array size invalid");
506 }
507 return;
Jarkko Poyry8852c822014-09-11 10:20:23 +0300508 }
509 }
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800510
511 DE_ASSERT(false);
Jarkko Poyry8852c822014-09-11 10:20:23 +0300512}
513
Jarkko Poyry3c827362014-09-02 11:48:52 +0300514class ArrayStrideValidator : public SingleVariableValidator
515{
516public:
517 ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800518
519 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300520};
521
522ArrayStrideValidator::ArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800523 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ARRAY_STRIDE, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300524{
525}
526
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800527void ArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300528{
529 const VariablePathComponent nullComponent;
530 const VariablePathComponent& component = path.back();
531 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
532 const VariablePathComponent& firstComponent = path.front();
533
534 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
535 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
536 const bool isAtomicCounter = glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType()); // atomic counters are buffer backed with a stride of 4 basic machine units
537
538 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800539 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300540
541 // Layout tests will verify layouts of buffer backed arrays properly. Here we just check values are greater or equal to the element size
542 if (isBufferBlock && isArray)
543 {
544 const int elementSize = glu::getDataTypeScalarSize(component.getVariableType()->getBasicType()) * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
545 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting greater or equal to " << elementSize << tcu::TestLog::EndMessage;
546
547 if (propValue < elementSize)
548 {
549 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
550 setError("resource array stride invalid");
551 }
552 }
553 else
554 {
555 // Atomics are buffer backed with stride of 4 even though they are not in an interface block
556 const int arrayStride = (isAtomicCounter && isArray) ? (4) : (!isBufferBlock && !isAtomicCounter) ? (-1) : (0);
557
558 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array stride, expecting " << arrayStride << tcu::TestLog::EndMessage;
559
560 if (arrayStride != propValue)
561 {
562 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
563 setError("resource array stride invalid");
564 }
565 }
566}
567
568class BlockIndexValidator : public SingleVariableValidator
569{
570public:
571 BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800572
573 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300574};
575
576BlockIndexValidator::BlockIndexValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800577 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_BLOCK_INDEX, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300578{
579}
580
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800581void BlockIndexValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300582{
583 const VariablePathComponent& firstComponent = path.front();
584
585 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800586 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300587
588 if (!firstComponent.isInterfaceBlock())
589 {
590 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting -1" << tcu::TestLog::EndMessage;
591
592 if (propValue != -1)
593 {
594 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
595 setError("resource block index invalid");
596 }
597 }
598 else
599 {
600 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block index, expecting a valid block index" << tcu::TestLog::EndMessage;
601
602 if (propValue == -1)
603 {
604 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
605 setError("resource block index invalid");
606 }
607 else
608 {
609 const glw::Functions& gl = m_renderContext.getFunctions();
610 const glw::GLenum interface = (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_UNIFORM) ? (GL_UNIFORM_BLOCK) :
611 (firstComponent.getInterfaceBlock()->storage == glu::STORAGE_BUFFER) ? (GL_SHADER_STORAGE_BLOCK) :
612 (0);
613 glw::GLint written = 0;
614 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
615
616 gl.getProgramResourceName(m_programID, interface, propValue, (int)nameBuffer.size() - 1, &written, &nameBuffer[0]);
617 GLU_EXPECT_NO_ERROR(gl.getError(), "query block name");
618 TCU_CHECK(written < (int)nameBuffer.size());
619 TCU_CHECK(nameBuffer.back() == '\0');
620
621 {
622 const std::string blockName (&nameBuffer[0], written);
623 std::ostringstream expectedName;
624
625 expectedName << firstComponent.getInterfaceBlock()->interfaceName;
626 for (int dimensionNdx = 0; dimensionNdx < (int)firstComponent.getInterfaceBlock()->dimensions.size(); ++dimensionNdx)
627 expectedName << "[0]";
628
629 m_testCtx.getLog() << tcu::TestLog::Message << "Block name with index " << propValue << " is \"" << blockName << "\"" << tcu::TestLog::EndMessage;
630 if (blockName != expectedName.str())
631 {
632 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, expected " << expectedName.str() << tcu::TestLog::EndMessage;
633 setError("resource block index invalid");
634 }
635 }
636 }
637 }
638}
639
640class IsRowMajorValidator : public SingleVariableValidator
641{
642public:
643 IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
644
645 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800646 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300647};
648
649IsRowMajorValidator::IsRowMajorValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800650 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_ROW_MAJOR, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300651{
652}
653
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800654std::string IsRowMajorValidator::getHumanReadablePropertyString (glw::GLint propVal) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300655{
656 return de::toString(glu::getBooleanStr(propVal));
657}
658
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800659void IsRowMajorValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300660{
661 const VariablePathComponent& component = path.back();
662 const VariablePathComponent& firstComponent = path.front();
663
664 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
665 const bool isMatrix = glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
666 const int expected = (isBufferBlock && isMatrix && getMatrixOrderFromPath(path) == glu::MATRIXORDER_ROW_MAJOR) ? (1) : (0);
667
668 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800669 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300670
671 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix order, expecting IS_ROW_MAJOR = " << expected << tcu::TestLog::EndMessage;
672
673 if (propValue != expected)
674 {
675 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
676 setError("resource matrix order invalid");
677 }
678}
679
680class MatrixStrideValidator : public SingleVariableValidator
681{
682public:
683 MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800684
685 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300686};
687
688MatrixStrideValidator::MatrixStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800689 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_MATRIX_STRIDE, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300690{
691}
692
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800693void MatrixStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300694{
695 const VariablePathComponent& component = path.back();
696 const VariablePathComponent& firstComponent = path.front();
697
698 const bool isBufferBlock = firstComponent.isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(firstComponent.getInterfaceBlock()->storage);
699 const bool isMatrix = glu::isDataTypeMatrix(component.getVariableType()->getBasicType());
700
701 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800702 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300703
704 // 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
705 if (isBufferBlock && isMatrix)
706 {
707 const bool columnMajor = getMatrixOrderFromPath(path) != glu::MATRIXORDER_ROW_MAJOR;
708 const int numMajorElements = (columnMajor) ? (glu::getDataTypeMatrixNumRows(component.getVariableType()->getBasicType())) : (glu::getDataTypeMatrixNumColumns(component.getVariableType()->getBasicType()));
709 const int majorSize = numMajorElements * getTypeSize(glu::getDataTypeScalarType(component.getVariableType()->getBasicType()));
710
711 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting greater or equal to " << majorSize << tcu::TestLog::EndMessage;
712
713 if (propValue < majorSize)
714 {
715 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
716 setError("resource matrix stride invalid");
717 }
718 }
719 else
720 {
721 const int matrixStride = (!isBufferBlock && !glu::isDataTypeAtomicCounter(component.getVariableType()->getBasicType())) ? (-1) : (0);
722
723 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying matrix stride, expecting " << matrixStride << tcu::TestLog::EndMessage;
724
725 if (matrixStride != propValue)
726 {
727 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
728 setError("resource matrix stride invalid");
729 }
730 }
731}
732
733class AtomicCounterBufferIndexVerifier : public SingleVariableValidator
734{
735public:
736 AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800737
738 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300739};
740
741AtomicCounterBufferIndexVerifier::AtomicCounterBufferIndexVerifier (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800742 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_ATOMIC_COUNTER_BUFFER_INDEX, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300743{
744}
745
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800746void AtomicCounterBufferIndexVerifier::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300747{
748 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800749 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300750
751 if (!glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType()))
752 {
753 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting -1" << tcu::TestLog::EndMessage;
754
755 if (propValue != -1)
756 {
757 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
758 setError("resource atomic counter buffer index invalid");
759 }
760 }
761 else
762 {
763 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying atomic counter buffer index, expecting a valid index" << tcu::TestLog::EndMessage;
764
765 if (propValue == -1)
766 {
767 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
768 setError("resource atomic counter buffer index invalid");
769 }
770 else
771 {
772 const glw::Functions& gl = m_renderContext.getFunctions();
773 glw::GLint numActiveResources = 0;
774
775 gl.getProgramInterfaceiv(m_programID, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, &numActiveResources);
776 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramInterfaceiv(..., GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, ...)");
777
778 if (propValue >= numActiveResources)
779 {
780 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << ", GL_ACTIVE_RESOURCES = " << numActiveResources << tcu::TestLog::EndMessage;
781 setError("resource atomic counter buffer index invalid");
782 }
783 }
784 }
785}
786
787class LocationValidator : public SingleVariableValidator
788{
789public:
790 LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800791
792 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
793 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +0300794};
795
796LocationValidator::LocationValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800797 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_LOCATION, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300798{
799}
800
801static int getVariableLocationLength (const glu::VarType& type)
802{
803 if (type.isBasicType())
804 {
805 if (glu::isDataTypeMatrix(type.getBasicType()))
806 return glu::getDataTypeMatrixNumColumns(type.getBasicType());
807 else
808 return 1;
809 }
810 else if (type.isStructType())
811 {
812 int size = 0;
813 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx)
814 size += getVariableLocationLength(type.getStructPtr()->getMember(ndx).getType());
815 return size;
816 }
817 else if (type.isArrayType())
818 return type.getArraySize() * getVariableLocationLength(type.getElementType());
819 else
820 {
821 DE_ASSERT(false);
822 return 0;
823 }
824}
825
826static int getIOSubVariableLocation (const std::vector<VariablePathComponent>& path, int startNdx, int currentLocation)
827{
828 if (currentLocation == -1)
829 return -1;
830
831 if (path[startNdx].getVariableType()->isBasicType())
832 return currentLocation;
833 else if (path[startNdx].getVariableType()->isArrayType())
834 return getIOSubVariableLocation(path, startNdx+1, currentLocation);
835 else if (path[startNdx].getVariableType()->isStructType())
836 {
837 for (int ndx = 0; ndx < path[startNdx].getVariableType()->getStructPtr()->getNumMembers(); ++ndx)
838 {
839 if (&path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType() == path[startNdx + 1].getVariableType())
840 return getIOSubVariableLocation(path, startNdx + 1, currentLocation);
841
842 if (currentLocation != -1)
843 currentLocation += getVariableLocationLength(path[startNdx].getVariableType()->getStructPtr()->getMember(ndx).getType());
844 }
845
846 // could not find member, never happens
847 DE_ASSERT(false);
848 return -1;
849 }
850 else
851 {
852 DE_ASSERT(false);
853 return -1;
854 }
855}
856
857static int getIOBlockVariableLocation (const std::vector<VariablePathComponent>& path)
858{
859 const glu::InterfaceBlock* block = path.front().getInterfaceBlock();
860 int currentLocation = block->layout.location;
861
862 // Find the block member
863 for (int memberNdx = 0; memberNdx < (int)block->variables.size(); ++memberNdx)
864 {
Jarkko Poyry3c827362014-09-02 11:48:52 +0300865 if (block->variables[memberNdx].layout.location != -1)
866 currentLocation = block->variables[memberNdx].layout.location;
867
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800868 if (&block->variables[memberNdx] == path[1].getDeclaration())
869 break;
870
871 // unspecified + unspecified = unspecified
872 if (currentLocation != -1)
873 currentLocation += getVariableLocationLength(block->variables[memberNdx].varType);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300874 }
875
876 // Find subtype location in the complex type
877 return getIOSubVariableLocation(path, 2, currentLocation);
878}
879
880static int getExplicitLocationFromPath (const std::vector<VariablePathComponent>& path)
881{
882 const glu::VariableDeclaration* varDecl = (path[0].isInterfaceBlock()) ? (path[1].getDeclaration()) : (path[0].getDeclaration());
883
884 if (path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM)
885 {
886 // inside uniform block
887 return -1;
888 }
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800889 else if (path.front().isInterfaceBlock() && (path.front().getInterfaceBlock()->storage == glu::STORAGE_IN ||
890 path.front().getInterfaceBlock()->storage == glu::STORAGE_OUT ||
891 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_IN ||
892 path.front().getInterfaceBlock()->storage == glu::STORAGE_PATCH_OUT))
Jarkko Poyry3c827362014-09-02 11:48:52 +0300893 {
894 // inside ioblock
895 return getIOBlockVariableLocation(path);
896 }
897 else if (varDecl->storage == glu::STORAGE_UNIFORM)
898 {
899 // default block uniform
900 return varDecl->layout.location;
901 }
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800902 else if (varDecl->storage == glu::STORAGE_IN ||
903 varDecl->storage == glu::STORAGE_OUT ||
904 varDecl->storage == glu::STORAGE_PATCH_IN ||
905 varDecl->storage == glu::STORAGE_PATCH_OUT)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300906 {
907 // default block input/output
908 return getIOSubVariableLocation(path, 1, varDecl->layout.location);
909 }
910 else
911 {
912 DE_ASSERT(false);
913 return -1;
914 }
915}
916
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800917void LocationValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +0300918{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800919 const bool isAtomicCounterUniform = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
920 const bool isUniformBlockVariable = path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_UNIFORM;
921 const bool isVertexShader = m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_VERTEX);
922 const bool isFragmentShader = m_filter.getShaderTypeBits() == (1u << glu::SHADERTYPE_FRAGMENT);
923 const glu::Storage storage = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
924 const bool isInputVariable = (storage == glu::STORAGE_IN || storage == glu::STORAGE_PATCH_IN);
925 const bool isOutputVariable = (storage == glu::STORAGE_OUT || storage == glu::STORAGE_PATCH_OUT);
926 const int explicitLayoutLocation = getExplicitLocationFromPath(path);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300927
Jarkko Pöyryc423ce62015-02-12 22:51:46 -0800928 bool expectLocation;
929 std::string reasonStr;
930
931 DE_UNREF(resource);
Jarkko Poyry3c827362014-09-02 11:48:52 +0300932
933 if (isAtomicCounterUniform)
934 {
935 expectLocation = false;
936 reasonStr = "Atomic counter uniforms have effective location of -1";
937 }
938 else if (isUniformBlockVariable)
939 {
940 expectLocation = false;
941 reasonStr = "Uniform block variables have effective location of -1";
942 }
943 else if (isInputVariable && !isVertexShader && explicitLayoutLocation == -1)
944 {
945 expectLocation = false;
946 reasonStr = "Inputs (except for vertex shader inputs) not declared with a location layout qualifier have effective location of -1";
947 }
948 else if (isOutputVariable && !isFragmentShader && explicitLayoutLocation == -1)
949 {
950 expectLocation = false;
951 reasonStr = "Outputs (except for fragment shader outputs) not declared with a location layout qualifier have effective location of -1";
952 }
953 else
954 {
955 expectLocation = true;
956 }
957
958 if (!expectLocation)
959 {
960 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform location, expecting -1. (" << reasonStr << ")" << tcu::TestLog::EndMessage;
961
962 if (propValue != -1)
963 {
964 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
965 setError("resource location invalid");
966 }
967 }
968 else
969 {
970 bool locationOk;
971
972 if (explicitLayoutLocation == -1)
973 {
974 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting a valid location" << tcu::TestLog::EndMessage;
975 locationOk = (propValue != -1);
976 }
977 else
978 {
979 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting " << explicitLayoutLocation << tcu::TestLog::EndMessage;
980 locationOk = (propValue == explicitLayoutLocation);
981 }
982
983 if (!locationOk)
984 {
985 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
986 setError("resource location invalid");
987 }
988 else
989 {
990 const VariablePathComponent nullComponent;
991 const VariablePathComponent& enclosingcomponent = (path.size() > 1) ? (path[path.size()-2]) : (nullComponent);
992 const bool isArray = enclosingcomponent.isVariableType() && enclosingcomponent.getVariableType()->isArrayType();
993
994 const glw::Functions& gl = m_renderContext.getFunctions();
Jarkko Poyry3c827362014-09-02 11:48:52 +0300995 const glw::GLenum interface = getProgramDefaultBlockInterfaceFromStorage(storage);
996
997 m_testCtx.getLog() << tcu::TestLog::Message << "Comparing location to the values returned by GetProgramResourceLocation" << tcu::TestLog::EndMessage;
998
999 // Test all bottom-level array elements
1000 if (isArray)
1001 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001002 const std::string arrayResourceName = (implementationName.size() > 3) ? (implementationName.substr(0, implementationName.size() - 3)) : (""); // chop "[0]"
Jarkko Poyry3c827362014-09-02 11:48:52 +03001003
1004 for (int arrayElementNdx = 0; arrayElementNdx < enclosingcomponent.getVariableType()->getArraySize(); ++arrayElementNdx)
1005 {
1006 const std::string elementResourceName = arrayResourceName + "[" + de::toString(arrayElementNdx) + "]";
1007 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, elementResourceName.c_str());
1008
1009 if (location != propValue+arrayElementNdx)
1010 {
1011 m_testCtx.getLog()
1012 << tcu::TestLog::Message
1013 << "\tError, getProgramResourceLocation (resource=\"" << elementResourceName << "\") returned location " << location
1014 << ", expected " << (propValue+arrayElementNdx)
1015 << tcu::TestLog::EndMessage;
1016 setError("resource location invalid");
1017 }
1018 else
1019 m_testCtx.getLog() << tcu::TestLog::Message << "\tLocation of \"" << elementResourceName << "\":\t" << location << tcu::TestLog::EndMessage;
1020 }
1021 }
1022 else
1023 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001024 const glw::GLint location = gl.getProgramResourceLocation(m_programID, interface, implementationName.c_str());
Jarkko Poyry3c827362014-09-02 11:48:52 +03001025
1026 if (location != propValue)
1027 {
1028 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, getProgramResourceLocation returned location " << location << ", expected " << propValue << tcu::TestLog::EndMessage;
1029 setError("resource location invalid");
1030 }
1031 }
1032
1033 }
1034 }
1035}
1036
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001037void LocationValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry8852c822014-09-11 10:20:23 +03001038{
1039 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001040 DE_UNREF(implementationName);
Jarkko Poyry8852c822014-09-11 10:20:23 +03001041
1042 // built-ins have no location
1043
1044 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying location, expecting -1" << tcu::TestLog::EndMessage;
1045
1046 if (propValue != -1)
1047 {
1048 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1049 setError("resource location invalid");
1050 }
1051}
1052
Jarkko Poyry3c827362014-09-02 11:48:52 +03001053class VariableNameLengthValidator : public SingleVariableValidator
1054{
1055public:
1056 VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001057
1058 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1059 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1060 void validateNameLength (const std::string& implementationName, glw::GLint propValue) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001061};
1062
1063VariableNameLengthValidator::VariableNameLengthValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001064 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001065{
1066}
1067
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001068void VariableNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001069{
1070 DE_UNREF(path);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001071 DE_UNREF(resource);
1072 validateNameLength(implementationName, propValue);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001073}
1074
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001075void VariableNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001076{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001077 DE_UNREF(resource);
1078 validateNameLength(implementationName, propValue);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001079}
1080
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001081void VariableNameLengthValidator::validateNameLength (const std::string& implementationName, glw::GLint propValue) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001082{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001083 const int expected = (int)implementationName.length() + 1; // includes null byte
1084 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001085
1086 if (propValue != expected)
1087 {
1088 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1089 setError("name length invalid");
1090 }
1091}
1092
1093class OffsetValidator : public SingleVariableValidator
1094{
1095public:
1096 OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001097
1098 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001099};
1100
1101OffsetValidator::OffsetValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001102 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_OFFSET, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001103{
1104}
1105
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001106void OffsetValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001107{
1108 const bool isAtomicCounterUniform = glu::isDataTypeAtomicCounter(path.back().getVariableType()->getBasicType());
1109 const bool isBufferBackedBlockStorage = path.front().isInterfaceBlock() && isBufferBackedInterfaceBlockStorage(path.front().getInterfaceBlock()->storage);
1110
1111 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001112 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001113
1114 if (!isAtomicCounterUniform && !isBufferBackedBlockStorage)
1115 {
1116 // Not buffer backed
1117 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting -1" << tcu::TestLog::EndMessage;
1118
1119 if (propValue != -1)
1120 {
1121 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1122 setError("offset invalid");
1123 }
1124 }
1125 else
1126 {
1127 // Expect a valid offset
1128 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying offset, expecting a valid offset" << tcu::TestLog::EndMessage;
1129
1130 if (propValue < 0)
1131 {
1132 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid offset, got " << propValue << tcu::TestLog::EndMessage;
1133 setError("offset invalid");
1134 }
1135 }
1136}
1137
1138class VariableReferencedByShaderValidator : public PropValidator
1139{
1140public:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001141 VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001142
1143 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001144 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001145
1146private:
1147 const VariableSearchFilter m_filter;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001148 const glu::ShaderType m_shaderType;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001149};
1150
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001151VariableReferencedByShaderValidator::VariableReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1152 : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1153 , m_filter (VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1154 , m_shaderType (shaderType)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001155{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001156 DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001157}
1158
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001159std::string VariableReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001160{
1161 return de::toString(glu::getBooleanStr(propVal));
1162}
1163
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001164void VariableReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001165{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001166 DE_UNREF(implementationName);
1167
Jarkko Poyry3c827362014-09-02 11:48:52 +03001168 std::vector<VariablePathComponent> dummyPath;
1169 const bool referencedByShader = findProgramVariablePathByPathName(dummyPath, program, resource, m_filter);
1170
1171 m_testCtx.getLog()
1172 << tcu::TestLog::Message
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001173 << "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
Jarkko Poyry3c827362014-09-02 11:48:52 +03001174 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1175 << tcu::TestLog::EndMessage;
1176
1177 if (propValue != ((referencedByShader) ? (1) : (0)))
1178 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001179 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1180 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
Jarkko Poyry3c827362014-09-02 11:48:52 +03001181 }
1182}
1183
1184class BlockNameLengthValidator : public SingleBlockValidator
1185{
1186public:
1187 BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001188
1189 void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001190};
1191
1192BlockNameLengthValidator::BlockNameLengthValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001193 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001194{
1195}
1196
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001197void BlockNameLengthValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001198{
1199 DE_UNREF(instanceIndex);
1200 DE_UNREF(block);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001201 DE_UNREF(resource);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001202
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001203 const int expected = (int)implementationName.length() + 1; // includes null byte
1204 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001205
1206 if (propValue != expected)
1207 {
1208 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1209 setError("name length invalid");
1210 }
1211}
1212
1213class BufferBindingValidator : public SingleBlockValidator
1214{
1215public:
1216 BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001217
1218 void validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001219};
1220
1221BufferBindingValidator::BufferBindingValidator (Context& context, const glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001222 : SingleBlockValidator(context, PROGRAMRESOURCEPROP_BUFFER_BINDING, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001223{
1224}
1225
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001226void BufferBindingValidator::validateSingleBlock (const glu::InterfaceBlock& block, const std::vector<int>& instanceIndex, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001227{
1228 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001229 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001230
1231 if (block.layout.binding != -1)
1232 {
1233 int flatIndex = 0;
1234 int dimensionSize = 1;
1235
1236 for (int dimensionNdx = (int)(block.dimensions.size()) - 1; dimensionNdx >= 0; --dimensionNdx)
1237 {
1238 flatIndex += dimensionSize * instanceIndex[dimensionNdx];
1239 dimensionSize *= block.dimensions[dimensionNdx];
1240 }
1241
1242 const int expected = (block.dimensions.empty()) ? (block.layout.binding) : (block.layout.binding + flatIndex);
1243 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying block binding, expecting " << expected << tcu::TestLog::EndMessage;
1244
1245 if (propValue != expected)
1246 {
1247 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1248 setError("buffer binding invalid");
1249 }
1250 }
1251 else
1252 {
1253 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying buffer binding, expecting a valid binding" << tcu::TestLog::EndMessage;
1254
1255 if (propValue < 0)
1256 {
1257 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid buffer binding, got " << propValue << tcu::TestLog::EndMessage;
1258 setError("buffer binding invalid");
1259 }
1260 }
1261}
1262
1263class BlockReferencedByShaderValidator : public PropValidator
1264{
1265public:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001266 BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001267
1268 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001269 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001270
1271private:
1272 const VariableSearchFilter m_filter;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001273 const glu::ShaderType m_shaderType;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001274};
1275
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001276BlockReferencedByShaderValidator::BlockReferencedByShaderValidator (Context& context, glu::ShaderType shaderType, const VariableSearchFilter& searchFilter)
1277 : PropValidator (context, PROGRAMRESOURCEPROP_REFERENCED_BY_SHADER, getRequiredExtensionForStage(shaderType))
1278 , m_filter (VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType), searchFilter))
1279 , m_shaderType (shaderType)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001280{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001281 DE_ASSERT(m_shaderType < glu::SHADERTYPE_LAST);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001282}
1283
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001284std::string BlockReferencedByShaderValidator::getHumanReadablePropertyString (glw::GLint propVal) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001285{
1286 return de::toString(glu::getBooleanStr(propVal));
1287}
1288
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001289void BlockReferencedByShaderValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001290{
1291 const std::string blockName = glu::parseVariableName(resource.c_str());
1292 bool referencedByShader = false;
1293
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001294 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001295
1296 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1297 {
1298 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1299 if (!m_filter.matchesFilter(shader))
1300 continue;
1301
1302 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1303 {
1304 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1305
1306 if (m_filter.matchesFilter(block) && block.interfaceName == blockName)
1307 referencedByShader = true;
1308 }
1309 }
1310
1311 m_testCtx.getLog()
1312 << tcu::TestLog::Message
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001313 << "Verifying referenced by " << glu::getShaderTypeName(m_shaderType) << " shader, expecting "
Jarkko Poyry3c827362014-09-02 11:48:52 +03001314 << ((referencedByShader) ? ("GL_TRUE") : ("GL_FALSE"))
1315 << tcu::TestLog::EndMessage;
1316
1317 if (propValue != ((referencedByShader) ? (1) : (0)))
1318 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001319 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid referenced_by_" << glu::getShaderTypeName(m_shaderType) << ", got " << propValue << tcu::TestLog::EndMessage;
1320 setError("referenced_by_" + std::string(glu::getShaderTypeName(m_shaderType)) + " invalid");
Jarkko Poyry3c827362014-09-02 11:48:52 +03001321 }
1322}
1323
1324class TopLevelArraySizeValidator : public SingleVariableValidator
1325{
1326public:
1327 TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001328
1329 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001330};
1331
1332TopLevelArraySizeValidator::TopLevelArraySizeValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001333 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_SIZE, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001334{
1335}
1336
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001337void TopLevelArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001338{
1339 int expected;
1340 std::string reason;
1341
1342 DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1343 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001344 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001345
1346 if (!path[1].getDeclaration()->varType.isArrayType())
1347 {
1348 expected = 1;
1349 reason = "Top-level block member is not an array";
1350 }
1351 else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1352 {
1353 expected = 1;
1354 reason = "Top-level block member is not an array of an aggregate type";
1355 }
1356 else if (path[1].getDeclaration()->varType.getArraySize() == glu::VarType::UNSIZED_ARRAY)
1357 {
1358 expected = 0;
1359 reason = "Top-level block member is an unsized top-level array";
1360 }
1361 else
1362 {
1363 expected = path[1].getDeclaration()->varType.getArraySize();
1364 reason = "Top-level block member is a sized top-level array";
1365 }
1366
1367 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array size, expecting " << expected << ". (" << reason << ")." << tcu::TestLog::EndMessage;
1368
1369 if (propValue != expected)
1370 {
1371 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array size, got " << propValue << tcu::TestLog::EndMessage;
1372 setError("top level array size invalid");
1373 }
1374}
1375
1376class TopLevelArrayStrideValidator : public SingleVariableValidator
1377{
1378public:
1379 TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001380
1381 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001382};
1383
1384TopLevelArrayStrideValidator::TopLevelArrayStrideValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001385 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_TOP_LEVEL_ARRAY_STRIDE, programID, filter, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001386{
1387}
1388
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001389void TopLevelArrayStrideValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001390{
1391 DE_ASSERT(path.front().isInterfaceBlock() && path.front().getInterfaceBlock()->storage == glu::STORAGE_BUFFER);
1392 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001393 DE_UNREF(implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001394
1395 if (!path[1].getDeclaration()->varType.isArrayType())
1396 {
1397 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting 0. (Top-level block member is not an array)." << tcu::TestLog::EndMessage;
1398
1399 if (propValue != 0)
1400 {
1401 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1402 setError("top level array stride invalid");
1403 }
1404 }
1405 else if (path[1].getDeclaration()->varType.getElementType().isBasicType())
1406 {
1407 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;
1408
1409 if (propValue != 0)
1410 {
1411 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1412 setError("top level array stride invalid");
1413 }
1414 }
1415 else
1416 {
1417 const int minimumStride = getVarTypeSize(path[1].getDeclaration()->varType.getElementType());
1418
1419 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying top level array stride, expecting greater or equal to " << minimumStride << "." << tcu::TestLog::EndMessage;
1420
1421 if (propValue < minimumStride)
1422 {
1423 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid top level array stride, got " << propValue << tcu::TestLog::EndMessage;
1424 setError("top level array stride invalid");
1425 }
1426 }
1427}
1428
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001429class TransformFeedbackResourceValidator : public PropValidator
Jarkko Poyry3c827362014-09-02 11:48:52 +03001430{
1431public:
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001432 TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001433
1434 void validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001435
1436private:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001437 virtual void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
1438 virtual void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const = 0;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001439};
1440
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001441
1442TransformFeedbackResourceValidator::TransformFeedbackResourceValidator (Context& context, ProgramResourcePropFlags validationProp)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001443 : PropValidator(context, validationProp, DE_NULL)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001444{
1445}
1446
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001447void TransformFeedbackResourceValidator::validate (const ProgramInterfaceDefinition::Program* program, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Poyry3c827362014-09-02 11:48:52 +03001448{
Jarkko Poyry3c827362014-09-02 11:48:52 +03001449 if (deStringBeginsWith(resource.c_str(), "gl_"))
1450 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001451 validateBuiltinVariable(resource, propValue, implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001452 }
1453 else
1454 {
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001455 // Check resource name is a xfb output. (sanity check)
1456#if defined(DE_DEBUG)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001457 bool generatorFound = false;
1458
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001459 // Check the resource name is a valid transform feedback resource and find the name generating resource
Jarkko Poyry3c827362014-09-02 11:48:52 +03001460 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx)
1461 {
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001462 const std::string varyingName = program->getTransformFeedbackVaryings()[varyingNdx];
Jarkko Poyry3c827362014-09-02 11:48:52 +03001463 std::vector<VariablePathComponent> path;
1464 std::vector<std::string> resources;
1465
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001466 if (!findProgramVariablePathByPathName(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
Jarkko Poyry3c827362014-09-02 11:48:52 +03001467 {
1468 // program does not contain feedback varying, not valid program
1469 DE_ASSERT(false);
1470 return;
1471 }
1472
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001473 generateVariableTypeResourceNames(resources, varyingName, *path.back().getVariableType(), RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001474
1475 if (de::contains(resources.begin(), resources.end(), resource))
1476 {
Jarkko Poyry3c827362014-09-02 11:48:52 +03001477 generatorFound = true;
1478 break;
1479 }
1480 }
1481
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001482 // resource name was not found, should never happen
1483 DE_ASSERT(generatorFound);
1484 DE_UNREF(generatorFound);
1485#endif
1486
1487 // verify resource
Jarkko Poyry3c827362014-09-02 11:48:52 +03001488 {
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001489 std::vector<VariablePathComponent> path;
1490
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001491 if (!findProgramVariablePathByPathName(path, program, resource, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT)))
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001492 DE_ASSERT(false);
1493
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001494 validateSingleVariable(path, resource, propValue, implementationName);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001495 }
1496 }
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001497}
1498
1499class TransformFeedbackArraySizeValidator : public TransformFeedbackResourceValidator
1500{
1501public:
1502 TransformFeedbackArraySizeValidator (Context& context);
1503
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001504 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1505 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001506};
1507
1508TransformFeedbackArraySizeValidator::TransformFeedbackArraySizeValidator (Context& context)
1509 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_ARRAY_SIZE)
1510{
1511}
1512
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001513void TransformFeedbackArraySizeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001514{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001515 DE_UNREF(implementationName);
1516
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001517 int arraySize = 0;
1518
1519 if (resource == "gl_Position")
1520 arraySize = 1;
1521 else
1522 DE_ASSERT(false);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001523
1524 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1525 if (arraySize != propValue)
1526 {
1527 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1528 setError("resource array size invalid");
1529 }
1530}
1531
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001532void TransformFeedbackArraySizeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001533{
1534 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001535 DE_UNREF(implementationName);
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001536
1537 const int arraySize = (path.back().getVariableType()->isArrayType()) ? (path.back().getVariableType()->getArraySize()) : (1);
1538
1539 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying array size, expecting " << arraySize << tcu::TestLog::EndMessage;
1540 if (arraySize != propValue)
1541 {
1542 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1543 setError("resource array size invalid");
1544 }
1545}
1546
1547class TransformFeedbackNameLengthValidator : public TransformFeedbackResourceValidator
1548{
1549public:
1550 TransformFeedbackNameLengthValidator (Context& context);
1551
1552private:
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001553 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1554 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1555 void validateVariable (const std::string& implementationName, glw::GLint propValue) const;
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001556};
1557
1558TransformFeedbackNameLengthValidator::TransformFeedbackNameLengthValidator (Context& context)
1559 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_NAME_LENGTH)
1560{
1561}
1562
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001563void TransformFeedbackNameLengthValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001564{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001565 DE_UNREF(resource);
1566 validateVariable(implementationName, propValue);
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001567}
1568
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001569void TransformFeedbackNameLengthValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001570{
1571 DE_UNREF(path);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001572 DE_UNREF(resource);
1573 validateVariable(implementationName, propValue);
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001574}
1575
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001576void TransformFeedbackNameLengthValidator::validateVariable (const std::string& implementationName, glw::GLint propValue) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001577{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001578 const int expected = (int)implementationName.length() + 1; // includes null byte
1579 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying name length, expecting " << expected << " (" << (int)implementationName.length() << " for \"" << implementationName << "\" + 1 byte for terminating null character)" << tcu::TestLog::EndMessage;
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001580
1581 if (propValue != expected)
1582 {
1583 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, invalid name length, got " << propValue << tcu::TestLog::EndMessage;
1584 setError("name length invalid");
1585 }
1586}
1587
1588class TransformFeedbackTypeValidator : public TransformFeedbackResourceValidator
1589{
1590public:
1591 TransformFeedbackTypeValidator (Context& context);
1592
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001593 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1594 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001595};
1596
1597TransformFeedbackTypeValidator::TransformFeedbackTypeValidator (Context& context)
1598 : TransformFeedbackResourceValidator(context, PROGRAMRESOURCEPROP_TYPE)
1599{
1600}
1601
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001602void TransformFeedbackTypeValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001603{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001604 DE_UNREF(implementationName);
1605
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001606 glu::DataType varType = glu::TYPE_INVALID;
1607
1608 if (resource == "gl_Position")
1609 varType = glu::TYPE_FLOAT_VEC4;
1610 else
1611 DE_ASSERT(false);
1612
1613 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(varType) << tcu::TestLog::EndMessage;
1614 if (glu::getDataTypeFromGLType(propValue) != varType)
1615 {
1616 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1617 setError("resource type invalid");
1618 }
1619 return;
1620}
1621
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001622void TransformFeedbackTypeValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001623{
1624 DE_UNREF(resource);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001625 DE_UNREF(implementationName);
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07001626
1627 // Unlike other interfaces, xfb program interface uses just variable name to refer to arrays of basic types. (Others use "variable[0]")
1628 // Thus we might end up querying a type for an array. In this case, return the type of an array element.
1629 const glu::VarType& variable = *path.back().getVariableType();
1630 const glu::VarType& elementType = (variable.isArrayType()) ? (variable.getElementType()) : (variable);
1631
1632 DE_ASSERT(elementType.isBasicType());
1633
1634 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying type, expecting " << glu::getDataTypeName(elementType.getBasicType()) << tcu::TestLog::EndMessage;
1635 if (elementType.getBasicType() != glu::getDataTypeFromGLType(propValue))
1636 {
1637 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << glu::getDataTypeName(glu::getDataTypeFromGLType(propValue)) << tcu::TestLog::EndMessage;
1638 setError("resource type invalid");
1639 }
1640}
1641
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001642class PerPatchValidator : public SingleVariableValidator
1643{
1644public:
1645 PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter);
1646
1647 std::string getHumanReadablePropertyString (glw::GLint propVal) const;
1648 void validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1649 void validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const;
1650};
1651
1652PerPatchValidator::PerPatchValidator (Context& context, glw::GLuint programID, const VariableSearchFilter& filter)
1653 : SingleVariableValidator(context, PROGRAMRESOURCEPROP_IS_PER_PATCH, programID, filter, "GL_EXT_tessellation_shader")
1654{
1655}
1656
1657std::string PerPatchValidator::getHumanReadablePropertyString (glw::GLint propVal) const
1658{
1659 return de::toString(glu::getBooleanStr(propVal));
1660}
1661
1662void PerPatchValidator::validateSingleVariable (const std::vector<VariablePathComponent>& path, const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1663{
1664 const glu::Storage storage = (path.front().isInterfaceBlock()) ? (path.front().getInterfaceBlock()->storage) : (path.front().getDeclaration()->storage);
1665 const int expected = (storage == glu::STORAGE_PATCH_IN || storage == glu::STORAGE_PATCH_OUT) ? (1) : (0);
1666
1667 DE_UNREF(resource);
1668 DE_UNREF(implementationName);
1669
1670 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << expected << tcu::TestLog::EndMessage;
1671
1672 if (propValue != expected)
1673 {
1674 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1675 setError("resource is per patch invalid");
1676 }
1677}
1678
1679void PerPatchValidator::validateBuiltinVariable (const std::string& resource, glw::GLint propValue, const std::string& implementationName) const
1680{
1681 DE_UNREF(implementationName);
1682
1683 static const struct
1684 {
1685 const char* name;
1686 int isPerPatch;
1687 } builtins[] =
1688 {
1689 { "gl_Position", 0 },
1690 { "gl_PerVertex.gl_Position", 0 },
1691 { "gl_InvocationID", 0 },
1692 { "gl_TessLevelOuter", 1 },
1693 { "gl_TessLevelInner", 1 },
1694 };
1695
1696 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtins); ++ndx)
1697 {
1698 if (resource == builtins[ndx].name)
1699 {
1700 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying if is per patch, expecting IS_PER_PATCH = " << builtins[ndx].isPerPatch << tcu::TestLog::EndMessage;
1701
1702 if (propValue != builtins[ndx].isPerPatch)
1703 {
1704 m_testCtx.getLog() << tcu::TestLog::Message << "\tError, got " << propValue << tcu::TestLog::EndMessage;
1705 setError("resource is per patch invalid");
1706 }
1707 return;
1708 }
1709 }
1710
1711 DE_ASSERT(false);
1712}
1713
Jarkko Poyry3c827362014-09-02 11:48:52 +03001714} // anonymous
1715
1716ProgramResourceQueryTestTarget::ProgramResourceQueryTestTarget (ProgramInterface interface_, deUint32 propFlags_)
1717 : interface(interface_)
1718 , propFlags(propFlags_)
1719{
1720 switch (interface)
1721 {
1722 case PROGRAMINTERFACE_UNIFORM: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_INTERFACE_MASK) == propFlags); break;
1723 case PROGRAMINTERFACE_UNIFORM_BLOCK: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_UNIFORM_BLOCK_INTERFACE_MASK) == propFlags); break;
1724 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_SHADER_STORAGE_BLOCK_MASK) == propFlags); break;
1725 case PROGRAMINTERFACE_PROGRAM_INPUT: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_INPUT_MASK) == propFlags); break;
1726 case PROGRAMINTERFACE_PROGRAM_OUTPUT: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_PROGRAM_OUTPUT_MASK) == propFlags); break;
1727 case PROGRAMINTERFACE_BUFFER_VARIABLE: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_BUFFER_VARIABLE_MASK) == propFlags); break;
1728 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: DE_ASSERT((propFlags & PROGRAMRESOURCEPROP_TRANSFORM_FEEDBACK_VARYING_MASK) == propFlags); break;
1729
1730 default:
1731 DE_ASSERT(false);
1732 }
1733}
1734
1735ProgramInterfaceQueryTestCase::ProgramInterfaceQueryTestCase (Context& context, const char* name, const char* description, ProgramResourceQueryTestTarget queryTarget)
1736 : TestCase (context, name, description)
1737 , m_queryTarget (queryTarget)
1738{
1739}
1740
1741ProgramInterfaceQueryTestCase::~ProgramInterfaceQueryTestCase (void)
1742{
1743}
1744
1745ProgramInterface ProgramInterfaceQueryTestCase::getTargetInterface (void) const
1746{
1747 return m_queryTarget.interface;
1748}
1749
1750static glw::GLenum getGLInterfaceEnumValue (ProgramInterface interface)
1751{
1752 switch (interface)
1753 {
1754 case PROGRAMINTERFACE_UNIFORM: return GL_UNIFORM;
1755 case PROGRAMINTERFACE_UNIFORM_BLOCK: return GL_UNIFORM_BLOCK;
1756 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER: return GL_ATOMIC_COUNTER_BUFFER;
1757 case PROGRAMINTERFACE_PROGRAM_INPUT: return GL_PROGRAM_INPUT;
1758 case PROGRAMINTERFACE_PROGRAM_OUTPUT: return GL_PROGRAM_OUTPUT;
1759 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: return GL_TRANSFORM_FEEDBACK_VARYING;
1760 case PROGRAMINTERFACE_BUFFER_VARIABLE: return GL_BUFFER_VARIABLE;
1761 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: return GL_SHADER_STORAGE_BLOCK;
1762 default:
1763 DE_ASSERT(false);
1764 return 0;
1765 };
1766}
1767
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001768static bool isInterfaceBlockInterfaceName (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& blockInterfaceName)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001769{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001770 deUint32 validStorageBits;
1771 deUint32 searchStageBits;
1772
1773 DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1774 DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1775
1776 switch (interface)
1777 {
1778 case PROGRAMINTERFACE_UNIFORM_BLOCK:
1779 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1780 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1781 return false;
1782
1783 case PROGRAMINTERFACE_PROGRAM_INPUT:
1784 validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1785 searchStageBits = (1u << program->getFirstStage());
1786 break;
1787
1788 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1789 validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1790 searchStageBits = (1u << program->getLastStage());
1791 break;
1792
1793 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1794 validStorageBits = (1u << glu::STORAGE_OUT);
1795 searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1796 break;
1797
1798 case PROGRAMINTERFACE_UNIFORM:
1799 validStorageBits = (1u << glu::STORAGE_UNIFORM);
1800 searchStageBits = 0xFFFFFFFFu;
1801 break;
1802
1803 case PROGRAMINTERFACE_BUFFER_VARIABLE:
1804 validStorageBits = (1u << glu::STORAGE_BUFFER);
1805 searchStageBits = 0xFFFFFFFFu;
1806 break;
1807
1808 default:
1809 DE_ASSERT(false);
1810 return false;
1811 }
1812
1813 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1814 {
1815 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1816 if (((1u << shader->getType()) & searchStageBits) == 0)
1817 continue;
1818
1819 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1820 {
1821 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1822
1823 if (((1u << block.storage) & validStorageBits) == 0)
1824 continue;
1825
1826 if (block.interfaceName == blockInterfaceName)
1827 return true;
1828 }
1829 }
1830 return false;
1831}
1832
1833static std::string getInterfaceBlockInteraceNameByMember (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface, const std::string& memberName)
1834{
1835 deUint32 validStorageBits;
1836 deUint32 searchStageBits;
1837
1838 DE_STATIC_ASSERT(glu::STORAGE_LAST < 32);
1839 DE_STATIC_ASSERT(glu::SHADERTYPE_LAST < 32);
1840
1841 switch (interface)
1842 {
1843 case PROGRAMINTERFACE_UNIFORM_BLOCK:
1844 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
1845 case PROGRAMINTERFACE_ATOMIC_COUNTER_BUFFER:
1846 return "";
1847
1848 case PROGRAMINTERFACE_PROGRAM_INPUT:
1849 validStorageBits = (1u << glu::STORAGE_IN) | (1u << glu::STORAGE_PATCH_IN);
1850 searchStageBits = (1u << program->getFirstStage());
1851 break;
1852
1853 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
1854 validStorageBits = (1u << glu::STORAGE_OUT) | (1u << glu::STORAGE_PATCH_OUT);
1855 searchStageBits = (1u << program->getLastStage());
1856 break;
1857
1858 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
1859 validStorageBits = (1u << glu::STORAGE_OUT);
1860 searchStageBits = (1u << getProgramTransformFeedbackStage(program));
1861 break;
1862
1863 case PROGRAMINTERFACE_UNIFORM:
1864 validStorageBits = (1u << glu::STORAGE_UNIFORM);
1865 searchStageBits = 0xFFFFFFFFu;
1866 break;
1867
1868 case PROGRAMINTERFACE_BUFFER_VARIABLE:
1869 validStorageBits = (1u << glu::STORAGE_BUFFER);
1870 searchStageBits = 0xFFFFFFFFu;
1871 break;
1872
1873 default:
1874 DE_ASSERT(false);
1875 return "";
1876 }
1877
1878 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
1879 {
1880 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx];
1881 if (((1u << shader->getType()) & searchStageBits) == 0)
1882 continue;
1883
1884 for (int blockNdx = 0; blockNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++blockNdx)
1885 {
1886 const glu::InterfaceBlock& block = shader->getDefaultBlock().interfaceBlocks[blockNdx];
1887
1888 if (((1u << block.storage) & validStorageBits) == 0)
1889 continue;
1890
1891 for (int varNdx = 0; varNdx < (int)block.variables.size(); ++varNdx)
1892 {
1893 if (block.variables[varNdx].name == memberName)
1894 return block.interfaceName;
1895 }
1896 }
1897 }
1898 return "";
1899}
1900
1901static void queryAndValidateProps (tcu::TestContext& testCtx,
1902 const glw::Functions& gl,
1903 glw::GLuint programID,
1904 ProgramInterface interface,
1905 const char* targetResourceName,
1906 const ProgramInterfaceDefinition::Program* programDefinition,
1907 const std::vector<glw::GLenum>& props,
1908 const std::vector<const PropValidator*>& validators)
1909{
1910 const glw::GLenum glInterface = getGLInterfaceEnumValue(interface);
1911 std::string implementationResourceName = targetResourceName;
Jarkko Poyry3c827362014-09-02 11:48:52 +03001912 glw::GLuint resourceNdx;
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001913 glw::GLint written = -1;
1914
1915 // prefill result buffer with an invalid value. -1 might be valid sometimes, avoid it. Make buffer one larger
1916 // to allow detection of too many return values
1917 std::vector<glw::GLint> propValues (props.size() + 1, -2);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001918
1919 DE_ASSERT(props.size() == validators.size());
1920
1921 // query
1922
1923 resourceNdx = gl.getProgramResourceIndex(programID, glInterface, targetResourceName);
1924 GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
1925
1926 if (resourceNdx == GL_INVALID_INDEX)
1927 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001928 static const struct
1929 {
1930 bool removeTrailingArray; // convert from "target[0]" -> "target"
1931 bool removeTrailingMember; // convert from "target.member" -> "target"
1932 bool removeIOBlock; // convert from "InterfaceName.target" -> "target"
1933 bool addIOBlock; // convert from "target" -> "InterfaceName.target"
1934 bool addIOBlockArray; // convert from "target" -> "InterfaceName[0].target"
1935 } recoveryStrategies[] =
1936 {
1937 // try one patch
1938 { true, false, false, false, false },
1939 { false, true, false, false, false },
1940 { false, false, true, false, false },
1941 { false, false, false, true, false },
1942 { false, false, false, false, true },
1943 // patch both ends
1944 { true, false, true, false, false },
1945 { true, false, false, true, false },
1946 { true, false, false, false, true },
1947 { false, true, true, false, false },
1948 { false, true, false, true, false },
1949 { false, true, false, false, true },
1950 };
1951
1952 // The resource name generation in the GL implementations is very commonly broken. Try to
1953 // keep the tests producing useful data even in these cases by attempting to recover from
1954 // common naming bugs. Set test result to failure even if recovery succeeded to signal
1955 // incorrect name generation.
1956
Jarkko Poyry3c827362014-09-02 11:48:52 +03001957 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceIndex returned GL_INVALID_INDEX for \"" << targetResourceName << "\"" << tcu::TestLog::EndMessage;
1958 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "could not find target resource");
1959
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001960 for (int strategyNdx = 0; strategyNdx < DE_LENGTH_OF_ARRAY(recoveryStrategies); ++strategyNdx)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001961 {
1962 const std::string resourceName = std::string(targetResourceName);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001963 const size_t rootNameEnd = resourceName.find_first_of(".[");
1964 const std::string rootName = resourceName.substr(0, rootNameEnd);
Jarkko Poyry3c827362014-09-02 11:48:52 +03001965 std::string simplifiedResourceName;
1966
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001967 if (recoveryStrategies[strategyNdx].removeTrailingArray)
1968 {
1969 if (stringEndsWith(resourceName, "[0]"))
1970 simplifiedResourceName = resourceName.substr(0, resourceName.length() - 3);
1971 else
1972 continue;
1973 }
1974
1975 if (recoveryStrategies[strategyNdx].removeTrailingMember)
Jarkko Poyry3c827362014-09-02 11:48:52 +03001976 {
1977 const size_t lastMember = resourceName.find_last_of('.');
1978 if (lastMember != std::string::npos)
1979 simplifiedResourceName = resourceName.substr(0, lastMember);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08001980 else
1981 continue;
1982 }
1983
1984 if (recoveryStrategies[strategyNdx].removeIOBlock)
1985 {
1986 if (deStringBeginsWith(resourceName.c_str(), "gl_PerVertex."))
1987 {
1988 // builtin interface bock, remove block name
1989 simplifiedResourceName = resourceName.substr(13);
1990 }
1991 else if (isInterfaceBlockInterfaceName(programDefinition, interface, rootName))
1992 {
1993 // user-defined inteface block, remove name
1994 const size_t accessorEnd = resourceName.find('.'); // includes potential array accessor
1995
1996 if (accessorEnd != std::string::npos)
1997 simplifiedResourceName = resourceName.substr(0, accessorEnd+1);
1998 else
1999 continue;
2000 }
2001 else
2002 {
2003 // recovery not applicable
2004 continue;
2005 }
2006 }
2007
2008 if (recoveryStrategies[strategyNdx].addIOBlock || recoveryStrategies[strategyNdx].addIOBlockArray)
2009 {
2010 const std::string arrayAccessor = (recoveryStrategies[strategyNdx].addIOBlockArray) ? ("[0]") : ("");
2011
2012 if (deStringBeginsWith(resourceName.c_str(), "gl_") && resourceName.find('.') == std::string::npos)
2013 {
2014 // free builtin variable, add block name
2015 simplifiedResourceName = "gl_PerVertex" + arrayAccessor + "." + resourceName;
2016 }
2017 else
2018 {
2019 const std::string interafaceName = getInterfaceBlockInteraceNameByMember(programDefinition, interface, rootName);
2020
2021 if (!interafaceName.empty())
2022 {
2023 // free user variable, add block name
2024 simplifiedResourceName = interafaceName + arrayAccessor + "." + resourceName;
2025 }
2026 else
2027 {
2028 // recovery not applicable
2029 continue;
2030 }
2031 }
Jarkko Poyry3c827362014-09-02 11:48:52 +03002032 }
2033
2034 if (simplifiedResourceName.empty())
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002035 continue;
Jarkko Poyry3c827362014-09-02 11:48:52 +03002036
2037 resourceNdx = gl.getProgramResourceIndex(programID, glInterface, simplifiedResourceName.c_str());
2038 GLU_EXPECT_NO_ERROR(gl.getError(), "get resource index");
2039
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002040 // recovery succeeded
2041 if (resourceNdx != GL_INVALID_INDEX)
2042 {
2043 implementationResourceName = simplifiedResourceName;
2044 testCtx.getLog() << tcu::TestLog::Message << "\tResource not found, continuing anyway using index obtained for resource \"" << simplifiedResourceName << "\"" << tcu::TestLog::EndMessage;
2045 break;
2046 }
Jarkko Poyry3c827362014-09-02 11:48:52 +03002047 }
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002048
2049 if (resourceNdx == GL_INVALID_INDEX)
2050 return;
Jarkko Poyry3c827362014-09-02 11:48:52 +03002051 }
2052
2053 gl.getProgramResourceiv(programID, glInterface, resourceNdx, (int)props.size(), &props[0], (int)propValues.size(), &written, &propValues[0]);
2054 GLU_EXPECT_NO_ERROR(gl.getError(), "get props");
2055
2056 if (written != (int)props.size())
2057 {
2058 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv returned unexpected number of values, expected " << (int)props.size() << ", got " << written << tcu::TestLog::EndMessage;
2059 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2060 return;
2061 }
2062
2063 if (propValues.back() != -2)
2064 {
2065 testCtx.getLog() << tcu::TestLog::Message << "getProgramResourceiv post write buffer guard value was modified, too many return values" << tcu::TestLog::EndMessage;
2066 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "getProgramResourceiv returned unexpected number of values");
2067 return;
2068 }
2069 propValues.pop_back();
2070 DE_ASSERT(validators.size() == propValues.size());
2071
2072 // log
2073
2074 {
2075 tcu::MessageBuilder message(&testCtx.getLog());
2076 message << "For resource index " << resourceNdx << " (\"" << targetResourceName << "\") got following properties:\n";
2077
2078 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
2079 message << "\t" << glu::getProgramResourcePropertyName(props[propNdx]) << ":\t" << validators[propNdx]->getHumanReadablePropertyString(propValues[propNdx]) << "\n";
2080
2081 message << tcu::TestLog::EndMessage;
2082 }
2083
2084 // validate
2085
2086 for (int propNdx = 0; propNdx < (int)propValues.size(); ++propNdx)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002087 validators[propNdx]->validate(programDefinition, targetResourceName, propValues[propNdx], implementationResourceName);
2088}
2089
2090const ProgramInterfaceDefinition::Program* ProgramInterfaceQueryTestCase::getAndCheckProgramDefinition (void)
2091{
2092 const ProgramInterfaceDefinition::Program* programDefinition = getProgramDefinition();
2093 DE_ASSERT(programDefinition->isValid());
2094
2095 if (programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_CONTROL) ||
2096 programDefinition->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION))
2097 {
2098 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2099 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2100 }
2101
2102 // Testing IS_PER_PATCH as a part of a larger set is ok, since the extension is checked
2103 // before query. However, we don't want IS_PER_PATCH-specific tests to become noop and pass.
2104 if (m_queryTarget.propFlags == PROGRAMRESOURCEPROP_IS_PER_PATCH)
2105 {
2106 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"))
2107 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension");
2108 }
2109
2110 if (programDefinition->hasStage(glu::SHADERTYPE_GEOMETRY))
2111 {
2112 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2113 throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension");
2114 }
2115
2116 if (programContainsIOBlocks(programDefinition))
2117 {
2118 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_io_blocks"))
2119 throw tcu::NotSupportedError("Test requires GL_EXT_shader_io_blocks extension");
2120 }
2121
2122 return programDefinition;
2123}
2124
2125int ProgramInterfaceQueryTestCase::getMaxPatchVertices (void)
2126{
2127 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2128 glw::GLint maxPatchVertices = 0;
2129
2130 gl.getIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
2131 GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_PATCH_VERTICES)");
2132 return maxPatchVertices;
Jarkko Poyry3c827362014-09-02 11:48:52 +03002133}
2134
2135ProgramInterfaceQueryTestCase::IterateResult ProgramInterfaceQueryTestCase::iterate (void)
2136{
2137 struct TestProperty
2138 {
2139 glw::GLenum prop;
2140 const PropValidator* validator;
2141 };
2142
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002143 const ProgramInterfaceDefinition::Program* programDefinition = getAndCheckProgramDefinition();
Jarkko Poyry3c827362014-09-02 11:48:52 +03002144 const std::vector<std::string> targetResources = getQueryTargetResources();
2145 glu::ShaderProgram program (m_context.getRenderContext(), generateProgramInterfaceProgramSources(programDefinition));
2146
2147 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2148
Jarkko Poyry3c827362014-09-02 11:48:52 +03002149 // Log program
2150 {
2151 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program", "Program");
2152
2153 // Feedback varyings
2154 if (!programDefinition->getTransformFeedbackVaryings().empty())
2155 {
2156 tcu::MessageBuilder builder(&m_testCtx.getLog());
2157 builder << "Transform feedback varyings: {";
2158 for (int ndx = 0; ndx < (int)programDefinition->getTransformFeedbackVaryings().size(); ++ndx)
2159 {
2160 if (ndx)
2161 builder << ", ";
2162 builder << "\"" << programDefinition->getTransformFeedbackVaryings()[ndx] << "\"";
2163 }
2164 builder << "}" << tcu::TestLog::EndMessage;
2165 }
2166
2167 m_testCtx.getLog() << program;
2168 if (!program.isOk())
2169 {
2170 m_testCtx.getLog() << tcu::TestLog::Message << "Program build failed, checking if program exceeded implementation limits" << tcu::TestLog::EndMessage;
2171 checkProgramResourceUsage(programDefinition, m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2172
2173 // within limits
2174 throw tcu::TestError("could not build program");
2175 }
2176 }
2177
2178 // Check interface props
2179
2180 switch (m_queryTarget.interface)
2181 {
2182 case PROGRAMINTERFACE_UNIFORM:
2183 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002184 const VariableSearchFilter uniformFilter = VariableSearchFilter::createStorageFilter(glu::STORAGE_UNIFORM);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002185
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002186 const TypeValidator typeValidator (m_context, program.getProgram(), uniformFilter);
2187 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), -1, uniformFilter);
2188 const ArrayStrideValidator arrayStrideValidator (m_context, program.getProgram(), uniformFilter);
2189 const BlockIndexValidator blockIndexValidator (m_context, program.getProgram(), uniformFilter);
2190 const IsRowMajorValidator isRowMajorValidator (m_context, program.getProgram(), uniformFilter);
2191 const MatrixStrideValidator matrixStrideValidator (m_context, program.getProgram(), uniformFilter);
2192 const AtomicCounterBufferIndexVerifier atomicCounterBufferIndexVerifier (m_context, program.getProgram(), uniformFilter);
2193 const LocationValidator locationValidator (m_context, program.getProgram(), uniformFilter);
2194 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), uniformFilter);
2195 const OffsetValidator offsetVerifier (m_context, program.getProgram(), uniformFilter);
2196 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, uniformFilter);
2197 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, uniformFilter);
2198 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, uniformFilter);
2199 const VariableReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, uniformFilter);
2200 const VariableReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, uniformFilter);
2201 const VariableReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, uniformFilter);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002202
2203 const TestProperty allProperties[] =
2204 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002205 { GL_ARRAY_SIZE, &arraySizeValidator },
2206 { GL_ARRAY_STRIDE, &arrayStrideValidator },
2207 { GL_ATOMIC_COUNTER_BUFFER_INDEX, &atomicCounterBufferIndexVerifier },
2208 { GL_BLOCK_INDEX, &blockIndexValidator },
2209 { GL_IS_ROW_MAJOR, &isRowMajorValidator },
2210 { GL_LOCATION, &locationValidator },
2211 { GL_MATRIX_STRIDE, &matrixStrideValidator },
2212 { GL_NAME_LENGTH, &nameLengthValidator },
2213 { GL_OFFSET, &offsetVerifier },
2214 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
2215 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
2216 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
2217 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier },
2218 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier },
2219 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier },
2220 { GL_TYPE, &typeValidator },
Jarkko Poyry3c827362014-09-02 11:48:52 +03002221 };
2222
2223 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2224 {
2225 const tcu::ScopedLogSection section (m_testCtx.getLog(), "UniformResource", "Uniform resource \"" + targetResources[targetResourceNdx] + "\"");
2226 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2227 std::vector<glw::GLenum> props;
2228 std::vector<const PropValidator*> validators;
2229
2230 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2231 {
2232 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2233 allProperties[propNdx].validator->isSupported())
2234 {
2235 props.push_back(allProperties[propNdx].prop);
2236 validators.push_back(allProperties[propNdx].validator);
2237 }
2238 }
2239
2240 DE_ASSERT(!props.empty());
2241
2242 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2243 }
2244
2245 break;
2246 }
2247
2248 case PROGRAMINTERFACE_UNIFORM_BLOCK:
2249 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK:
2250 {
2251 const glu::Storage storage = (m_queryTarget.interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER);
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002252 const VariableSearchFilter blockFilter = VariableSearchFilter::createStorageFilter(storage);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002253
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002254 const BlockNameLengthValidator nameLengthValidator (m_context, program.getProgram(), blockFilter);
2255 const BlockReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, blockFilter);
2256 const BlockReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, blockFilter);
2257 const BlockReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, blockFilter);
2258 const BlockReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, blockFilter);
2259 const BlockReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, blockFilter);
2260 const BlockReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, blockFilter);
2261 const BufferBindingValidator bufferBindingValidator (m_context, program.getProgram(), blockFilter);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002262
2263 const TestProperty allProperties[] =
2264 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002265 { GL_NAME_LENGTH, &nameLengthValidator },
2266 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
2267 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
2268 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
2269 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier },
2270 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier },
2271 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier },
2272 { GL_BUFFER_BINDING, &bufferBindingValidator },
Jarkko Poyry3c827362014-09-02 11:48:52 +03002273 };
2274
2275 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2276 {
2277 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BlockResource", "Interface block \"" + targetResources[targetResourceNdx] + "\"");
2278 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2279 std::vector<glw::GLenum> props;
2280 std::vector<const PropValidator*> validators;
2281
2282 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2283 {
2284 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2285 allProperties[propNdx].validator->isSupported())
2286 {
2287 props.push_back(allProperties[propNdx].prop);
2288 validators.push_back(allProperties[propNdx].validator);
2289 }
2290 }
2291
2292 DE_ASSERT(!props.empty());
2293
2294 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2295 }
2296
2297 break;
2298 }
2299
2300 case PROGRAMINTERFACE_PROGRAM_INPUT:
2301 case PROGRAMINTERFACE_PROGRAM_OUTPUT:
2302 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002303 const bool isInputCase = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT);
2304 const glu::Storage varyingStorage = (isInputCase) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT);
2305 const glu::Storage patchStorage = (isInputCase) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT);
2306 const glu::ShaderType shaderType = (isInputCase) ? (programDefinition->getFirstStage()) : (programDefinition->getLastStage());
2307 const int unsizedArraySize = (isInputCase && shaderType == glu::SHADERTYPE_GEOMETRY) ? (1) // input points
2308 : (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) ? (getMaxPatchVertices()) // input batch size
2309 : (!isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) ? (programDefinition->getTessellationNumOutputPatchVertices()) // output batch size
2310 : (isInputCase && shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) ? (getMaxPatchVertices()) // input batch size
2311 : (-1);
2312 const VariableSearchFilter variableFilter = VariableSearchFilter::logicalAnd(VariableSearchFilter::createShaderTypeFilter(shaderType),
2313 VariableSearchFilter::logicalOr(VariableSearchFilter::createStorageFilter(varyingStorage),
2314 VariableSearchFilter::createStorageFilter(patchStorage)));
Jarkko Poyry3c827362014-09-02 11:48:52 +03002315
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002316 const TypeValidator typeValidator (m_context, program.getProgram(), variableFilter);
2317 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), unsizedArraySize, variableFilter);
2318 const LocationValidator locationValidator (m_context, program.getProgram(), variableFilter);
2319 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), variableFilter);
2320 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, variableFilter);
2321 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, variableFilter);
2322 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, variableFilter);
2323 const VariableReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, variableFilter);
2324 const VariableReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, variableFilter);
2325 const VariableReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, variableFilter);
2326 const PerPatchValidator perPatchValidator (m_context, program.getProgram(), variableFilter);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002327
2328 const TestProperty allProperties[] =
2329 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002330 { GL_ARRAY_SIZE, &arraySizeValidator },
2331 { GL_LOCATION, &locationValidator },
2332 { GL_NAME_LENGTH, &nameLengthValidator },
2333 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
2334 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
2335 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
2336 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier },
2337 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier },
2338 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier },
2339 { GL_TYPE, &typeValidator },
2340 { GL_IS_PER_PATCH, &perPatchValidator },
Jarkko Poyry3c827362014-09-02 11:48:52 +03002341 };
2342
2343 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2344 {
2345 const std::string resourceInterfaceName = (m_queryTarget.interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? ("Input") : ("Output");
2346 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BlockResource", resourceInterfaceName + " resource \"" + targetResources[targetResourceNdx] + "\"");
2347 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2348 std::vector<glw::GLenum> props;
2349 std::vector<const PropValidator*> validators;
2350
2351 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2352 {
2353 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2354 allProperties[propNdx].validator->isSupported())
2355 {
2356 props.push_back(allProperties[propNdx].prop);
2357 validators.push_back(allProperties[propNdx].validator);
2358 }
2359 }
2360
2361 DE_ASSERT(!props.empty());
2362
2363 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2364 }
2365
2366 break;
2367 }
2368
2369 case PROGRAMINTERFACE_BUFFER_VARIABLE:
2370 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002371 const VariableSearchFilter variableFilter = VariableSearchFilter::createStorageFilter(glu::STORAGE_BUFFER);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002372
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002373 const TypeValidator typeValidator (m_context, program.getProgram(), variableFilter);
2374 const ArraySizeValidator arraySizeValidator (m_context, program.getProgram(), 0, variableFilter);
2375 const ArrayStrideValidator arrayStrideValidator (m_context, program.getProgram(), variableFilter);
2376 const BlockIndexValidator blockIndexValidator (m_context, program.getProgram(), variableFilter);
2377 const IsRowMajorValidator isRowMajorValidator (m_context, program.getProgram(), variableFilter);
2378 const MatrixStrideValidator matrixStrideValidator (m_context, program.getProgram(), variableFilter);
2379 const OffsetValidator offsetValidator (m_context, program.getProgram(), variableFilter);
2380 const VariableNameLengthValidator nameLengthValidator (m_context, program.getProgram(), variableFilter);
2381 const VariableReferencedByShaderValidator referencedByVertexVerifier (m_context, glu::SHADERTYPE_VERTEX, variableFilter);
2382 const VariableReferencedByShaderValidator referencedByFragmentVerifier (m_context, glu::SHADERTYPE_FRAGMENT, variableFilter);
2383 const VariableReferencedByShaderValidator referencedByComputeVerifier (m_context, glu::SHADERTYPE_COMPUTE, variableFilter);
2384 const VariableReferencedByShaderValidator referencedByGeometryVerifier (m_context, glu::SHADERTYPE_GEOMETRY, variableFilter);
2385 const VariableReferencedByShaderValidator referencedByTessControlVerifier (m_context, glu::SHADERTYPE_TESSELLATION_CONTROL, variableFilter);
2386 const VariableReferencedByShaderValidator referencedByTessEvaluationVerifier (m_context, glu::SHADERTYPE_TESSELLATION_EVALUATION, variableFilter);
2387 const TopLevelArraySizeValidator topLevelArraySizeValidator (m_context, program.getProgram(), variableFilter);
2388 const TopLevelArrayStrideValidator topLevelArrayStrideValidator (m_context, program.getProgram(), variableFilter);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002389
2390 const TestProperty allProperties[] =
2391 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002392 { GL_ARRAY_SIZE, &arraySizeValidator },
2393 { GL_ARRAY_STRIDE, &arrayStrideValidator },
2394 { GL_BLOCK_INDEX, &blockIndexValidator },
2395 { GL_IS_ROW_MAJOR, &isRowMajorValidator },
2396 { GL_MATRIX_STRIDE, &matrixStrideValidator },
2397 { GL_NAME_LENGTH, &nameLengthValidator },
2398 { GL_OFFSET, &offsetValidator },
2399 { GL_REFERENCED_BY_VERTEX_SHADER, &referencedByVertexVerifier },
2400 { GL_REFERENCED_BY_FRAGMENT_SHADER, &referencedByFragmentVerifier },
2401 { GL_REFERENCED_BY_COMPUTE_SHADER, &referencedByComputeVerifier },
2402 { GL_REFERENCED_BY_GEOMETRY_SHADER, &referencedByGeometryVerifier },
2403 { GL_REFERENCED_BY_TESS_CONTROL_SHADER, &referencedByTessControlVerifier },
2404 { GL_REFERENCED_BY_TESS_EVALUATION_SHADER, &referencedByTessEvaluationVerifier },
2405 { GL_TOP_LEVEL_ARRAY_SIZE, &topLevelArraySizeValidator },
2406 { GL_TOP_LEVEL_ARRAY_STRIDE, &topLevelArrayStrideValidator },
2407 { GL_TYPE, &typeValidator },
Jarkko Poyry3c827362014-09-02 11:48:52 +03002408 };
2409
2410 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2411 {
2412 const tcu::ScopedLogSection section (m_testCtx.getLog(), "BufferVariableResource", "Buffer variable \"" + targetResources[targetResourceNdx] + "\"");
2413 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2414 std::vector<glw::GLenum> props;
2415 std::vector<const PropValidator*> validators;
2416
2417 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2418 {
2419 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2420 allProperties[propNdx].validator->isSupported())
2421 {
2422 props.push_back(allProperties[propNdx].prop);
2423 validators.push_back(allProperties[propNdx].validator);
2424 }
2425 }
2426
2427 DE_ASSERT(!props.empty());
2428
2429 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2430 }
2431
2432 break;
2433 }
2434
2435 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING:
2436 {
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07002437 const TransformFeedbackTypeValidator typeValidator (m_context);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002438 const TransformFeedbackArraySizeValidator arraySizeValidator (m_context);
Jarkko Pöyry79ec5222014-10-15 13:34:56 -07002439 const TransformFeedbackNameLengthValidator nameLengthValidator (m_context);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002440
2441 const TestProperty allProperties[] =
2442 {
2443 { GL_ARRAY_SIZE, &arraySizeValidator },
2444 { GL_NAME_LENGTH, &nameLengthValidator },
2445 { GL_TYPE, &typeValidator },
2446 };
2447
2448 for (int targetResourceNdx = 0; targetResourceNdx < (int)targetResources.size(); ++targetResourceNdx)
2449 {
2450 const tcu::ScopedLogSection section (m_testCtx.getLog(), "XFBVariableResource", "Transform feedback varying \"" + targetResources[targetResourceNdx] + "\"");
2451 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2452 std::vector<glw::GLenum> props;
2453 std::vector<const PropValidator*> validators;
2454
2455 for (int propNdx = 0; propNdx < DE_LENGTH_OF_ARRAY(allProperties); ++propNdx)
2456 {
2457 if (allProperties[propNdx].validator->isSelected(m_queryTarget.propFlags) &&
2458 allProperties[propNdx].validator->isSupported())
2459 {
2460 props.push_back(allProperties[propNdx].prop);
2461 validators.push_back(allProperties[propNdx].validator);
2462 }
2463 }
2464
2465 DE_ASSERT(!props.empty());
2466
2467 queryAndValidateProps(m_testCtx, gl, program.getProgram(), m_queryTarget.interface, targetResources[targetResourceNdx].c_str(), programDefinition, props, validators);
2468 }
2469
2470 break;
2471 }
2472
2473 default:
2474 DE_ASSERT(false);
2475 }
2476
2477 return STOP;
2478}
2479
2480static bool checkLimit (glw::GLenum pname, int usage, const glw::Functions& gl, tcu::TestLog& log)
2481{
2482 if (usage > 0)
2483 {
2484 glw::GLint limit = 0;
2485 gl.getIntegerv(pname, &limit);
2486 GLU_EXPECT_NO_ERROR(gl.getError(), "query limits");
2487
2488 log << tcu::TestLog::Message << "\t" << glu::getGettableStateStr(pname) << " = " << limit << ", test requires " << usage << tcu::TestLog::EndMessage;
2489
2490 if (limit < usage)
2491 {
2492 log << tcu::TestLog::Message << "\t\tLimit exceeded" << tcu::TestLog::EndMessage;
2493 return false;
2494 }
2495 }
2496
2497 return true;
2498}
2499
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002500static bool checkShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader, const glw::Functions& gl, tcu::TestLog& log)
Jarkko Poyry3c827362014-09-02 11:48:52 +03002501{
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002502 const ProgramInterfaceDefinition::ShaderResourceUsage usage = getShaderResourceUsage(program, shader);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002503
2504 switch (shader->getType())
2505 {
2506 case glu::SHADERTYPE_VERTEX:
2507 {
2508 const struct
2509 {
2510 glw::GLenum pname;
2511 int usage;
2512 } restrictions[] =
2513 {
2514 { GL_MAX_VERTEX_ATTRIBS, usage.numInputVectors },
2515 { GL_MAX_VERTEX_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
2516 { GL_MAX_VERTEX_UNIFORM_VECTORS, usage.numUniformVectors },
2517 { GL_MAX_VERTEX_UNIFORM_BLOCKS, usage.numUniformBlocks },
2518 { GL_MAX_VERTEX_OUTPUT_COMPONENTS, usage.numOutputComponents },
2519 { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, usage.numSamplers },
2520 { GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2521 { GL_MAX_VERTEX_ATOMIC_COUNTERS, usage.numAtomicCounters },
2522 { GL_MAX_VERTEX_IMAGE_UNIFORMS, usage.numImages },
2523 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents },
2524 { GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2525 };
2526
2527 bool allOk = true;
2528
2529 log << tcu::TestLog::Message << "Vertex shader:" << tcu::TestLog::EndMessage;
2530 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2531 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2532
2533 return allOk;
2534 }
2535
2536 case glu::SHADERTYPE_FRAGMENT:
2537 {
2538 const struct
2539 {
2540 glw::GLenum pname;
2541 int usage;
2542 } restrictions[] =
2543 {
2544 { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
2545 { GL_MAX_FRAGMENT_UNIFORM_VECTORS, usage.numUniformVectors },
2546 { GL_MAX_FRAGMENT_UNIFORM_BLOCKS, usage.numUniformBlocks },
2547 { GL_MAX_FRAGMENT_INPUT_COMPONENTS, usage.numInputComponents },
2548 { GL_MAX_TEXTURE_IMAGE_UNITS, usage.numSamplers },
2549 { GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2550 { GL_MAX_FRAGMENT_ATOMIC_COUNTERS, usage.numAtomicCounters },
2551 { GL_MAX_FRAGMENT_IMAGE_UNIFORMS, usage.numImages },
2552 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents },
2553 { GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2554 };
2555
2556 bool allOk = true;
2557
2558 log << tcu::TestLog::Message << "Fragment shader:" << tcu::TestLog::EndMessage;
2559 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2560 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2561
2562 return allOk;
2563 }
2564
2565 case glu::SHADERTYPE_COMPUTE:
2566 {
2567 const struct
2568 {
2569 glw::GLenum pname;
2570 int usage;
2571 } restrictions[] =
2572 {
2573 { GL_MAX_COMPUTE_UNIFORM_BLOCKS, usage.numUniformBlocks },
2574 { GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, usage.numSamplers },
2575 { GL_MAX_COMPUTE_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
2576 { GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2577 { GL_MAX_COMPUTE_ATOMIC_COUNTERS, usage.numAtomicCounters },
2578 { GL_MAX_COMPUTE_IMAGE_UNIFORMS, usage.numImages },
2579 { GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, usage.numCombinedUniformComponents },
2580 { GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2581 };
2582
2583 bool allOk = true;
2584
2585 log << tcu::TestLog::Message << "Compute shader:" << tcu::TestLog::EndMessage;
2586 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2587 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2588
2589 return allOk;
2590 }
2591
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002592 case glu::SHADERTYPE_GEOMETRY:
2593 {
2594 const int totalOutputComponents = program->getGeometryNumOutputVertices() * usage.numOutputComponents;
2595 const struct
2596 {
2597 glw::GLenum pname;
2598 int usage;
2599 } restrictions[] =
2600 {
2601 { GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
2602 { GL_MAX_GEOMETRY_UNIFORM_BLOCKS, usage.numUniformBlocks },
2603 { GL_MAX_GEOMETRY_INPUT_COMPONENTS, usage.numInputComponents },
2604 { GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, usage.numOutputComponents },
2605 { GL_MAX_GEOMETRY_OUTPUT_VERTICES, (int)program->getGeometryNumOutputVertices() },
2606 { GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, totalOutputComponents },
2607 { GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, usage.numSamplers },
2608 { GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2609 { GL_MAX_GEOMETRY_ATOMIC_COUNTERS, usage.numAtomicCounters },
2610 { GL_MAX_GEOMETRY_IMAGE_UNIFORMS, usage.numImages },
2611 { GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2612 };
2613
2614 bool allOk = true;
2615
2616 log << tcu::TestLog::Message << "Geometry shader:" << tcu::TestLog::EndMessage;
2617 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2618 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2619
2620 return allOk;
2621 }
2622
2623 case glu::SHADERTYPE_TESSELLATION_CONTROL:
2624 {
2625 const int totalOutputComponents = program->getTessellationNumOutputPatchVertices() * usage.numOutputComponents + usage.numPatchOutputComponents;
2626 const struct
2627 {
2628 glw::GLenum pname;
2629 int usage;
2630 } restrictions[] =
2631 {
2632 { GL_MAX_PATCH_VERTICES, (int)program->getTessellationNumOutputPatchVertices() },
2633 { GL_MAX_TESS_PATCH_COMPONENTS, usage.numPatchOutputComponents },
2634 { GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
2635 { GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, usage.numUniformBlocks },
2636 { GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, usage.numInputComponents },
2637 { GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, usage.numOutputComponents },
2638 { GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS, totalOutputComponents },
2639 { GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, usage.numSamplers },
2640 { GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2641 { GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, usage.numAtomicCounters },
2642 { GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2643 };
2644
2645 bool allOk = true;
2646
2647 log << tcu::TestLog::Message << "Tessellation control shader:" << tcu::TestLog::EndMessage;
2648 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2649 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2650
2651 return allOk;
2652 }
2653
2654 case glu::SHADERTYPE_TESSELLATION_EVALUATION:
2655 {
2656 const struct
2657 {
2658 glw::GLenum pname;
2659 int usage;
2660 } restrictions[] =
2661 {
2662 { GL_MAX_PATCH_VERTICES, (int)program->getTessellationNumOutputPatchVertices() },
2663 { GL_MAX_TESS_PATCH_COMPONENTS, usage.numPatchInputComponents },
2664 { GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, usage.numDefaultBlockUniformComponents },
2665 { GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, usage.numUniformBlocks },
2666 { GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, usage.numInputComponents },
2667 { GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, usage.numOutputComponents },
2668 { GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, usage.numSamplers },
2669 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2670 { GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, usage.numAtomicCounters },
2671 { GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2672 };
2673
2674 bool allOk = true;
2675
2676 log << tcu::TestLog::Message << "Tessellation evaluation shader:" << tcu::TestLog::EndMessage;
2677 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2678 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2679
2680 return allOk;
2681 }
2682
Jarkko Poyry3c827362014-09-02 11:48:52 +03002683 default:
2684 DE_ASSERT(false);
2685 return false;
2686 }
2687}
2688
2689static bool checkProgramCombinedResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2690{
2691 const ProgramInterfaceDefinition::ProgramResourceUsage usage = getCombinedProgramResourceUsage(program);
2692
2693 const struct
2694 {
2695 glw::GLenum pname;
2696 int usage;
2697 } restrictions[] =
2698 {
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002699 { GL_MAX_UNIFORM_BUFFER_BINDINGS, usage.uniformBufferMaxBinding+1 },
2700 { GL_MAX_UNIFORM_BLOCK_SIZE, usage.uniformBufferMaxSize },
2701 { GL_MAX_COMBINED_UNIFORM_BLOCKS, usage.numUniformBlocks },
2702 { GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, usage.numCombinedVertexUniformComponents },
2703 { GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, usage.numCombinedFragmentUniformComponents },
2704 { GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, usage.numCombinedGeometryUniformComponents },
2705 { GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, usage.numCombinedTessControlUniformComponents },
2706 { GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS, usage.numCombinedTessEvalUniformComponents },
2707 { GL_MAX_VARYING_COMPONENTS, usage.numVaryingComponents },
2708 { GL_MAX_VARYING_VECTORS, usage.numVaryingVectors },
2709 { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, usage.numCombinedSamplers },
2710 { GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, usage.numCombinedOutputResources },
2711 { GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, usage.atomicCounterBufferMaxBinding+1 },
2712 { GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, usage.atomicCounterBufferMaxSize },
2713 { GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, usage.numAtomicCounterBuffers },
2714 { GL_MAX_COMBINED_ATOMIC_COUNTERS, usage.numAtomicCounters },
2715 { GL_MAX_IMAGE_UNITS, usage.maxImageBinding+1 },
2716 { GL_MAX_COMBINED_IMAGE_UNIFORMS, usage.numCombinedImages },
2717 { GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, usage.shaderStorageBufferMaxBinding+1 },
2718 { GL_MAX_SHADER_STORAGE_BLOCK_SIZE, usage.shaderStorageBufferMaxSize },
2719 { GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, usage.numShaderStorageBlocks },
2720 { GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, usage.numXFBInterleavedComponents },
2721 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, usage.numXFBSeparateAttribs },
2722 { GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, usage.numXFBSeparateComponents },
2723 { GL_MAX_DRAW_BUFFERS, usage.fragmentOutputMaxBinding+1 },
Jarkko Poyry3c827362014-09-02 11:48:52 +03002724 };
2725
2726 bool allOk = true;
2727
2728 log << tcu::TestLog::Message << "Program combined:" << tcu::TestLog::EndMessage;
2729 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(restrictions); ++ndx)
2730 allOk &= checkLimit(restrictions[ndx].pname, restrictions[ndx].usage, gl, log);
2731
2732 return allOk;
2733}
2734
2735void checkProgramResourceUsage (const ProgramInterfaceDefinition::Program* program, const glw::Functions& gl, tcu::TestLog& log)
2736{
2737 bool limitExceeded = false;
2738
2739 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx)
Jarkko Pöyryc423ce62015-02-12 22:51:46 -08002740 limitExceeded |= !checkShaderResourceUsage(program, program->getShaders()[shaderNdx], gl, log);
Jarkko Poyry3c827362014-09-02 11:48:52 +03002741
2742 limitExceeded |= !checkProgramCombinedResourceUsage(program, gl, log);
2743
2744 if (limitExceeded)
2745 {
2746 log << tcu::TestLog::Message << "One or more resource limits exceeded" << tcu::TestLog::EndMessage;
2747 throw tcu::NotSupportedError("one or more resource limits exceeded");
2748 }
2749}
2750
2751} // Functional
2752} // gles31
2753} // deqp