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