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