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