xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fUniformLocationTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Explicit uniform location tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fUniformLocationTests.hpp"
25 
26 #include "tcuTestLog.hpp"
27 #include "tcuTextureUtil.hpp"
28 #include "tcuVectorUtil.hpp"
29 #include "tcuCommandLine.hpp"
30 
31 #include "glsShaderLibrary.hpp"
32 #include "glsTextureTestUtil.hpp"
33 
34 #include "gluShaderProgram.hpp"
35 #include "gluTexture.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluVarType.hpp"
38 #include "gluVarTypeUtil.hpp"
39 
40 #include "glwFunctions.hpp"
41 #include "glwEnums.hpp"
42 #include "sglrContextUtil.hpp"
43 
44 #include "deStringUtil.hpp"
45 #include "deUniquePtr.hpp"
46 #include "deString.h"
47 #include "deRandom.hpp"
48 #include "deInt32.h"
49 
50 #include <set>
51 #include <map>
52 
53 namespace deqp
54 {
55 namespace gles31
56 {
57 namespace Functional
58 {
59 namespace
60 {
61 
62 using de::UniquePtr;
63 using glu::VarType;
64 using std::map;
65 using std::string;
66 using std::vector;
67 
68 struct UniformInfo
69 {
70     enum ShaderStage
71     {
72         SHADERSTAGE_NONE     = 0,
73         SHADERSTAGE_VERTEX   = (1 << 0),
74         SHADERSTAGE_FRAGMENT = (1 << 1),
75         SHADERSTAGE_BOTH     = (SHADERSTAGE_VERTEX | SHADERSTAGE_FRAGMENT),
76     };
77 
78     VarType type;
79     ShaderStage declareLocation; // support declarations with/without layout qualifiers, needed for linkage testing
80     ShaderStage layoutLocation;
81     ShaderStage checkLocation;
82     int location; // -1 for unset
83 
UniformInfodeqp::gles31::Functional::__anon257b02870111::UniformInfo84     UniformInfo(VarType type_, ShaderStage declareLocation_, ShaderStage layoutLocation_, ShaderStage checkLocation_,
85                 int location_ = -1)
86         : type(type_)
87         , declareLocation(declareLocation_)
88         , layoutLocation(layoutLocation_)
89         , checkLocation(checkLocation_)
90         , location(location_)
91     {
92     }
93 };
94 
95 class UniformLocationCase : public tcu::TestCase
96 {
97 public:
98     UniformLocationCase(tcu::TestContext &context, glu::RenderContext &renderContext, const char *name,
99                         const char *desc, const vector<UniformInfo> &uniformInfo);
~UniformLocationCase(void)100     virtual ~UniformLocationCase(void)
101     {
102     }
103 
104     virtual IterateResult iterate(void);
105 
106 protected:
107     IterateResult run(const vector<UniformInfo> &uniformList);
108     static glu::ProgramSources genShaderSources(const vector<UniformInfo> &uniformList);
109     bool verifyLocations(const glu::ShaderProgram &program, const vector<UniformInfo> &uniformList);
110     void render(const glu::ShaderProgram &program, const vector<UniformInfo> &uniformList);
111     static bool verifyResult(const tcu::ConstPixelBufferAccess &access);
112 
113     static float getExpectedValue(glu::DataType type, int id, const char *name);
114 
115     de::MovePtr<glu::Texture2D> createTexture(glu::DataType samplerType, float redChannelValue, int binding);
116 
117     glu::RenderContext &m_renderCtx;
118 
119     const vector<UniformInfo> m_uniformInfo;
120 
121     enum
122     {
123         RENDER_SIZE = 16
124     };
125 };
126 
getUniformName(int ndx,const glu::VarType & type,const glu::TypeComponentVector & path)127 string getUniformName(int ndx, const glu::VarType &type, const glu::TypeComponentVector &path)
128 {
129     std::ostringstream buff;
130     buff << "uni" << ndx << glu::TypeAccessFormat(type, path);
131 
132     return buff.str();
133 }
134 
getFirstComponentName(const glu::VarType & type)135 string getFirstComponentName(const glu::VarType &type)
136 {
137     std::ostringstream buff;
138     if (glu::isDataTypeVector(type.getBasicType()))
139         buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).component(0).getPath());
140     else if (glu::isDataTypeMatrix(type.getBasicType()))
141         buff << glu::TypeAccessFormat(type, glu::SubTypeAccess(type).column(0).component(0).getPath());
142 
143     return buff.str();
144 }
145 
UniformLocationCase(tcu::TestContext & context,glu::RenderContext & renderContext,const char * name,const char * desc,const vector<UniformInfo> & uniformInfo)146 UniformLocationCase::UniformLocationCase(tcu::TestContext &context, glu::RenderContext &renderContext, const char *name,
147                                          const char *desc, const vector<UniformInfo> &uniformInfo)
148     : TestCase(context, name, desc)
149     , m_renderCtx(renderContext)
150     , m_uniformInfo(uniformInfo)
151 {
152 }
153 
154 // [from, to]
shuffledRange(int from,int to,int seed)155 std::vector<int> shuffledRange(int from, int to, int seed)
156 {
157     const int count = to - from;
158 
159     vector<int> retval(count);
160     de::Random rng(seed);
161 
162     DE_ASSERT(count > 0);
163 
164     for (int ndx = 0; ndx < count; ndx++)
165         retval[ndx] = ndx + from;
166 
167     rng.shuffle(retval.begin(), retval.end());
168     return retval;
169 }
170 
getDataTypeSamplerSampleType(glu::DataType type)171 glu::DataType getDataTypeSamplerSampleType(glu::DataType type)
172 {
173     using namespace glu;
174 
175     if (type >= TYPE_SAMPLER_1D && type <= TYPE_SAMPLER_3D)
176         return TYPE_FLOAT_VEC4;
177     else if (type >= TYPE_INT_SAMPLER_1D && type <= TYPE_INT_SAMPLER_3D)
178         return TYPE_INT_VEC4;
179     else if (type >= TYPE_UINT_SAMPLER_1D && type <= TYPE_UINT_SAMPLER_3D)
180         return TYPE_UINT_VEC4;
181     else if (type >= TYPE_SAMPLER_1D_SHADOW && type <= TYPE_SAMPLER_2D_ARRAY_SHADOW)
182         return TYPE_FLOAT;
183     else
184         DE_FATAL("Unknown sampler type");
185 
186     return TYPE_INVALID;
187 }
188 
189 // A (hopefully) unique value for a uniform. For multi-component types creates only one value. Values are in the range [0,1] for floats, [-128, 127] for ints, [0,255] for uints and 0/1 for booleans. Samplers are treated according to the types they return.
getExpectedValue(glu::DataType type,int id,const char * name)190 float UniformLocationCase::getExpectedValue(glu::DataType type, int id, const char *name)
191 {
192     const uint32_t hash = deStringHash(name) + deInt32Hash(id);
193 
194     glu::DataType adjustedType = type;
195 
196     if (glu::isDataTypeSampler(type))
197         adjustedType = getDataTypeSamplerSampleType(type);
198 
199     if (glu::isDataTypeIntOrIVec(adjustedType))
200         return float(hash % 128);
201     else if (glu::isDataTypeUintOrUVec(adjustedType))
202         return float(hash % 255);
203     else if (glu::isDataTypeFloatOrVec(adjustedType))
204         return float(hash % 255) / 255.0f;
205     else if (glu::isDataTypeBoolOrBVec(adjustedType))
206         return float(hash % 2);
207     else
208         DE_FATAL("Unkown primitive type");
209 
210     return glu::TYPE_INVALID;
211 }
212 
iterate(void)213 UniformLocationCase::IterateResult UniformLocationCase::iterate(void)
214 {
215     return run(m_uniformInfo);
216 }
217 
run(const vector<UniformInfo> & uniformList)218 UniformLocationCase::IterateResult UniformLocationCase::run(const vector<UniformInfo> &uniformList)
219 {
220     using gls::TextureTestUtil::RandomViewport;
221 
222     const glu::ProgramSources sources = genShaderSources(uniformList);
223     const glu::ShaderProgram program(m_renderCtx, sources);
224     const int baseSeed       = m_testCtx.getCommandLine().getBaseSeed();
225     const glw::Functions &gl = m_renderCtx.getFunctions();
226     const RandomViewport viewport(m_renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE,
227                                   deStringHash(getName()) + baseSeed);
228 
229     tcu::Surface rendered(RENDER_SIZE, RENDER_SIZE);
230 
231     if (!verifyLocations(program, uniformList))
232         return STOP;
233 
234     gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
235     gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
236     gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
237 
238     render(program, uniformList);
239 
240     glu::readPixels(m_renderCtx, viewport.x, viewport.y, rendered.getAccess());
241     GLU_EXPECT_NO_ERROR(gl.getError(), "error in readPixels");
242 
243     if (!verifyResult(rendered.getAccess()))
244     {
245         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader produced incorrect result");
246         return STOP;
247     }
248 
249     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
250     return STOP;
251 }
252 
genShaderSources(const vector<UniformInfo> & uniformList)253 glu::ProgramSources UniformLocationCase::genShaderSources(const vector<UniformInfo> &uniformList)
254 {
255     std::ostringstream vertDecl, vertMain, fragDecl, fragMain;
256 
257     vertDecl << "#version 310 es\n"
258              << "precision highp float;\n"
259              << "precision highp int;\n"
260              << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
261              << "in highp vec4 a_position;\n"
262              << "out highp vec4 v_color;\n";
263     fragDecl << "#version 310 es\n\n"
264              << "precision highp float;\n"
265              << "precision highp int;\n"
266              << "float verify(float val, float ref) { return float(abs(val-ref) < 0.05); }\n\n"
267              << "in highp vec4 v_color;\n"
268              << "layout(location = 0) out mediump vec4 o_color;\n\n";
269 
270     vertMain << "void main()\n{\n"
271              << "    gl_Position = a_position;\n"
272              << "    v_color = vec4(1.0);\n";
273 
274     fragMain << "void main()\n{\n"
275              << "    o_color = v_color;\n";
276 
277     std::set<const glu::StructType *> declaredStructs;
278 
279     // Declare uniforms
280     for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
281     {
282         const UniformInfo &uniformInfo = uniformList[uniformNdx];
283 
284         const bool declareInVert = (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_VERTEX) != 0;
285         const bool declareInFrag = (uniformInfo.declareLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
286         const bool layoutInVert  = (uniformInfo.layoutLocation & UniformInfo::SHADERSTAGE_VERTEX) != 0;
287         const bool layoutInFrag  = (uniformInfo.layoutLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
288         const bool checkInVert   = (uniformInfo.checkLocation & UniformInfo::SHADERSTAGE_VERTEX) != 0;
289         const bool checkInFrag   = (uniformInfo.checkLocation & UniformInfo::SHADERSTAGE_FRAGMENT) != 0;
290 
291         const string layout =
292             uniformInfo.location >= 0 ? "layout(location = " + de::toString(uniformInfo.location) + ") " : "";
293         const string uniName = "uni" + de::toString(uniformNdx);
294 
295         int location     = uniformInfo.location;
296         int subTypeIndex = 0;
297 
298         DE_ASSERT((declareInVert && layoutInVert) || !layoutInVert); // Cannot have layout without declaration
299         DE_ASSERT((declareInFrag && layoutInFrag) || !layoutInFrag);
300         DE_ASSERT(location < 0 || (layoutInVert || layoutInFrag)); // Cannot have location without layout
301 
302         // struct definitions
303         if (uniformInfo.type.isStructType())
304         {
305             const glu::StructType *const structType = uniformInfo.type.getStructPtr();
306             if (!declaredStructs.count(structType))
307             {
308                 if (declareInVert)
309                     vertDecl << glu::declare(structType, 0) << ";\n";
310 
311                 if (declareInFrag)
312                     fragDecl << glu::declare(structType, 0) << ";\n";
313 
314                 declaredStructs.insert(structType);
315             }
316         }
317 
318         if (declareInVert)
319             vertDecl << "uniform " << (layoutInVert ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
320 
321         if (declareInFrag)
322             fragDecl << "uniform " << (layoutInFrag ? layout : "") << glu::declare(uniformInfo.type, uniName) << ";\n";
323 
324         // Anything that needs to be done for each enclosed primitive type
325         for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type);
326              subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
327         {
328             const glu::VarType subType     = glu::getVarType(uniformInfo.type, subTypeIter.getPath());
329             const glu::DataType scalarType = glu::getDataTypeScalarType(subType.getBasicType());
330             const char *const typeName     = glu::getDataTypeName(scalarType);
331             const string expectValue       = de::floatToString(
332                 getExpectedValue(scalarType, location >= 0 ? location + subTypeIndex : -1, typeName), 3);
333 
334             if (glu::isDataTypeSampler(scalarType))
335             {
336                 if (checkInVert)
337                     vertMain << "    v_color.rgb *= verify(float( texture(" << uniName
338                              << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath()) << ", vec2(0.5)).r), "
339                              << expectValue << ");\n";
340                 if (checkInFrag)
341                     fragMain << "    o_color.rgb *= verify(float( texture(" << uniName
342                              << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath()) << ", vec2(0.5)).r), "
343                              << expectValue << ");\n";
344             }
345             else
346             {
347                 if (checkInVert)
348                     vertMain << "    v_color.rgb *= verify(float(" << uniName
349                              << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
350                              << getFirstComponentName(subType) << "), " << expectValue << ");\n";
351                 if (checkInFrag)
352                     fragMain << "    o_color.rgb *= verify(float(" << uniName
353                              << glu::TypeAccessFormat(uniformInfo.type, subTypeIter.getPath())
354                              << getFirstComponentName(subType) << "), " << expectValue << ");\n";
355             }
356         }
357     }
358 
359     vertMain << "}\n";
360     fragMain << "}\n";
361 
362     return glu::makeVtxFragSources(vertDecl.str() + vertMain.str(), fragDecl.str() + fragMain.str());
363 }
364 
verifyLocations(const glu::ShaderProgram & program,const vector<UniformInfo> & uniformList)365 bool UniformLocationCase::verifyLocations(const glu::ShaderProgram &program, const vector<UniformInfo> &uniformList)
366 {
367     using tcu::TestLog;
368 
369     const glw::Functions &gl = m_renderCtx.getFunctions();
370     const bool vertexOk      = program.getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk;
371     const bool fragmentOk    = program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk;
372     const bool linkOk        = program.getProgramInfo().linkOk;
373     const uint32_t programID = program.getProgram();
374 
375     TestLog &log = m_testCtx.getLog();
376     std::set<int> usedLocations;
377 
378     log << program;
379 
380     if (!vertexOk || !fragmentOk || !linkOk)
381     {
382         log << TestLog::Message << "ERROR: shader failed to compile/link" << TestLog::EndMessage;
383         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader failed to compile/link");
384         return false;
385     }
386 
387     for (int uniformNdx = 0; uniformNdx < int(uniformList.size()); uniformNdx++)
388     {
389         const UniformInfo &uniformInfo = uniformList[uniformNdx];
390         int subTypeIndex               = 0;
391 
392         for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type);
393              subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++, subTypeIndex++)
394         {
395             const string name   = getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
396             const int gotLoc    = gl.getUniformLocation(programID, name.c_str());
397             const int expectLoc = uniformInfo.location >= 0 ? uniformInfo.location + subTypeIndex : -1;
398 
399             if (expectLoc >= 0)
400             {
401                 if (uniformInfo.checkLocation == 0 && gotLoc == -1)
402                     continue;
403 
404                 if (gotLoc != expectLoc)
405                 {
406                     log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc
407                         << " when it should have been in " << expectLoc << TestLog::EndMessage;
408                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect uniform location");
409                     return false;
410                 }
411 
412                 if (usedLocations.find(expectLoc) != usedLocations.end())
413                 {
414                     log << TestLog::Message << "ERROR: expected uniform " << name << " in location " << gotLoc
415                         << " but it has already been used" << TestLog::EndMessage;
416                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
417                     return false;
418                 }
419 
420                 usedLocations.insert(expectLoc);
421             }
422             else if (gotLoc >= 0)
423             {
424                 if (usedLocations.count(gotLoc))
425                 {
426                     log << TestLog::Message << "ERROR: found uniform " << name << " in location " << gotLoc
427                         << " which has already been used" << TestLog::EndMessage;
428                     m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Overlapping uniform location");
429                     return false;
430                 }
431 
432                 usedLocations.insert(gotLoc);
433             }
434         }
435     }
436 
437     return true;
438 }
439 
440 // Check that shader output is white (or very close to it)
verifyResult(const tcu::ConstPixelBufferAccess & access)441 bool UniformLocationCase::verifyResult(const tcu::ConstPixelBufferAccess &access)
442 {
443     using tcu::Vec4;
444 
445     const Vec4 threshold(0.1f, 0.1f, 0.1f, 0.1f);
446     const Vec4 reference(1.0f, 1.0f, 1.0f, 1.0f);
447 
448     for (int y = 0; y < access.getHeight(); y++)
449     {
450         for (int x = 0; x < access.getWidth(); x++)
451         {
452             const Vec4 diff = abs(access.getPixel(x, y) - reference);
453 
454             if (!boolAll(lessThanEqual(diff, threshold)))
455                 return false;
456         }
457     }
458 
459     return true;
460 }
461 
462 // get a 4 channel 8 bits each texture format that is usable by the given sampler type
getTextureFormat(glu::DataType samplerType)463 uint32_t getTextureFormat(glu::DataType samplerType)
464 {
465     using namespace glu;
466 
467     switch (samplerType)
468     {
469     case TYPE_SAMPLER_1D:
470     case TYPE_SAMPLER_2D:
471     case TYPE_SAMPLER_CUBE:
472     case TYPE_SAMPLER_2D_ARRAY:
473     case TYPE_SAMPLER_3D:
474         return GL_RGBA8;
475 
476     case TYPE_INT_SAMPLER_1D:
477     case TYPE_INT_SAMPLER_2D:
478     case TYPE_INT_SAMPLER_CUBE:
479     case TYPE_INT_SAMPLER_2D_ARRAY:
480     case TYPE_INT_SAMPLER_3D:
481         return GL_RGBA8I;
482 
483     case TYPE_UINT_SAMPLER_1D:
484     case TYPE_UINT_SAMPLER_2D:
485     case TYPE_UINT_SAMPLER_CUBE:
486     case TYPE_UINT_SAMPLER_2D_ARRAY:
487     case TYPE_UINT_SAMPLER_3D:
488         return GL_RGBA8UI;
489 
490     default:
491         DE_FATAL("Unsupported (sampler) type");
492         return 0;
493     }
494 }
495 
496 // create a texture suitable for sampling by the given sampler type and bind it
createTexture(glu::DataType samplerType,float redChannelValue,int binding)497 de::MovePtr<glu::Texture2D> UniformLocationCase::createTexture(glu::DataType samplerType, float redChannelValue,
498                                                                int binding)
499 {
500     using namespace glu;
501 
502     const glw::Functions &gl = m_renderCtx.getFunctions();
503 
504     const uint32_t format = getTextureFormat(samplerType);
505     de::MovePtr<Texture2D> tex;
506 
507     tex = de::MovePtr<Texture2D>(new Texture2D(m_renderCtx, format, 16, 16));
508 
509     tex->getRefTexture().allocLevel(0);
510 
511     if (format == GL_RGBA8I || format == GL_RGBA8UI)
512         tcu::clear(tex->getRefTexture().getLevel(0), tcu::IVec4(int(redChannelValue), 0, 0, 0));
513     else
514         tcu::clear(tex->getRefTexture().getLevel(0), tcu::Vec4(redChannelValue, 0.0f, 0.0f, 1.0f));
515 
516     gl.activeTexture(GL_TEXTURE0 + binding);
517     tex->upload();
518 
519     gl.bindTexture(GL_TEXTURE_2D, tex->getGLTexture());
520     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
521     gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
522 
523     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase: texture upload");
524 
525     return tex;
526 }
527 
render(const glu::ShaderProgram & program,const vector<UniformInfo> & uniformList)528 void UniformLocationCase::render(const glu::ShaderProgram &program, const vector<UniformInfo> &uniformList)
529 {
530     using de::MovePtr;
531     using glu::Texture2D;
532     typedef vector<Texture2D *> TextureList;
533 
534     const glw::Functions &gl = m_renderCtx.getFunctions();
535     const uint32_t programID = program.getProgram();
536     const int32_t posLoc     = gl.getAttribLocation(programID, "a_position");
537 
538     // Vertex data.
539     const float position[]   = {-1.0f, -1.0f, 0.1f, 1.0f, -1.0f, 1.0f, 0.1f, 1.0f,
540                                 1.0f,  -1.0f, 0.1f, 1.0f, 1.0f,  1.0f, 0.1f, 1.0f};
541     const void *positionPtr  = &position[0];
542     const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
543     const void *indicesPtr   = &indices[0];
544 
545     // some buffers to feed to the GPU, only the first element is relevant since the others are never verified
546     float floatBuf[16]  = {0.0f};
547     int32_t intBuf[4]   = {0};
548     uint32_t uintBuf[4] = {0};
549     uint32_t vao        = 0;
550     uint32_t attribVbo  = 0;
551     uint32_t elementVbo = 0;
552 
553     TextureList texList;
554 
555     bool isGL45 = glu::contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 5));
556     if (isGL45)
557     {
558         gl.genVertexArrays(1, &vao);
559         gl.bindVertexArray(vao);
560 
561         gl.genBuffers(1, &attribVbo);
562         gl.genBuffers(1, &elementVbo);
563 
564         gl.bindBuffer(GL_ARRAY_BUFFER, attribVbo);
565         gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(DE_LENGTH_OF_ARRAY(position) * sizeof(float)), position,
566                       GL_STATIC_DRAW);
567         GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase::render");
568 
569         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementVbo);
570         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(DE_LENGTH_OF_ARRAY(indices) * sizeof(uint16_t)),
571                       indices, GL_STATIC_DRAW);
572         GLU_EXPECT_NO_ERROR(gl.getError(), "UniformLocationCase::render");
573 
574         positionPtr = 0;
575         indicesPtr  = 0;
576     }
577 
578     TCU_CHECK(posLoc >= 0);
579     gl.useProgram(programID);
580 
581     try
582     {
583 
584         // Set uniforms
585         for (unsigned int uniformNdx = 0; uniformNdx < uniformList.size(); uniformNdx++)
586         {
587             const UniformInfo &uniformInfo = uniformList[uniformNdx];
588             int expectedLocation           = uniformInfo.location;
589 
590             for (glu::BasicTypeIterator subTypeIter = glu::BasicTypeIterator::begin(&uniformInfo.type);
591                  subTypeIter != glu::BasicTypeIterator::end(&uniformInfo.type); subTypeIter++)
592             {
593                 const glu::VarType type        = glu::getVarType(uniformInfo.type, subTypeIter.getPath());
594                 const string name              = getUniformName(uniformNdx, uniformInfo.type, subTypeIter.getPath());
595                 const int gotLoc               = gl.getUniformLocation(programID, name.c_str());
596                 const glu::DataType scalarType = glu::getDataTypeScalarType(type.getBasicType());
597                 const char *const typeName     = glu::getDataTypeName(scalarType);
598                 const float expectedValue      = getExpectedValue(scalarType, expectedLocation, typeName);
599 
600                 if (glu::isDataTypeSampler(scalarType))
601                 {
602                     const int binding = (int)texList.size();
603 
604                     texList.push_back(createTexture(scalarType, expectedValue, binding).release());
605                     gl.uniform1i(gotLoc, binding);
606                 }
607                 else if (gotLoc >= 0)
608                 {
609                     floatBuf[0] = expectedValue;
610                     intBuf[0]   = int(expectedValue);
611                     uintBuf[0]  = uint32_t(expectedValue);
612 
613                     m_testCtx.getLog() << tcu::TestLog::Message << "Set uniform " << name << " in location " << gotLoc
614                                        << " to " << expectedValue << tcu::TestLog::EndMessage;
615 
616                     switch (type.getBasicType())
617                     {
618                     case glu::TYPE_FLOAT:
619                         gl.uniform1fv(gotLoc, 1, floatBuf);
620                         break;
621                     case glu::TYPE_FLOAT_VEC2:
622                         gl.uniform2fv(gotLoc, 1, floatBuf);
623                         break;
624                     case glu::TYPE_FLOAT_VEC3:
625                         gl.uniform3fv(gotLoc, 1, floatBuf);
626                         break;
627                     case glu::TYPE_FLOAT_VEC4:
628                         gl.uniform4fv(gotLoc, 1, floatBuf);
629                         break;
630 
631                     case glu::TYPE_INT:
632                         gl.uniform1iv(gotLoc, 1, intBuf);
633                         break;
634                     case glu::TYPE_INT_VEC2:
635                         gl.uniform2iv(gotLoc, 1, intBuf);
636                         break;
637                     case glu::TYPE_INT_VEC3:
638                         gl.uniform3iv(gotLoc, 1, intBuf);
639                         break;
640                     case glu::TYPE_INT_VEC4:
641                         gl.uniform4iv(gotLoc, 1, intBuf);
642                         break;
643 
644                     case glu::TYPE_UINT:
645                         gl.uniform1uiv(gotLoc, 1, uintBuf);
646                         break;
647                     case glu::TYPE_UINT_VEC2:
648                         gl.uniform2uiv(gotLoc, 1, uintBuf);
649                         break;
650                     case glu::TYPE_UINT_VEC3:
651                         gl.uniform3uiv(gotLoc, 1, uintBuf);
652                         break;
653                     case glu::TYPE_UINT_VEC4:
654                         gl.uniform4uiv(gotLoc, 1, uintBuf);
655                         break;
656 
657                     case glu::TYPE_BOOL:
658                         gl.uniform1iv(gotLoc, 1, intBuf);
659                         break;
660                     case glu::TYPE_BOOL_VEC2:
661                         gl.uniform2iv(gotLoc, 1, intBuf);
662                         break;
663                     case glu::TYPE_BOOL_VEC3:
664                         gl.uniform3iv(gotLoc, 1, intBuf);
665                         break;
666                     case glu::TYPE_BOOL_VEC4:
667                         gl.uniform4iv(gotLoc, 1, intBuf);
668                         break;
669 
670                     case glu::TYPE_FLOAT_MAT2:
671                         gl.uniformMatrix2fv(gotLoc, 1, false, floatBuf);
672                         break;
673                     case glu::TYPE_FLOAT_MAT2X3:
674                         gl.uniformMatrix2x3fv(gotLoc, 1, false, floatBuf);
675                         break;
676                     case glu::TYPE_FLOAT_MAT2X4:
677                         gl.uniformMatrix2x4fv(gotLoc, 1, false, floatBuf);
678                         break;
679 
680                     case glu::TYPE_FLOAT_MAT3X2:
681                         gl.uniformMatrix3x2fv(gotLoc, 1, false, floatBuf);
682                         break;
683                     case glu::TYPE_FLOAT_MAT3:
684                         gl.uniformMatrix3fv(gotLoc, 1, false, floatBuf);
685                         break;
686                     case glu::TYPE_FLOAT_MAT3X4:
687                         gl.uniformMatrix3x4fv(gotLoc, 1, false, floatBuf);
688                         break;
689 
690                     case glu::TYPE_FLOAT_MAT4X2:
691                         gl.uniformMatrix4x2fv(gotLoc, 1, false, floatBuf);
692                         break;
693                     case glu::TYPE_FLOAT_MAT4X3:
694                         gl.uniformMatrix4x3fv(gotLoc, 1, false, floatBuf);
695                         break;
696                     case glu::TYPE_FLOAT_MAT4:
697                         gl.uniformMatrix4fv(gotLoc, 1, false, floatBuf);
698                         break;
699                     default:
700                         DE_ASSERT(false);
701                     }
702                 }
703 
704                 expectedLocation += expectedLocation >= 0;
705             }
706         }
707 
708         gl.enableVertexAttribArray(posLoc);
709         GLU_EXPECT_NO_ERROR(gl.getError(), "error in glEnableVertexAttribArray");
710         gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, positionPtr);
711         GLU_EXPECT_NO_ERROR(gl.getError(), "error in glVertexAttribPointer");
712 
713         gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, indicesPtr);
714         GLU_EXPECT_NO_ERROR(gl.getError(), "error in glDrawElements");
715 
716         gl.disableVertexAttribArray(posLoc);
717         GLU_EXPECT_NO_ERROR(gl.getError(), "error in glDisableVertexAttribArray");
718 
719         if (isGL45)
720         {
721             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
722             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
723 
724             gl.deleteBuffers(1, &attribVbo);
725             gl.deleteBuffers(1, &elementVbo);
726             gl.deleteVertexArrays(1, &vao);
727         }
728     }
729     catch (...)
730     {
731         for (int i = 0; i < int(texList.size()); i++)
732             delete texList[i];
733 
734         throw;
735     }
736 
737     for (int i = 0; i < int(texList.size()); i++)
738         delete texList[i];
739 }
740 
741 class MaxUniformLocationCase : public UniformLocationCase
742 {
743 public:
744     MaxUniformLocationCase(tcu::TestContext &context, glu::RenderContext &renderContext, const char *name,
745                            const char *desc, const vector<UniformInfo> &uniformInfo);
~MaxUniformLocationCase(void)746     virtual ~MaxUniformLocationCase(void)
747     {
748     }
749     virtual IterateResult iterate(void);
750 };
751 
MaxUniformLocationCase(tcu::TestContext & context,glu::RenderContext & renderContext,const char * name,const char * desc,const vector<UniformInfo> & uniformInfo)752 MaxUniformLocationCase::MaxUniformLocationCase(tcu::TestContext &context, glu::RenderContext &renderContext,
753                                                const char *name, const char *desc,
754                                                const vector<UniformInfo> &uniformInfo)
755     : UniformLocationCase(context, renderContext, name, desc, uniformInfo)
756 {
757     DE_ASSERT(!uniformInfo.empty());
758 }
759 
iterate(void)760 UniformLocationCase::IterateResult MaxUniformLocationCase::iterate(void)
761 {
762     int maxLocation                 = 1024;
763     vector<UniformInfo> uniformInfo = m_uniformInfo;
764 
765     m_renderCtx.getFunctions().getIntegerv(GL_MAX_UNIFORM_LOCATIONS, &maxLocation);
766 
767     uniformInfo[0].location = maxLocation - 1;
768 
769     return UniformLocationCase::run(uniformInfo);
770 }
771 
772 } // namespace
773 
UniformLocationTests(Context & context,bool isGL45)774 UniformLocationTests::UniformLocationTests(Context &context, bool isGL45)
775     : TestCaseGroup(context, "uniform_location", "Explicit uniform locations")
776     , m_isGL45(isGL45)
777 {
778 }
779 
~UniformLocationTests(void)780 UniformLocationTests::~UniformLocationTests(void)
781 {
782     for (int i = 0; i < int(structTypes.size()); i++)
783         delete structTypes[i];
784 }
785 
createVarType(glu::DataType type)786 glu::VarType createVarType(glu::DataType type)
787 {
788     return glu::VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP);
789 }
790 
init(void)791 void UniformLocationTests::init(void)
792 {
793     using namespace glu;
794 
795     const UniformInfo::ShaderStage checkStages[] = {UniformInfo::SHADERSTAGE_VERTEX, UniformInfo::SHADERSTAGE_FRAGMENT};
796     const char *stageNames[]                     = {"vertex", "fragment"};
797     const int maxLocations                       = 1024;
798     const int baseSeed                           = m_context.getTestContext().getCommandLine().getBaseSeed();
799 
800     const DataType primitiveTypes[] = {
801         TYPE_FLOAT,        TYPE_FLOAT_VEC2,     TYPE_FLOAT_VEC3,      TYPE_FLOAT_VEC4,
802 
803         TYPE_INT,          TYPE_INT_VEC2,       TYPE_INT_VEC3,        TYPE_INT_VEC4,
804 
805         TYPE_UINT,         TYPE_UINT_VEC2,      TYPE_UINT_VEC3,       TYPE_UINT_VEC4,
806 
807         TYPE_BOOL,         TYPE_BOOL_VEC2,      TYPE_BOOL_VEC3,       TYPE_BOOL_VEC4,
808 
809         TYPE_FLOAT_MAT2,   TYPE_FLOAT_MAT2X3,   TYPE_FLOAT_MAT2X4,    TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3,
810         TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT4X2,   TYPE_FLOAT_MAT4X3,    TYPE_FLOAT_MAT4,
811 
812         TYPE_SAMPLER_2D,   TYPE_INT_SAMPLER_2D, TYPE_UINT_SAMPLER_2D,
813     };
814 
815     const int maxPrimitiveTypeNdx = DE_LENGTH_OF_ARRAY(primitiveTypes) - 4;
816     DE_ASSERT(primitiveTypes[maxPrimitiveTypeNdx] == TYPE_FLOAT_MAT4);
817 
818     // Primitive type cases with trivial linkage
819     {
820         tcu::TestCaseGroup *const group =
821             new tcu::TestCaseGroup(m_testCtx, "basic", "Location specified with use, single shader stage");
822         de::Random rng(baseSeed + 0x1001);
823         addChild(group);
824 
825         for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
826         {
827             const DataType type = primitiveTypes[primitiveNdx];
828 
829             for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
830             {
831                 const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
832 
833                 vector<UniformInfo> config;
834 
835                 UniformInfo uniform(createVarType(type), checkStages[stageNdx], checkStages[stageNdx],
836                                     checkStages[stageNdx], rng.getInt(0, maxLocations - 1));
837 
838                 config.push_back(uniform);
839                 group->addChild(new UniformLocationCase(m_testCtx, m_context.getRenderContext(), name.c_str(),
840                                                         name.c_str(), config));
841             }
842         }
843     }
844 
845     // Arrays
846     {
847         tcu::TestCaseGroup *const group =
848             new tcu::TestCaseGroup(m_testCtx, "array", "Array location specified with use, single shader stage");
849         de::Random rng(baseSeed + 0x2001);
850         addChild(group);
851 
852         for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
853         {
854             const DataType type = primitiveTypes[primitiveNdx];
855 
856             for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
857             {
858 
859                 const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
860 
861                 vector<UniformInfo> config;
862 
863                 UniformInfo uniform(VarType(createVarType(type), 8), checkStages[stageNdx], checkStages[stageNdx],
864                                     checkStages[stageNdx], rng.getInt(0, maxLocations - 1 - 8));
865 
866                 config.push_back(uniform);
867                 group->addChild(new UniformLocationCase(m_testCtx, m_context.getRenderContext(), name.c_str(),
868                                                         name.c_str(), config));
869             }
870         }
871     }
872 
873     // Nested Arrays
874     {
875         tcu::TestCaseGroup *const group =
876             new tcu::TestCaseGroup(m_testCtx, "nested_array", "Array location specified with use, single shader stage");
877         de::Random rng(baseSeed + 0x3001);
878         addChild(group);
879 
880         for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
881         {
882             const DataType type = primitiveTypes[primitiveNdx];
883 
884             for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
885             {
886                 const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
887                 // stay comfortably within minimum max uniform component count (896 in fragment) and sampler count with all types
888                 const int arraySize = (getDataTypeScalarSize(type) > 4 || isDataTypeSampler(type)) ? 3 : 7;
889 
890                 vector<UniformInfo> config;
891 
892                 UniformInfo uniform(VarType(VarType(createVarType(type), arraySize), arraySize), checkStages[stageNdx],
893                                     checkStages[stageNdx], checkStages[stageNdx],
894                                     rng.getInt(0, maxLocations - 1 - arraySize * arraySize));
895 
896                 config.push_back(uniform);
897                 group->addChild(new UniformLocationCase(m_testCtx, m_context.getRenderContext(), name.c_str(),
898                                                         name.c_str(), config));
899             }
900         }
901     }
902 
903     // Structs
904     {
905         tcu::TestCaseGroup *const group =
906             new tcu::TestCaseGroup(m_testCtx, "struct", "Struct location, random contents & declaration location");
907         de::Random rng(baseSeed + 0x4001);
908         addChild(group);
909 
910         for (int caseNdx = 0; caseNdx < 16; caseNdx++)
911         {
912             typedef UniformInfo::ShaderStage Stage;
913 
914             const string name = "case_" + de::toString(caseNdx);
915 
916             const Stage layoutLoc  = Stage(rng.getUint32() & 0x3);
917             const Stage declareLoc = Stage((rng.getUint32() & 0x3) | layoutLoc);
918             const Stage verifyLoc  = Stage((rng.getUint32() & 0x3) & declareLoc);
919             const int location     = layoutLoc ? rng.getInt(0, maxLocations - 1 - 5) : -1;
920 
921             StructType *structProto = new StructType("S");
922 
923             structTypes.push_back(structProto);
924 
925             structProto->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
926             structProto->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
927             structProto->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
928             structProto->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
929             structProto->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
930 
931             {
932                 vector<UniformInfo> config;
933 
934                 config.push_back(UniformInfo(VarType(structProto), declareLoc, layoutLoc, verifyLoc, location));
935                 group->addChild(new UniformLocationCase(m_testCtx, m_context.getRenderContext(), name.c_str(),
936                                                         name.c_str(), config));
937             }
938         }
939     }
940 
941     // Nested Structs
942     {
943         tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(
944             m_testCtx, "nested_struct", "Struct location specified with use, single shader stage");
945         de::Random rng(baseSeed + 0x5001);
946 
947         addChild(group);
948 
949         for (int caseNdx = 0; caseNdx < 16; caseNdx++)
950         {
951             typedef UniformInfo::ShaderStage Stage;
952 
953             const string name = "case_" + de::toString(caseNdx);
954             const int baseLoc = rng.getInt(0, maxLocations - 1 - 60);
955 
956             // Structs need to be added in the order of their declaration
957             const Stage layoutLocs[] = {
958                 Stage(rng.getUint32() & 0x3),
959                 Stage(rng.getUint32() & 0x3),
960                 Stage(rng.getUint32() & 0x3),
961                 Stage(rng.getUint32() & 0x3),
962             };
963 
964             const uint32_t tempDecl[] = {
965                 (rng.getUint32() & 0x3) | layoutLocs[0],
966                 (rng.getUint32() & 0x3) | layoutLocs[1],
967                 (rng.getUint32() & 0x3) | layoutLocs[2],
968                 (rng.getUint32() & 0x3) | layoutLocs[3],
969             };
970 
971             // Component structs need to be declared if anything using them is declared
972             const Stage declareLocs[] = {
973                 Stage(tempDecl[0] | tempDecl[1] | tempDecl[2] | tempDecl[3]),
974                 Stage(tempDecl[1] | tempDecl[2] | tempDecl[3]),
975                 Stage(tempDecl[2] | tempDecl[3]),
976                 Stage(tempDecl[3]),
977             };
978 
979             const Stage verifyLocs[] = {
980                 Stage(rng.getUint32() & 0x3 & declareLocs[0]),
981                 Stage(rng.getUint32() & 0x3 & declareLocs[1]),
982                 Stage(rng.getUint32() & 0x3 & declareLocs[2]),
983                 Stage(rng.getUint32() & 0x3 & declareLocs[3]),
984             };
985 
986             StructType *testTypes[] = {
987                 new StructType("Type0"),
988                 new StructType("Type1"),
989                 new StructType("Type2"),
990                 new StructType("Type3"),
991             };
992 
993             structTypes.push_back(testTypes[0]);
994             structTypes.push_back(testTypes[1]);
995             structTypes.push_back(testTypes[2]);
996             structTypes.push_back(testTypes[3]);
997 
998             testTypes[0]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
999             testTypes[0]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1000             testTypes[0]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1001             testTypes[0]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1002             testTypes[0]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1003 
1004             testTypes[1]->addMember("a", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1005             testTypes[1]->addMember("b", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1006             testTypes[1]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1007             testTypes[1]->addMember("d", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1008             testTypes[1]->addMember("e", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1009 
1010             testTypes[2]->addMember("a", VarType(testTypes[0]));
1011             testTypes[2]->addMember("b", VarType(testTypes[1]));
1012             testTypes[2]->addMember("c", createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]));
1013 
1014             testTypes[3]->addMember("a", VarType(testTypes[2]));
1015 
1016             {
1017                 vector<UniformInfo> config;
1018 
1019                 config.push_back(UniformInfo(VarType(testTypes[0]), declareLocs[0], layoutLocs[0], verifyLocs[0],
1020                                              layoutLocs[0] ? baseLoc : -1));
1021 
1022                 config.push_back(UniformInfo(VarType(testTypes[1]), declareLocs[1], layoutLocs[1], verifyLocs[1],
1023                                              layoutLocs[1] ? baseLoc + 5 : -1));
1024 
1025                 config.push_back(UniformInfo(VarType(testTypes[2]), declareLocs[2], layoutLocs[2], verifyLocs[2],
1026                                              layoutLocs[2] ? baseLoc + 16 : -1));
1027 
1028                 config.push_back(UniformInfo(VarType(testTypes[3]), declareLocs[3], layoutLocs[3], verifyLocs[3],
1029                                              layoutLocs[3] ? baseLoc + 27 : -1));
1030 
1031                 group->addChild(new UniformLocationCase(m_testCtx, m_context.getRenderContext(), name.c_str(),
1032                                                         name.c_str(), config));
1033             }
1034         }
1035     }
1036 
1037     // Min/Max location
1038     {
1039         tcu::TestCaseGroup *const group = new tcu::TestCaseGroup(m_testCtx, "min_max", "Maximum & minimum location");
1040 
1041         addChild(group);
1042 
1043         for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveNdx++)
1044         {
1045             const DataType type = primitiveTypes[primitiveNdx];
1046 
1047             for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(checkStages); stageNdx++)
1048             {
1049                 const string name = string(getDataTypeName(type)) + "_" + stageNames[stageNdx];
1050                 vector<UniformInfo> config;
1051 
1052                 config.push_back(UniformInfo(createVarType(type), checkStages[stageNdx], checkStages[stageNdx],
1053                                              checkStages[stageNdx], 0));
1054 
1055                 group->addChild(new UniformLocationCase(m_testCtx, m_context.getRenderContext(),
1056                                                         (name + "_min").c_str(), (name + "_min").c_str(), config));
1057 
1058                 group->addChild(new MaxUniformLocationCase(m_testCtx, m_context.getRenderContext(),
1059                                                            (name + "_max").c_str(), (name + "_max").c_str(), config));
1060             }
1061         }
1062     }
1063 
1064     // Link
1065     {
1066         tcu::TestCaseGroup *const group =
1067             new tcu::TestCaseGroup(m_testCtx, "link", "Location specified independently from use");
1068         de::Random rng(baseSeed + 0x82e1);
1069 
1070         addChild(group);
1071 
1072         for (int caseNdx = 0; caseNdx < 10; caseNdx++)
1073         {
1074             const string name = "case_" + de::toString(caseNdx);
1075             vector<UniformInfo> config;
1076 
1077             vector<int> locations = shuffledRange(0, maxLocations, 0x1234 + caseNdx * 100);
1078 
1079             for (int count = 0; count < 32; count++)
1080             {
1081                 typedef UniformInfo::ShaderStage Stage;
1082 
1083                 const Stage layoutLoc  = Stage(rng.getUint32() & 0x3);
1084                 const Stage declareLoc = Stage((rng.getUint32() & 0x3) | layoutLoc);
1085                 const Stage verifyLoc  = Stage((rng.getUint32() & 0x3) & declareLoc);
1086 
1087                 const UniformInfo uniform(createVarType(primitiveTypes[rng.getInt(0, maxPrimitiveTypeNdx)]), declareLoc,
1088                                           layoutLoc, verifyLoc, (layoutLoc != 0) ? locations.back() : -1);
1089 
1090                 config.push_back(uniform);
1091                 locations.pop_back();
1092             }
1093             group->addChild(
1094                 new UniformLocationCase(m_testCtx, m_context.getRenderContext(), name.c_str(), name.c_str(), config));
1095         }
1096     }
1097 
1098     // Negative
1099     {
1100         de::MovePtr<tcu::TestCaseGroup> negativeGroup(new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests"));
1101 
1102         {
1103             de::MovePtr<tcu::TestCaseGroup> es31Group(
1104                 new tcu::TestCaseGroup(m_testCtx, "es31", "GLSL ES 3.1 Negative tests"));
1105             gls::ShaderLibrary shaderLibrary(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
1106             const vector<TestNode *> negativeCases = shaderLibrary.loadShaderFile("shaders/es31/uniform_location.test");
1107 
1108             for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
1109                 es31Group->addChild(negativeCases[ndx]);
1110 
1111             negativeGroup->addChild(es31Group.release());
1112         }
1113 
1114         // ES only
1115         if (!m_isGL45)
1116         {
1117             de::MovePtr<tcu::TestCaseGroup> es32Group(
1118                 new tcu::TestCaseGroup(m_testCtx, "es32", "GLSL ES 3.2 Negative tests"));
1119             gls::ShaderLibrary shaderLibrary(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
1120             const vector<TestNode *> negativeCases = shaderLibrary.loadShaderFile("shaders/es32/uniform_location.test");
1121 
1122             for (int ndx = 0; ndx < int(negativeCases.size()); ndx++)
1123                 es32Group->addChild(negativeCases[ndx]);
1124 
1125             negativeGroup->addChild(es32Group.release());
1126         }
1127 
1128         addChild(negativeGroup.release());
1129     }
1130 }
1131 
1132 } // namespace Functional
1133 } // namespace gles31
1134 } // namespace deqp
1135