1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 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 Uniform API tests. 22 * 23 * \todo [2013-02-26 nuutti] Much duplication between this and ES3. 24 * Utilities to glshared? 25 *//*--------------------------------------------------------------------*/ 26 27#include "es2fUniformApiTests.hpp" 28#include "gluCallLogWrapper.hpp" 29#include "gluShaderProgram.hpp" 30#include "gluVarType.hpp" 31#include "gluPixelTransfer.hpp" 32#include "gluTextureUtil.hpp" 33#include "gluTexture.hpp" 34#include "tcuRenderTarget.hpp" 35#include "tcuTestLog.hpp" 36#include "tcuSurface.hpp" 37#include "tcuCommandLine.hpp" 38#include "deRandom.hpp" 39#include "deStringUtil.hpp" 40#include "deSharedPtr.hpp" 41#include "deString.h" 42#include "deMemory.h" 43 44#include "glwEnums.hpp" 45#include "glwFunctions.hpp" 46 47#include <set> 48#include <cstring> 49 50using namespace glw; 51 52namespace deqp 53{ 54namespace gles2 55{ 56namespace Functional 57{ 58 59using std::vector; 60using std::string; 61using tcu::TestLog; 62using tcu::ScopedLogSection; 63using glu::ShaderProgram; 64using glu::StructType; 65using de::Random; 66using de::SharedPtr; 67 68typedef bool (* dataTypePredicate)(glu::DataType); 69 70static const int MAX_RENDER_WIDTH = 32; 71static const int MAX_RENDER_HEIGHT = 32; 72static const int MAX_NUM_SAMPLER_UNIFORMS = 16; 73 74static const glu::DataType s_testDataTypes[] = 75{ 76 glu::TYPE_FLOAT, 77 glu::TYPE_FLOAT_VEC2, 78 glu::TYPE_FLOAT_VEC3, 79 glu::TYPE_FLOAT_VEC4, 80 glu::TYPE_FLOAT_MAT2, 81 glu::TYPE_FLOAT_MAT3, 82 glu::TYPE_FLOAT_MAT4, 83 84 glu::TYPE_INT, 85 glu::TYPE_INT_VEC2, 86 glu::TYPE_INT_VEC3, 87 glu::TYPE_INT_VEC4, 88 89 glu::TYPE_BOOL, 90 glu::TYPE_BOOL_VEC2, 91 glu::TYPE_BOOL_VEC3, 92 glu::TYPE_BOOL_VEC4, 93 94 glu::TYPE_SAMPLER_2D, 95 glu::TYPE_SAMPLER_CUBE 96}; 97 98static inline int getGLInt (const glw::Functions& funcs, const deUint32 name) 99{ 100 int val = -1; 101 funcs.getIntegerv(name, &val); 102 return val; 103} 104 105static inline tcu::Vec4 vec4FromPtr (const float* const ptr) 106{ 107 tcu::Vec4 result; 108 for (int i = 0; i < 4; i++) 109 result[i] = ptr[i]; 110 return result; 111} 112 113static inline string beforeLast (const string& str, const char c) 114{ 115 return str.substr(0, str.find_last_of(c)); 116} 117 118static inline void fillWithColor (const tcu::PixelBufferAccess& access, const tcu::Vec4& color) 119{ 120 for (int z = 0; z < access.getDepth(); z++) 121 for (int y = 0; y < access.getHeight(); y++) 122 for (int x = 0; x < access.getWidth(); x++) 123 access.setPixel(color, x, y, z); 124} 125 126static inline int getSamplerNumLookupDimensions (const glu::DataType type) 127{ 128 switch (type) 129 { 130 case glu::TYPE_SAMPLER_2D: 131 return 2; 132 133 case glu::TYPE_SAMPLER_CUBE: 134 return 3; 135 136 default: // \note All others than 2d and cube are gles3-only types. 137 DE_ASSERT(false); 138 return 0; 139 } 140} 141 142template<glu::DataType T> 143static bool dataTypeEquals (const glu::DataType t) 144{ 145 return t == T; 146} 147 148template<int N> 149static bool dataTypeIsMatrixWithNRows (const glu::DataType t) 150{ 151 return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N; 152} 153 154static bool typeContainsMatchingBasicType (const glu::VarType& type, const dataTypePredicate predicate) 155{ 156 if (type.isBasicType()) 157 return predicate(type.getBasicType()); 158 else if (type.isArrayType()) 159 return typeContainsMatchingBasicType(type.getElementType(), predicate); 160 else 161 { 162 DE_ASSERT(type.isStructType()); 163 const StructType& structType = *type.getStructPtr(); 164 for (int i = 0; i < structType.getNumMembers(); i++) 165 if (typeContainsMatchingBasicType(structType.getMember(i).getType(), predicate)) 166 return true; 167 return false; 168 } 169} 170 171static void getDistinctSamplerTypes (vector<glu::DataType>& dst, const glu::VarType& type) 172{ 173 if (type.isBasicType()) 174 { 175 const glu::DataType basicType = type.getBasicType(); 176 if (glu::isDataTypeSampler(basicType) && std::find(dst.begin(), dst.end(), basicType) == dst.end()) 177 dst.push_back(basicType); 178 } 179 else if (type.isArrayType()) 180 getDistinctSamplerTypes(dst, type.getElementType()); 181 else 182 { 183 DE_ASSERT(type.isStructType()); 184 const StructType& structType = *type.getStructPtr(); 185 for (int i = 0; i < structType.getNumMembers(); i++) 186 getDistinctSamplerTypes(dst, structType.getMember(i).getType()); 187 } 188} 189 190static int getNumSamplersInType (const glu::VarType& type) 191{ 192 if (type.isBasicType()) 193 return glu::isDataTypeSampler(type.getBasicType()) ? 1 : 0; 194 else if (type.isArrayType()) 195 return getNumSamplersInType(type.getElementType()) * type.getArraySize(); 196 else 197 { 198 DE_ASSERT(type.isStructType()); 199 const StructType& structType = *type.getStructPtr(); 200 int sum = 0; 201 for (int i = 0; i < structType.getNumMembers(); i++) 202 sum += getNumSamplersInType(structType.getMember(i).getType()); 203 return sum; 204 } 205} 206 207static glu::VarType generateRandomType (const int maxDepth, int& curStructIdx, vector<const StructType*>& structTypesDst, Random& rnd) 208{ 209 const bool isStruct = maxDepth > 0 && rnd.getFloat() < 0.2f; 210 const bool isArray = rnd.getFloat() < 0.3f; 211 212 if (isStruct) 213 { 214 const int numMembers = rnd.getInt(1, 5); 215 StructType* const structType = new StructType(("structType" + de::toString(curStructIdx++)).c_str()); 216 217 for (int i = 0; i < numMembers; i++) 218 structType->addMember(("m" + de::toString(i)).c_str(), generateRandomType(maxDepth-1, curStructIdx, structTypesDst, rnd)); 219 220 structTypesDst.push_back(structType); 221 return isArray ? glu::VarType(glu::VarType(structType), rnd.getInt(1, 5)) : glu::VarType(structType); 222 } 223 else 224 { 225 const glu::DataType basicType = (glu::DataType)s_testDataTypes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(s_testDataTypes)-1)]; 226 const glu::Precision precision = glu::isDataTypeBoolOrBVec(basicType) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 227 return isArray ? glu::VarType(glu::VarType(basicType, precision), rnd.getInt(1, 5)) : glu::VarType(basicType, precision); 228 } 229} 230 231namespace 232{ 233 234struct VarValue 235{ 236 glu::DataType type; 237 238 union 239 { 240 float floatV[4*4]; // At most mat4. \note Matrices here are column-major. 241 deInt32 intV[4]; 242 bool boolV[4]; 243 struct 244 { 245 int unit; 246 float fillColor[4]; 247 } samplerV; 248 } val; 249}; 250 251enum CaseShaderType 252{ 253 CASESHADERTYPE_VERTEX = 0, 254 CASESHADERTYPE_FRAGMENT, 255 CASESHADERTYPE_BOTH, 256 257 CASESHADERTYPE_LAST 258}; 259 260struct Uniform 261{ 262 string name; 263 glu::VarType type; 264 265 Uniform (const char* const name_, const glu::VarType& type_) : name(name_), type(type_) {} 266}; 267 268// A set of uniforms, along with related struct types. 269class UniformCollection 270{ 271public: 272 int getNumUniforms (void) const { return (int)m_uniforms.size(); } 273 int getNumStructTypes (void) const { return (int)m_structTypes.size(); } 274 Uniform& getUniform (const int ndx) { return m_uniforms[ndx]; } 275 const Uniform& getUniform (const int ndx) const { return m_uniforms[ndx]; } 276 const StructType* getStructType (const int ndx) const { return m_structTypes[ndx]; } 277 void addUniform (const Uniform& uniform) { m_uniforms.push_back(uniform); } 278 void addStructType (const StructType* const type) { m_structTypes.push_back(type); } 279 280 UniformCollection (void) {} 281 ~UniformCollection (void) 282 { 283 for (int i = 0; i < (int)m_structTypes.size(); i++) 284 delete m_structTypes[i]; 285 } 286 287 // Add the contents of m_uniforms and m_structTypes to receiver, and remove them from this one. 288 // \note receiver takes ownership of the struct types. 289 void moveContents (UniformCollection& receiver) 290 { 291 for (int i = 0; i < (int)m_uniforms.size(); i++) 292 receiver.addUniform(m_uniforms[i]); 293 m_uniforms.clear(); 294 295 for (int i = 0; i < (int)m_structTypes.size(); i++) 296 receiver.addStructType(m_structTypes[i]); 297 m_structTypes.clear(); 298 } 299 300 bool containsMatchingBasicType (const dataTypePredicate predicate) const 301 { 302 for (int i = 0; i < (int)m_uniforms.size(); i++) 303 if (typeContainsMatchingBasicType(m_uniforms[i].type, predicate)) 304 return true; 305 return false; 306 } 307 308 vector<glu::DataType> getSamplerTypes (void) const 309 { 310 vector<glu::DataType> samplerTypes; 311 for (int i = 0; i < (int)m_uniforms.size(); i++) 312 getDistinctSamplerTypes(samplerTypes, m_uniforms[i].type); 313 return samplerTypes; 314 } 315 316 bool containsSeveralSamplerTypes (void) const 317 { 318 return getSamplerTypes().size() > 1; 319 } 320 321 int getNumSamplers (void) const 322 { 323 int sum = 0; 324 for (int i = 0; i < (int)m_uniforms.size(); i++) 325 sum += getNumSamplersInType(m_uniforms[i].type); 326 return sum; 327 } 328 329 static UniformCollection* basic (const glu::DataType type, const char* const nameSuffix = "") 330 { 331 UniformCollection* const res = new UniformCollection; 332 const glu::Precision prec = glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 333 res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(type, prec))); 334 return res; 335 } 336 337 static UniformCollection* basicArray (const glu::DataType type, const char* const nameSuffix = "") 338 { 339 UniformCollection* const res = new UniformCollection; 340 const glu::Precision prec = glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 341 res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(glu::VarType(type, prec), 3))); 342 return res; 343 } 344 345 static UniformCollection* basicStruct (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "") 346 { 347 UniformCollection* const res = new UniformCollection; 348 const glu::Precision prec0 = glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 349 const glu::Precision prec1 = glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 350 351 StructType* const structType = new StructType((string("structType") + nameSuffix).c_str()); 352 structType->addMember("m0", glu::VarType(type0, prec0)); 353 structType->addMember("m1", glu::VarType(type1, prec1)); 354 if (containsArrays) 355 { 356 structType->addMember("m2", glu::VarType(glu::VarType(type0, prec0), 3)); 357 structType->addMember("m3", glu::VarType(glu::VarType(type1, prec1), 3)); 358 } 359 360 res->addStructType(structType); 361 res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType))); 362 363 return res; 364 } 365 366 static UniformCollection* structInArray (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "") 367 { 368 UniformCollection* const res = basicStruct(type0, type1, containsArrays, nameSuffix); 369 res->getUniform(0).type = glu::VarType(res->getUniform(0).type, 3); 370 return res; 371 } 372 373 static UniformCollection* nestedArraysStructs (const glu::DataType type0, const glu::DataType type1, const char* const nameSuffix = "") 374 { 375 UniformCollection* const res = new UniformCollection; 376 const glu::Precision prec0 = glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 377 const glu::Precision prec1 = glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 378 StructType* const structType = new StructType((string("structType") + nameSuffix).c_str()); 379 StructType* const subStructType = new StructType((string("subStructType") + nameSuffix).c_str()); 380 StructType* const subSubStructType = new StructType((string("subSubStructType") + nameSuffix).c_str()); 381 382 subSubStructType->addMember("mss0", glu::VarType(type0, prec0)); 383 subSubStructType->addMember("mss1", glu::VarType(type1, prec1)); 384 385 subStructType->addMember("ms0", glu::VarType(type1, prec1)); 386 subStructType->addMember("ms1", glu::VarType(glu::VarType(type0, prec0), 2)); 387 subStructType->addMember("ms2", glu::VarType(glu::VarType(subSubStructType), 2)); 388 389 structType->addMember("m0", glu::VarType(type0, prec0)); 390 structType->addMember("m1", glu::VarType(subStructType)); 391 structType->addMember("m2", glu::VarType(type1, prec1)); 392 393 res->addStructType(subSubStructType); 394 res->addStructType(subStructType); 395 res->addStructType(structType); 396 397 res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType))); 398 399 return res; 400 } 401 402 static UniformCollection* multipleBasic (const char* const nameSuffix = "") 403 { 404 static const glu::DataType types[] = { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_FLOAT_MAT3, glu::TYPE_BOOL_VEC2 }; 405 UniformCollection* const res = new UniformCollection; 406 407 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++) 408 { 409 UniformCollection* const sub = basic(types[i], ("_" + de::toString(i) + nameSuffix).c_str()); 410 sub->moveContents(*res); 411 delete sub; 412 } 413 414 return res; 415 } 416 417 static UniformCollection* multipleBasicArray (const char* const nameSuffix = "") 418 { 419 static const glu::DataType types[] = { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_BOOL_VEC2 }; 420 UniformCollection* const res = new UniformCollection; 421 422 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++) 423 { 424 UniformCollection* const sub = basicArray(types[i], ("_" + de::toString(i) + nameSuffix).c_str()); 425 sub->moveContents(*res); 426 delete sub; 427 } 428 429 return res; 430 } 431 432 static UniformCollection* multipleNestedArraysStructs (const char* const nameSuffix = "") 433 { 434 static const glu::DataType types0[] = { glu::TYPE_FLOAT, glu::TYPE_INT, glu::TYPE_BOOL_VEC4 }; 435 static const glu::DataType types1[] = { glu::TYPE_FLOAT_VEC4, glu::TYPE_INT_VEC4, glu::TYPE_BOOL }; 436 UniformCollection* const res = new UniformCollection; 437 438 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types0) == DE_LENGTH_OF_ARRAY(types1)); 439 440 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types0); i++) 441 { 442 UniformCollection* const sub = nestedArraysStructs(types0[i], types1[i], ("_" + de::toString(i) + nameSuffix).c_str()); 443 sub->moveContents(*res); 444 delete sub; 445 } 446 447 return res; 448 } 449 450 static UniformCollection* random (const deUint32 seed) 451 { 452 Random rnd (seed); 453 const int numUniforms = rnd.getInt(1, 5); 454 int structIdx = 0; 455 UniformCollection* const res = new UniformCollection; 456 457 for (int i = 0; i < numUniforms; i++) 458 { 459 vector<const StructType*> structTypes; 460 Uniform uniform(("u_var" + de::toString(i)).c_str(), glu::VarType()); 461 462 // \note Discard uniforms that would cause number of samplers to exceed MAX_NUM_SAMPLER_UNIFORMS. 463 do 464 { 465 for (int j = 0; j < (int)structTypes.size(); j++) 466 delete structTypes[j]; 467 structTypes.clear(); 468 uniform.type = (("u_var" + de::toString(i)).c_str(), generateRandomType(3, structIdx, structTypes, rnd)); 469 } while (res->getNumSamplers() + getNumSamplersInType(uniform.type) > MAX_NUM_SAMPLER_UNIFORMS); 470 471 res->addUniform(uniform); 472 for (int j = 0; j < (int)structTypes.size(); j++) 473 res->addStructType(structTypes[j]); 474 } 475 476 return res; 477 } 478 479private: 480 // \note Copying these would be cumbersome, since deep-copying both m_uniforms and m_structTypes 481 // would mean that we'd need to update pointers from uniforms to point to the new structTypes. 482 // When the same UniformCollection is needed in several places, a SharedPtr is used instead. 483 UniformCollection (const UniformCollection&); // Not allowed. 484 UniformCollection& operator= (const UniformCollection&); // Not allowed. 485 486 vector<Uniform> m_uniforms; 487 vector<const StructType*> m_structTypes; 488}; 489 490}; // anonymous 491 492static VarValue getSamplerFillValue (const VarValue& sampler) 493{ 494 DE_ASSERT(glu::isDataTypeSampler(sampler.type)); 495 496 VarValue result; 497 result.type = glu::TYPE_FLOAT_VEC4; 498 499 for (int i = 0; i < 4; i++) 500 result.val.floatV[i] = sampler.val.samplerV.fillColor[i]; 501 502 return result; 503} 504 505static VarValue getSamplerUnitValue (const VarValue& sampler) 506{ 507 DE_ASSERT(glu::isDataTypeSampler(sampler.type)); 508 509 VarValue result; 510 result.type = glu::TYPE_INT; 511 result.val.intV[0] = sampler.val.samplerV.unit; 512 513 return result; 514} 515 516static string shaderVarValueStr (const VarValue& value) 517{ 518 const int numElems = glu::getDataTypeScalarSize(value.type); 519 std::ostringstream result; 520 521 if (numElems > 1) 522 result << glu::getDataTypeName(value.type) << "("; 523 524 for (int i = 0; i < numElems; i++) 525 { 526 if (i > 0) 527 result << ", "; 528 529 if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type)) 530 result << de::floatToString(value.val.floatV[i], 2); 531 else if (glu::isDataTypeIntOrIVec((value.type))) 532 result << de::toString(value.val.intV[i]); 533 else if (glu::isDataTypeBoolOrBVec((value.type))) 534 result << (value.val.boolV[i] ? "true" : "false"); 535 else if (glu::isDataTypeSampler((value.type))) 536 result << shaderVarValueStr(getSamplerFillValue(value)); 537 else 538 DE_ASSERT(false); 539 } 540 541 if (numElems > 1) 542 result << ")"; 543 544 return result.str(); 545} 546 547static string apiVarValueStr (const VarValue& value) 548{ 549 const int numElems = glu::getDataTypeScalarSize(value.type); 550 std::ostringstream result; 551 552 if (numElems > 1) 553 result << "("; 554 555 for (int i = 0; i < numElems; i++) 556 { 557 if (i > 0) 558 result << ", "; 559 560 if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type)) 561 result << de::floatToString(value.val.floatV[i], 2); 562 else if (glu::isDataTypeIntOrIVec((value.type))) 563 result << de::toString(value.val.intV[i]); 564 else if (glu::isDataTypeBoolOrBVec((value.type))) 565 result << (value.val.boolV[i] ? "true" : "false"); 566 else if (glu::isDataTypeSampler((value.type))) 567 result << value.val.samplerV.unit; 568 else 569 DE_ASSERT(false); 570 } 571 572 if (numElems > 1) 573 result << ")"; 574 575 return result.str(); 576} 577 578static VarValue generateRandomVarValue (const glu::DataType type, Random& rnd, int samplerUnit = -1 /* Used if type is a sampler type. \note Samplers' unit numbers are not randomized. */) 579{ 580 const int numElems = glu::getDataTypeScalarSize(type); 581 VarValue result; 582 result.type = type; 583 584 DE_ASSERT((samplerUnit >= 0) == (glu::isDataTypeSampler(type))); 585 586 if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type)) 587 { 588 for (int i = 0; i < numElems; i++) 589 result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f); 590 } 591 else if (glu::isDataTypeIntOrIVec(type)) 592 { 593 for (int i = 0; i < numElems; i++) 594 result.val.intV[i] = rnd.getInt(-10, 10); 595 } 596 else if (glu::isDataTypeBoolOrBVec(type)) 597 { 598 for (int i = 0; i < numElems; i++) 599 result.val.boolV[i] = rnd.getBool(); 600 } 601 else if (glu::isDataTypeSampler(type)) 602 { 603 result.val.samplerV.unit = samplerUnit; 604 605 for (int i = 0; i < 4; i++) 606 result.val.samplerV.fillColor[i] = rnd.getFloat(0.0f, 1.0f); 607 } 608 else 609 DE_ASSERT(false); 610 611 return result; 612} 613 614static VarValue generateZeroVarValue (const glu::DataType type) 615{ 616 const int numElems = glu::getDataTypeScalarSize(type); 617 VarValue result; 618 result.type = type; 619 620 if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type)) 621 { 622 for (int i = 0; i < numElems; i++) 623 result.val.floatV[i] = 0.0f; 624 } 625 else if (glu::isDataTypeIntOrIVec(type)) 626 { 627 for (int i = 0; i < numElems; i++) 628 result.val.intV[i] = 0; 629 } 630 else if (glu::isDataTypeBoolOrBVec(type)) 631 { 632 for (int i = 0; i < numElems; i++) 633 result.val.boolV[i] = false; 634 } 635 else if (glu::isDataTypeSampler(type)) 636 { 637 result.val.samplerV.unit = 0; 638 639 for (int i = 0; i < 4; i++) 640 result.val.samplerV.fillColor[i] = 0.12f * (float)i; 641 } 642 else 643 DE_ASSERT(false); 644 645 return result; 646} 647 648static bool apiVarValueEquals (const VarValue& a, const VarValue& b) 649{ 650 const int size = glu::getDataTypeScalarSize(a.type); 651 const float floatThreshold = 0.05f; 652 653 DE_ASSERT(a.type == b.type); 654 655 if (glu::isDataTypeFloatOrVec(a.type) || glu::isDataTypeMatrix(a.type)) 656 { 657 for (int i = 0; i < size; i++) 658 if (de::abs(a.val.floatV[i] - b.val.floatV[i]) >= floatThreshold) 659 return false; 660 } 661 else if (glu::isDataTypeIntOrIVec(a.type)) 662 { 663 for (int i = 0; i < size; i++) 664 if (a.val.intV[i] != b.val.intV[i]) 665 return false; 666 } 667 else if (glu::isDataTypeBoolOrBVec(a.type)) 668 { 669 for (int i = 0; i < size; i++) 670 if (a.val.boolV[i] != b.val.boolV[i]) 671 return false; 672 } 673 else if (glu::isDataTypeSampler(a.type)) 674 { 675 if (a.val.samplerV.unit != b.val.samplerV.unit) 676 return false; 677 } 678 else 679 DE_ASSERT(false); 680 681 return true; 682} 683 684static VarValue getRandomBoolRepresentation (const VarValue& boolValue, const glu::DataType targetScalarType, Random& rnd) 685{ 686 DE_ASSERT(glu::isDataTypeBoolOrBVec(boolValue.type)); 687 688 const int size = glu::getDataTypeScalarSize(boolValue.type); 689 const glu::DataType targetType = size == 1 ? targetScalarType : glu::getDataTypeVector(targetScalarType, size); 690 VarValue result; 691 result.type = targetType; 692 693 switch (targetScalarType) 694 { 695 case glu::TYPE_INT: 696 for (int i = 0; i < size; i++) 697 { 698 if (boolValue.val.boolV[i]) 699 { 700 result.val.intV[i] = rnd.getInt(-10, 10); 701 if (result.val.intV[i] == 0) 702 result.val.intV[i] = 1; 703 } 704 else 705 result.val.intV[i] = 0; 706 } 707 break; 708 709 case glu::TYPE_FLOAT: 710 for (int i = 0; i < size; i++) 711 { 712 if (boolValue.val.boolV[i]) 713 { 714 result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f); 715 if (result.val.floatV[i] == 0.0f) 716 result.val.floatV[i] = 1.0f; 717 } 718 else 719 result.val.floatV[i] = 0; 720 } 721 break; 722 723 default: 724 DE_ASSERT(false); 725 } 726 727 return result; 728} 729 730static const char* getCaseShaderTypeName (const CaseShaderType type) 731{ 732 switch (type) 733 { 734 case CASESHADERTYPE_VERTEX: return "vertex"; 735 case CASESHADERTYPE_FRAGMENT: return "fragment"; 736 case CASESHADERTYPE_BOTH: return "both"; 737 default: 738 DE_ASSERT(false); 739 return DE_NULL; 740 } 741} 742 743static CaseShaderType randomCaseShaderType (const deUint32 seed) 744{ 745 return (CaseShaderType)Random(seed).getInt(0, CASESHADERTYPE_LAST-1); 746} 747 748class UniformCase : public TestCase, protected glu::CallLogWrapper 749{ 750public: 751 enum Feature 752 { 753 // ARRAYUSAGE_ONLY_MIDDLE_INDEX: only middle index of each array is used in shader. If not given, use all indices. 754 FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX = 1<<0, 755 756 // UNIFORMFUNC_VALUE: use pass-by-value versions of uniform assignment funcs, e.g. glUniform1f(), where possible. If not given, use pass-by-pointer versions. 757 FEATURE_UNIFORMFUNC_VALUE = 1<<1, 758 759 // ARRAYASSIGN: how basic-type arrays are assigned with glUniform*(). If none given, assign each element of an array separately. 760 FEATURE_ARRAYASSIGN_FULL = 1<<2, //!< Assign all elements of an array with one glUniform*(). 761 FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO = 1<<3, //!< Assign two elements per one glUniform*(). 762 763 // UNIFORMUSAGE_EVERY_OTHER: use about half of the uniforms. If not given, use all uniforms (except that some array indices may be omitted according to ARRAYUSAGE). 764 FEATURE_UNIFORMUSAGE_EVERY_OTHER = 1<<4, 765 766 // BOOLEANAPITYPE: type used to pass booleans to and from GL api. If none given, use float. 767 FEATURE_BOOLEANAPITYPE_INT = 1<<5, 768 769 // UNIFORMVALUE_ZERO: use zero-valued uniforms. If not given, use random uniform values. 770 FEATURE_UNIFORMVALUE_ZERO = 1<<6, 771 772 // ARRAY_FIRST_ELEM_NAME_NO_INDEX: in certain API functions, when referring to the first element of an array, use just the array name without [0] at the end. 773 FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX = 1<<7 774 }; 775 776 UniformCase (Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection); 777 UniformCase (Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features); 778 UniformCase (Context& context, const char* name, const char* description, deUint32 seed); // \note Randomizes caseType, uniformCollection and features. 779 virtual ~UniformCase (void); 780 781 virtual void init (void); 782 virtual void deinit (void); 783 784 IterateResult iterate (void); 785 786protected: 787 // A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d). 788 struct BasicUniform 789 { 790 string name; 791 glu::DataType type; 792 bool isUsedInShader; 793 VarValue finalValue; //!< The value we ultimately want to set for this uniform. 794 795 string rootName; //!< If this is a member of a basic-typed array, rootName is the name of that array with "[0]" appended. Otherwise it equals name. 796 int elemNdx; //!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1. 797 int rootSize; //!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1. 798 799 BasicUniform (const char* const name_, 800 const glu::DataType type_, 801 const bool isUsedInShader_, 802 const VarValue& finalValue_, 803 const char* const rootName_ = DE_NULL, 804 const int elemNdx_ = -1, 805 const int rootSize_ = 1) 806 : name (name_) 807 , type (type_) 808 , isUsedInShader (isUsedInShader_) 809 , finalValue (finalValue_) 810 , rootName (rootName_ == DE_NULL ? name_ : rootName_) 811 , elemNdx (elemNdx_) 812 , rootSize (rootSize_) 813 { 814 } 815 816 static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name) 817 { 818 for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++) 819 { 820 if (it->name == name) 821 return it; 822 } 823 return vec.end(); 824 } 825 }; 826 827 // Reference values for info that is expected to be reported by glGetActiveUniform(). 828 struct BasicUniformReportRef 829 { 830 string name; 831 // \note minSize and maxSize are for arrays and can be distinct since implementations are allowed, but not required, to trim the inactive end indices of arrays. 832 int minSize; 833 int maxSize; 834 glu::DataType type; 835 bool isUsedInShader; 836 837 BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used) 838 : name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); } 839 BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used) 840 : name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {} 841 }; 842 843 // Info that is actually reported by glGetActiveUniform(). 844 struct BasicUniformReportGL 845 { 846 string name; 847 int nameLength; 848 int size; 849 glu::DataType type; 850 851 int index; 852 853 BasicUniformReportGL (const char* const name_, const int nameLength_, const int size_, const glu::DataType type_, const int index_) 854 : name(name_), nameLength(nameLength_), size(size_), type(type_), index(index_) {} 855 856 static vector<BasicUniformReportGL>::const_iterator findWithName (const vector<BasicUniformReportGL>& vec, const char* const name) 857 { 858 for (vector<BasicUniformReportGL>::const_iterator it = vec.begin(); it != vec.end(); it++) 859 { 860 if (it->name == name) 861 return it; 862 } 863 return vec.end(); 864 } 865 }; 866 867 // Query info with glGetActiveUniform() and check validity. 868 bool getActiveUniforms (vector<BasicUniformReportGL>& dst, const vector<BasicUniformReportRef>& ref, deUint32 programGL); 869 // Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID. 870 bool getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL); 871 // Check that every uniform has the default (zero) value. 872 bool checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms); 873 // Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value). 874 void assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd); 875 // Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values. 876 bool compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms); 877 // Render and check that all pixels are white (i.e. all uniform comparisons passed). 878 bool renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd); 879 880 virtual bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0; 881 882 const deUint32 m_features; 883 const SharedPtr<const UniformCollection> m_uniformCollection; 884 885private: 886 static deUint32 randomFeatures (deUint32 seed); 887 888 // Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected 889 // to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names. 890 void generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, 891 vector<BasicUniformReportRef>& basicUniformReportsDst, 892 const glu::VarType& varType, 893 const char* varName, 894 bool isParentActive, 895 int& samplerUnitCounter, 896 Random& rnd) const; 897 898 void writeUniformDefinitions (std::ostringstream& dst) const; 899 void writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const; 900 void writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const; 901 902 string generateVertexSource (const vector<BasicUniform>& basicUniforms) const; 903 string generateFragmentSource (const vector<BasicUniform>& basicUniforms) const; 904 905 void setupTexture (const VarValue& value); 906 907 const CaseShaderType m_caseShaderType; 908 909 vector<glu::Texture2D*> m_textures2d; 910 vector<glu::TextureCube*> m_texturesCube; 911 vector<deUint32> m_filledTextureUnits; 912}; 913 914deUint32 UniformCase::randomFeatures (const deUint32 seed) 915{ 916 static const deUint32 arrayUsageChoices[] = { 0, FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX }; 917 static const deUint32 uniformFuncChoices[] = { 0, FEATURE_UNIFORMFUNC_VALUE }; 918 static const deUint32 arrayAssignChoices[] = { 0, FEATURE_ARRAYASSIGN_FULL, FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO }; 919 static const deUint32 uniformUsageChoices[] = { 0, FEATURE_UNIFORMUSAGE_EVERY_OTHER }; 920 static const deUint32 booleanApiTypeChoices[] = { 0, FEATURE_BOOLEANAPITYPE_INT }; 921 static const deUint32 uniformValueChoices[] = { 0, FEATURE_UNIFORMVALUE_ZERO }; 922 923 Random rnd(seed); 924 925 deUint32 result = 0; 926 927#define ARRAY_CHOICE(ARR) (ARR[rnd.getInt(0, DE_LENGTH_OF_ARRAY(ARR)-1)]) 928 929 result |= ARRAY_CHOICE(arrayUsageChoices); 930 result |= ARRAY_CHOICE(uniformFuncChoices); 931 result |= ARRAY_CHOICE(arrayAssignChoices); 932 result |= ARRAY_CHOICE(uniformUsageChoices); 933 result |= ARRAY_CHOICE(booleanApiTypeChoices); 934 result |= ARRAY_CHOICE(uniformValueChoices); 935 936#undef ARRAY_CHOICE 937 938 return result; 939} 940 941UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features) 942 : TestCase (context, name, description) 943 , CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog()) 944 , m_features (features) 945 , m_uniformCollection (uniformCollection) 946 , m_caseShaderType (caseShaderType) 947{ 948} 949 950UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection) 951 : TestCase (context, name, description) 952 , CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog()) 953 , m_features (0) 954 , m_uniformCollection (uniformCollection) 955 , m_caseShaderType (caseShaderType) 956{ 957} 958 959UniformCase::UniformCase (Context& context, const char* name, const char* description, const deUint32 seed) 960 : TestCase (context, name, description) 961 , CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog()) 962 , m_features (randomFeatures(seed)) 963 , m_uniformCollection (UniformCollection::random(seed)) 964 , m_caseShaderType (randomCaseShaderType(seed)) 965{ 966} 967 968void UniformCase::init (void) 969{ 970 { 971 const glw::Functions& funcs = m_context.getRenderContext().getFunctions(); 972 const int numSamplerUniforms = m_uniformCollection->getNumSamplers(); 973 const int vertexTexUnitsRequired = m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0; 974 const int fragmentTexUnitsRequired = m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0; 975 const int combinedTexUnitsRequired = vertexTexUnitsRequired + fragmentTexUnitsRequired; 976 const int vertexTexUnitsSupported = getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); 977 const int fragmentTexUnitsSupported = getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS); 978 const int combinedTexUnitsSupported = getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); 979 980 DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS); 981 982 if (vertexTexUnitsRequired > vertexTexUnitsSupported) 983 throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported"); 984 if (fragmentTexUnitsRequired > fragmentTexUnitsSupported) 985 throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported"); 986 if (combinedTexUnitsRequired > combinedTexUnitsSupported) 987 throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported"); 988 } 989 990 enableLogging(true); 991} 992 993void UniformCase::deinit (void) 994{ 995 for (int i = 0; i < (int)m_textures2d.size(); i++) 996 delete m_textures2d[i]; 997 m_textures2d.clear(); 998 999 for (int i = 0; i < (int)m_texturesCube.size(); i++) 1000 delete m_texturesCube[i]; 1001 m_texturesCube.clear(); 1002 1003 m_filledTextureUnits.clear(); 1004} 1005 1006UniformCase::~UniformCase (void) 1007{ 1008 UniformCase::deinit(); 1009} 1010 1011void UniformCase::generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, vector<BasicUniformReportRef>& basicUniformReportsDst, const glu::VarType& varType, const char* const varName, const bool isParentActive, int& samplerUnitCounter, Random& rnd) const 1012{ 1013 if (varType.isBasicType()) 1014 { 1015 const bool isActive = isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true); 1016 const glu::DataType type = varType.getBasicType(); 1017 const VarValue value = m_features & FEATURE_UNIFORMVALUE_ZERO ? generateZeroVarValue(type) 1018 : glu::isDataTypeSampler(type) ? generateRandomVarValue(type, rnd, samplerUnitCounter++) 1019 : generateRandomVarValue(varType.getBasicType(), rnd); 1020 1021 basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value)); 1022 basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive)); 1023 } 1024 else if (varType.isArrayType()) 1025 { 1026 const int size = varType.getArraySize(); 1027 const string arrayRootName = string("") + varName + "[0]"; 1028 vector<bool> isElemActive; 1029 1030 for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++) 1031 { 1032 const string indexedName = string("") + varName + "[" + de::toString(elemNdx) + "]"; 1033 const bool isCurElemActive = isParentActive && 1034 (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true) && 1035 (m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX ? elemNdx == size/2 : true); 1036 1037 isElemActive.push_back(isCurElemActive); 1038 1039 if (varType.getElementType().isBasicType()) 1040 { 1041 // \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays. 1042 const glu::DataType elemBasicType = varType.getElementType().getBasicType(); 1043 const VarValue value = m_features & FEATURE_UNIFORMVALUE_ZERO ? generateZeroVarValue(elemBasicType) 1044 : glu::isDataTypeSampler(elemBasicType) ? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++) 1045 : generateRandomVarValue(elemBasicType, rnd); 1046 1047 basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size)); 1048 } 1049 else 1050 generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd); 1051 } 1052 1053 if (varType.getElementType().isBasicType()) 1054 { 1055 int minSize; 1056 for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--); 1057 1058 basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0)); 1059 } 1060 } 1061 else 1062 { 1063 DE_ASSERT(varType.isStructType()); 1064 1065 const StructType& structType = *varType.getStructPtr(); 1066 1067 for (int i = 0; i < structType.getNumMembers(); i++) 1068 { 1069 const glu::StructMember& member = structType.getMember(i); 1070 const string memberFullName = string("") + varName + "." + member.getName(); 1071 1072 generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd); 1073 } 1074 } 1075} 1076 1077void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const 1078{ 1079 for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++) 1080 dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n"; 1081 1082 for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++) 1083 dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n"; 1084 1085 dst << "\n"; 1086 1087 { 1088 static const struct 1089 { 1090 dataTypePredicate requiringTypes[2]; 1091 const char* definition; 1092 } compareFuncs[] = 1093 { 1094 { { glu::isDataTypeFloatOrVec, glu::isDataTypeMatrix }, "mediump float compare_float (mediump float a, mediump float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }" }, 1095 { { dataTypeEquals<glu::TYPE_FLOAT_VEC2>, dataTypeIsMatrixWithNRows<2> }, "mediump float compare_vec2 (mediump vec2 a, mediump vec2 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }" }, 1096 { { dataTypeEquals<glu::TYPE_FLOAT_VEC3>, dataTypeIsMatrixWithNRows<3> }, "mediump float compare_vec3 (mediump vec3 a, mediump vec3 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }" }, 1097 { { dataTypeEquals<glu::TYPE_FLOAT_VEC4>, dataTypeIsMatrixWithNRows<4> }, "mediump float compare_vec4 (mediump vec4 a, mediump vec4 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }" }, 1098 { { dataTypeEquals<glu::TYPE_FLOAT_MAT2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat2 (mediump mat2 a, mediump mat2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }" }, 1099 { { dataTypeEquals<glu::TYPE_FLOAT_MAT3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat3 (mediump mat3 a, mediump mat3 b) { return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }" }, 1100 { { dataTypeEquals<glu::TYPE_FLOAT_MAT4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat4 (mediump mat4 a, mediump mat4 b) { return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }" }, 1101 { { dataTypeEquals<glu::TYPE_INT>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_int (mediump int a, mediump int b) { return a == b ? 1.0 : 0.0; }" }, 1102 { { dataTypeEquals<glu::TYPE_INT_VEC2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_ivec2 (mediump ivec2 a, mediump ivec2 b) { return a == b ? 1.0 : 0.0; }" }, 1103 { { dataTypeEquals<glu::TYPE_INT_VEC3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_ivec3 (mediump ivec3 a, mediump ivec3 b) { return a == b ? 1.0 : 0.0; }" }, 1104 { { dataTypeEquals<glu::TYPE_INT_VEC4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_ivec4 (mediump ivec4 a, mediump ivec4 b) { return a == b ? 1.0 : 0.0; }" }, 1105 { { dataTypeEquals<glu::TYPE_BOOL>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }" }, 1106 { { dataTypeEquals<glu::TYPE_BOOL_VEC2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }" }, 1107 { { dataTypeEquals<glu::TYPE_BOOL_VEC3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }" }, 1108 { { dataTypeEquals<glu::TYPE_BOOL_VEC4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }" } 1109 }; 1110 1111 const bool containsSamplers = !m_uniformCollection->getSamplerTypes().empty(); 1112 1113 for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++) 1114 { 1115 const dataTypePredicate (&typeReq)[2] = compareFuncs[compFuncNdx].requiringTypes; 1116 const bool containsTypeSampler = containsSamplers && (typeReq[0](glu::TYPE_FLOAT_VEC4) || typeReq[1](glu::TYPE_FLOAT_VEC4)); 1117 1118 if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1])) 1119 dst << compareFuncs[compFuncNdx].definition << "\n"; 1120 } 1121 } 1122} 1123 1124void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const 1125{ 1126 if (glu::isDataTypeSampler(uniform.type)) 1127 { 1128 dst << "compare_vec4(" 1129 << (uniform.type == glu::TYPE_SAMPLER_2D ? "texture2D" : "textureCube") 1130 << "(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))"; 1131 } 1132 else 1133 dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name; 1134 1135 dst << ", " << shaderVarValueStr(uniform.finalValue) << ")"; 1136} 1137 1138void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const 1139{ 1140 for (int i = 0; i < (int)basicUniforms.size(); i++) 1141 { 1142 const BasicUniform& unif = basicUniforms[i]; 1143 1144 if (unif.isUsedInShader) 1145 { 1146 dst << "\t" << variableName << " *= "; 1147 writeUniformCompareExpr(dst, basicUniforms[i]); 1148 dst << ";\n"; 1149 } 1150 else 1151 dst << "\t// UNUSED: " << basicUniforms[i].name << "\n"; 1152 } 1153} 1154 1155string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const 1156{ 1157 const bool isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH; 1158 std::ostringstream result; 1159 1160 result << "attribute highp vec4 a_position;\n" 1161 "varying mediump float v_vtxOut;\n" 1162 "\n"; 1163 1164 if (isVertexCase) 1165 writeUniformDefinitions(result); 1166 1167 result << "\n" 1168 "void main (void)\n" 1169 "{\n" 1170 " gl_Position = a_position;\n" 1171 " v_vtxOut = 1.0;\n"; 1172 1173 if (isVertexCase) 1174 writeUniformComparisons(result, basicUniforms, "v_vtxOut"); 1175 1176 result << "}\n"; 1177 1178 return result.str(); 1179} 1180 1181string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const 1182{ 1183 const bool isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH; 1184 std::ostringstream result; 1185 1186 result << "varying mediump float v_vtxOut;\n" 1187 "\n"; 1188 1189 if (isFragmentCase) 1190 writeUniformDefinitions(result); 1191 1192 result << "\n" 1193 "void main (void)\n" 1194 "{\n" 1195 " mediump float result = v_vtxOut;\n"; 1196 1197 if (isFragmentCase) 1198 writeUniformComparisons(result, basicUniforms, "result"); 1199 1200 result << " gl_FragColor = vec4(result, result, result, 1.0);\n" 1201 "}\n"; 1202 1203 return result.str(); 1204} 1205 1206void UniformCase::setupTexture (const VarValue& value) 1207{ 1208 enableLogging(false); 1209 1210 const int width = 32; 1211 const int height = 32; 1212 const tcu::Vec4 color = vec4FromPtr(&value.val.samplerV.fillColor[0]); 1213 1214 if (value.type == glu::TYPE_SAMPLER_2D) 1215 { 1216 glu::Texture2D* texture = new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height); 1217 tcu::Texture2D& refTexture = texture->getRefTexture(); 1218 m_textures2d.push_back(texture); 1219 1220 refTexture.allocLevel(0); 1221 fillWithColor(refTexture.getLevel(0), color); 1222 1223 GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit)); 1224 m_filledTextureUnits.push_back(value.val.samplerV.unit); 1225 texture->upload(); 1226 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 1227 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 1228 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 1229 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 1230 } 1231 else if (value.type == glu::TYPE_SAMPLER_CUBE) 1232 { 1233 DE_ASSERT(width == height); 1234 1235 glu::TextureCube* texture = new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width); 1236 tcu::TextureCube& refTexture = texture->getRefTexture(); 1237 m_texturesCube.push_back(texture); 1238 1239 for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++) 1240 { 1241 refTexture.allocLevel((tcu::CubeFace)face, 0); 1242 fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color); 1243 } 1244 1245 GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit)); 1246 m_filledTextureUnits.push_back(value.val.samplerV.unit); 1247 texture->upload(); 1248 1249 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 1250 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 1251 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 1252 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 1253 1254 } 1255 else 1256 DE_ASSERT(false); 1257 1258 enableLogging(true); 1259} 1260 1261bool UniformCase::getActiveUniforms (vector<BasicUniformReportGL>& basicUniformReportsDst, const vector<BasicUniformReportRef>& basicUniformReportsRef, const deUint32 programGL) 1262{ 1263 TestLog& log = m_testCtx.getLog(); 1264 GLint numActiveUniforms = 0; 1265 GLint uniformMaxNameLength = 0; 1266 vector<char> nameBuffer; 1267 bool success = true; 1268 1269 GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORMS, &numActiveUniforms)); 1270 log << TestLog::Message << "// Number of active uniforms reported: " << numActiveUniforms << TestLog::EndMessage; 1271 GLU_CHECK_CALL(glGetProgramiv(programGL, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxNameLength)); 1272 log << TestLog::Message << "// Maximum uniform name length reported: " << uniformMaxNameLength << TestLog::EndMessage; 1273 nameBuffer.resize(uniformMaxNameLength); 1274 1275 for (int unifNdx = 0; unifNdx < numActiveUniforms; unifNdx++) 1276 { 1277 GLsizei reportedNameLength = 0; 1278 GLint reportedSize = -1; 1279 GLenum reportedTypeGL = GL_NONE; 1280 1281 GLU_CHECK_CALL(glGetActiveUniform(programGL, (GLuint)unifNdx, (GLsizei)uniformMaxNameLength, &reportedNameLength, &reportedSize, &reportedTypeGL, &nameBuffer[0])); 1282 1283 const glu::DataType reportedType = glu::getDataTypeFromGLType(reportedTypeGL); 1284 const string reportedNameStr (&nameBuffer[0]); 1285 1286 TCU_CHECK_MSG(reportedType != glu::TYPE_LAST, "Invalid uniform type"); 1287 1288 log << TestLog::Message << "// Got name = " << reportedNameStr << ", name length = " << reportedNameLength << ", size = " << reportedSize << ", type = " << glu::getDataTypeName(reportedType) << TestLog::EndMessage; 1289 1290 if ((GLsizei)reportedNameStr.length() != reportedNameLength) 1291 { 1292 log << TestLog::Message << "// FAILURE: wrong name length reported, should be " << reportedNameStr.length() << TestLog::EndMessage; 1293 success = false; 1294 } 1295 1296 if (!deStringBeginsWith(reportedNameStr.c_str(), "gl_")) // Ignore built-in uniforms. 1297 { 1298 int referenceNdx; 1299 for (referenceNdx = 0; referenceNdx < (int)basicUniformReportsRef.size(); referenceNdx++) 1300 { 1301 if (basicUniformReportsRef[referenceNdx].name == reportedNameStr) 1302 break; 1303 } 1304 1305 if (referenceNdx >= (int)basicUniformReportsRef.size()) 1306 { 1307 log << TestLog::Message << "// FAILURE: invalid non-built-in uniform name reported" << TestLog::EndMessage; 1308 success = false; 1309 } 1310 else 1311 { 1312 const BasicUniformReportRef& reference = basicUniformReportsRef[referenceNdx]; 1313 1314 DE_ASSERT(reference.type != glu::TYPE_LAST); 1315 DE_ASSERT(reference.minSize >= 1 || (reference.minSize == 0 && !reference.isUsedInShader)); 1316 DE_ASSERT(reference.minSize <= reference.maxSize); 1317 1318 if (BasicUniformReportGL::findWithName(basicUniformReportsDst, reportedNameStr.c_str()) != basicUniformReportsDst.end()) 1319 { 1320 log << TestLog::Message << "// FAILURE: same uniform name reported twice" << TestLog::EndMessage; 1321 success = false; 1322 } 1323 1324 basicUniformReportsDst.push_back(BasicUniformReportGL(reportedNameStr.c_str(), reportedNameLength, reportedSize, reportedType, unifNdx)); 1325 1326 if (reportedType != reference.type) 1327 { 1328 log << TestLog::Message << "// FAILURE: wrong type reported, should be " << glu::getDataTypeName(reference.type) << TestLog::EndMessage; 1329 success = false; 1330 } 1331 if (reportedSize < reference.minSize || reportedSize > reference.maxSize) 1332 { 1333 log << TestLog::Message 1334 << "// FAILURE: wrong size reported, should be " 1335 << (reference.minSize == reference.maxSize ? de::toString(reference.minSize) : "in the range [" + de::toString(reference.minSize) + ", " + de::toString(reference.maxSize) + "]") 1336 << TestLog::EndMessage; 1337 1338 success = false; 1339 } 1340 } 1341 } 1342 } 1343 1344 for (int i = 0; i < (int)basicUniformReportsRef.size(); i++) 1345 { 1346 const BasicUniformReportRef& expected = basicUniformReportsRef[i]; 1347 if (expected.isUsedInShader && BasicUniformReportGL::findWithName(basicUniformReportsDst, expected.name.c_str()) == basicUniformReportsDst.end()) 1348 { 1349 log << TestLog::Message << "// FAILURE: uniform with name " << expected.name << " was not reported by GL" << TestLog::EndMessage; 1350 success = false; 1351 } 1352 } 1353 1354 return success; 1355} 1356 1357bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL) 1358{ 1359 TestLog& log = m_testCtx.getLog(); 1360 bool success = true; 1361 1362 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1363 { 1364 const BasicUniform& uniform = basicUniforms[unifNdx]; 1365 const string queryName = m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name; 1366 const int location = glGetUniformLocation(programGL, queryName.c_str()); 1367 const int size = glu::getDataTypeScalarSize(uniform.type); 1368 VarValue value; 1369 1370 deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage. 1371 1372 if (location == -1) 1373 { 1374 value.type = glu::TYPE_INVALID; 1375 valuesDst.push_back(value); 1376 if (uniform.isUsedInShader) 1377 { 1378 log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage; 1379 success = false; 1380 } 1381 continue; 1382 } 1383 1384 value.type = uniform.type; 1385 1386 DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0])); 1387 DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0])); 1388 1389 if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type)) 1390 GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0])); 1391 else if (glu::isDataTypeIntOrIVec(uniform.type)) 1392 GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0])); 1393 else if (glu::isDataTypeBoolOrBVec(uniform.type)) 1394 { 1395 if (m_features & FEATURE_BOOLEANAPITYPE_INT) 1396 { 1397 GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0])); 1398 for (int i = 0; i < size; i++) 1399 value.val.boolV[i] = value.val.intV[i] != 0; 1400 } 1401 else // Default: use float. 1402 { 1403 GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0])); 1404 for (int i = 0; i < size; i++) 1405 value.val.boolV[i] = value.val.floatV[i] != 0.0f; 1406 } 1407 } 1408 else if (glu::isDataTypeSampler(uniform.type)) 1409 { 1410 GLint unit = -1; 1411 GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit)); 1412 value.val.samplerV.unit = unit; 1413 } 1414 else 1415 DE_ASSERT(false); 1416 1417 valuesDst.push_back(value); 1418 1419 log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage; 1420 } 1421 1422 return success; 1423} 1424 1425bool UniformCase::checkUniformDefaultValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms) 1426{ 1427 TestLog& log = m_testCtx.getLog(); 1428 bool success = true; 1429 1430 DE_ASSERT(values.size() == basicUniforms.size()); 1431 1432 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1433 { 1434 const BasicUniform& uniform = basicUniforms[unifNdx]; 1435 const VarValue& unifValue = values[unifNdx]; 1436 const int valSize = glu::getDataTypeScalarSize(uniform.type); 1437 1438 log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage; 1439 1440 if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1. 1441 continue; 1442 1443#define CHECK_UNIFORM(VAR_VALUE_MEMBER, ZERO) \ 1444 do \ 1445 { \ 1446 for (int i = 0; i < valSize; i++) \ 1447 { \ 1448 if (unifValue.val.VAR_VALUE_MEMBER[i] != ZERO) \ 1449 { \ 1450 log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage; \ 1451 success = false; \ 1452 } \ 1453 } \ 1454 } while (false) 1455 1456 if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type)) 1457 CHECK_UNIFORM(floatV, 0.0f); 1458 else if (glu::isDataTypeIntOrIVec(uniform.type)) 1459 CHECK_UNIFORM(intV, 0); 1460 else if (glu::isDataTypeBoolOrBVec(uniform.type)) 1461 CHECK_UNIFORM(boolV, false); 1462 else if (glu::isDataTypeSampler(uniform.type)) 1463 { 1464 if (unifValue.val.samplerV.unit != 0) 1465 { 1466 log << TestLog::Message << "// FAILURE: uniform " << uniform.name << " has non-zero initial value" << TestLog::EndMessage; 1467 success = false; 1468 } 1469 } 1470 else 1471 DE_ASSERT(false); 1472 1473#undef CHECK_UNIFORM 1474 } 1475 1476 return success; 1477} 1478 1479void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd) 1480{ 1481 TestLog& log = m_testCtx.getLog(); 1482 const glu::DataType boolApiType = m_features & FEATURE_BOOLEANAPITYPE_INT ? glu::TYPE_INT 1483 : glu::TYPE_FLOAT; 1484 1485 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1486 { 1487 const BasicUniform& uniform = basicUniforms[unifNdx]; 1488 const bool isArrayMember = uniform.elemNdx >= 0; 1489 const string queryName = m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name; 1490 const int numValuesToAssign = !isArrayMember ? 1 1491 : m_features & FEATURE_ARRAYASSIGN_FULL ? (uniform.elemNdx == 0 ? uniform.rootSize : 0) 1492 : m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO ? (uniform.elemNdx % 2 == 0 ? 2 : 0) 1493 : /* Default: assign array elements separately */ 1; 1494 1495 DE_ASSERT(numValuesToAssign >= 0); 1496 DE_ASSERT(numValuesToAssign == 1 || isArrayMember); 1497 1498 if (numValuesToAssign == 0) 1499 { 1500 log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glUniform*v() call to the same array" << TestLog::EndMessage; 1501 continue; 1502 } 1503 1504 const int location = glGetUniformLocation(programGL, queryName.c_str()); 1505 const int typeSize = glu::getDataTypeScalarSize(uniform.type); 1506 const bool assignByValue = m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1; 1507 vector<VarValue> valuesToAssign; 1508 1509 for (int i = 0; i < numValuesToAssign; i++) 1510 { 1511 const string curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name; 1512 VarValue unifValue; 1513 1514 if (isArrayMember) 1515 { 1516 const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str()); 1517 if (elemUnif == basicUniforms.end()) 1518 continue; 1519 unifValue = elemUnif->finalValue; 1520 } 1521 else 1522 unifValue = uniform.finalValue; 1523 1524 const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type) ? getRandomBoolRepresentation(unifValue, boolApiType, rnd) 1525 : glu::isDataTypeSampler(unifValue.type) ? getSamplerUnitValue(unifValue) 1526 : unifValue; 1527 1528 valuesToAssign.push_back(apiValue); 1529 1530 if (glu::isDataTypeBoolOrBVec(uniform.type)) 1531 log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage; 1532 else if (glu::isDataTypeSampler(uniform.type)) 1533 log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage; 1534 } 1535 1536 DE_ASSERT(!valuesToAssign.empty()); 1537 1538 if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type)) 1539 { 1540 if (assignByValue) 1541 { 1542 const float* const ptr = &valuesToAssign[0].val.floatV[0]; 1543 1544 switch (typeSize) 1545 { 1546 case 1: GLU_CHECK_CALL(glUniform1f(location, ptr[0])); break; 1547 case 2: GLU_CHECK_CALL(glUniform2f(location, ptr[0], ptr[1])); break; 1548 case 3: GLU_CHECK_CALL(glUniform3f(location, ptr[0], ptr[1], ptr[2])); break; 1549 case 4: GLU_CHECK_CALL(glUniform4f(location, ptr[0], ptr[1], ptr[2], ptr[3])); break; 1550 default: 1551 DE_ASSERT(false); 1552 } 1553 } 1554 else 1555 { 1556 vector<float> buffer(valuesToAssign.size() * typeSize); 1557 for (int i = 0; i < (int)buffer.size(); i++) 1558 buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize]; 1559 1560 DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0])); 1561 switch (typeSize) 1562 { 1563 case 1: GLU_CHECK_CALL(glUniform1fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1564 case 2: GLU_CHECK_CALL(glUniform2fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1565 case 3: GLU_CHECK_CALL(glUniform3fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1566 case 4: GLU_CHECK_CALL(glUniform4fv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1567 default: 1568 DE_ASSERT(false); 1569 } 1570 } 1571 } 1572 else if (glu::isDataTypeMatrix(valuesToAssign[0].type)) 1573 { 1574 DE_ASSERT(!assignByValue); 1575 1576 vector<float> buffer(valuesToAssign.size() * typeSize); 1577 for (int i = 0; i < (int)buffer.size(); i++) 1578 buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize]; 1579 1580 switch (uniform.type) 1581 { 1582 case glu::TYPE_FLOAT_MAT2: GLU_CHECK_CALL(glUniformMatrix2fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break; 1583 case glu::TYPE_FLOAT_MAT3: GLU_CHECK_CALL(glUniformMatrix3fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break; 1584 case glu::TYPE_FLOAT_MAT4: GLU_CHECK_CALL(glUniformMatrix4fv(location, (GLsizei)valuesToAssign.size(), GL_FALSE, &buffer[0])); break; 1585 default: 1586 DE_ASSERT(false); 1587 } 1588 } 1589 else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type)) 1590 { 1591 if (assignByValue) 1592 { 1593 const deInt32* const ptr = &valuesToAssign[0].val.intV[0]; 1594 1595 switch (typeSize) 1596 { 1597 case 1: GLU_CHECK_CALL(glUniform1i(location, ptr[0])); break; 1598 case 2: GLU_CHECK_CALL(glUniform2i(location, ptr[0], ptr[1])); break; 1599 case 3: GLU_CHECK_CALL(glUniform3i(location, ptr[0], ptr[1], ptr[2])); break; 1600 case 4: GLU_CHECK_CALL(glUniform4i(location, ptr[0], ptr[1], ptr[2], ptr[3])); break; 1601 default: 1602 DE_ASSERT(false); 1603 } 1604 } 1605 else 1606 { 1607 vector<deInt32> buffer(valuesToAssign.size() * typeSize); 1608 for (int i = 0; i < (int)buffer.size(); i++) 1609 buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize]; 1610 1611 DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0])); 1612 switch (typeSize) 1613 { 1614 case 1: GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1615 case 2: GLU_CHECK_CALL(glUniform2iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1616 case 3: GLU_CHECK_CALL(glUniform3iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1617 case 4: GLU_CHECK_CALL(glUniform4iv(location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1618 default: 1619 DE_ASSERT(false); 1620 } 1621 } 1622 } 1623 else if (glu::isDataTypeSampler(valuesToAssign[0].type)) 1624 { 1625 if (assignByValue) 1626 GLU_CHECK_CALL(glUniform1i(location, uniform.finalValue.val.samplerV.unit)); 1627 else 1628 { 1629 const GLint unit = uniform.finalValue.val.samplerV.unit; 1630 GLU_CHECK_CALL(glUniform1iv(location, (GLsizei)valuesToAssign.size(), &unit)); 1631 } 1632 } 1633 else 1634 DE_ASSERT(false); 1635 } 1636} 1637 1638bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms) 1639{ 1640 TestLog& log = m_testCtx.getLog(); 1641 bool success = true; 1642 1643 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1644 { 1645 const BasicUniform& uniform = basicUniforms[unifNdx]; 1646 const VarValue& unifValue = values[unifNdx]; 1647 1648 log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage; 1649 1650 if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1. 1651 continue; 1652 1653 if (!apiVarValueEquals(unifValue, uniform.finalValue)) 1654 { 1655 log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glUniform*()" << TestLog::EndMessage; 1656 success = false; 1657 } 1658 } 1659 1660 return success; 1661} 1662 1663bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd) 1664{ 1665 TestLog& log = m_testCtx.getLog(); 1666 const tcu::RenderTarget& renderTarget = m_context.getRenderTarget(); 1667 const int viewportW = de::min(renderTarget.getWidth(), MAX_RENDER_WIDTH); 1668 const int viewportH = de::min(renderTarget.getHeight(), MAX_RENDER_HEIGHT); 1669 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportW); 1670 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportH); 1671 tcu::Surface renderedImg (viewportW, viewportH); 1672 1673 // Assert that no two samplers of different types have the same texture unit - this is an error in GL. 1674 for (int i = 0; i < (int)basicUniforms.size(); i++) 1675 { 1676 if (glu::isDataTypeSampler(basicUniforms[i].type)) 1677 { 1678 for (int j = 0; j < i; j++) 1679 { 1680 if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type) 1681 DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit); 1682 } 1683 } 1684 } 1685 1686 for (int i = 0; i < (int)basicUniforms.size(); i++) 1687 { 1688 if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end()) 1689 { 1690 log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage; 1691 setupTexture(basicUniforms[i].finalValue); 1692 } 1693 } 1694 1695 GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH)); 1696 1697 { 1698 static const float position[] = 1699 { 1700 -1.0f, -1.0f, 0.0f, 1.0f, 1701 -1.0f, +1.0f, 0.0f, 1.0f, 1702 +1.0f, -1.0f, 0.0f, 1.0f, 1703 +1.0f, +1.0f, 0.0f, 1.0f 1704 }; 1705 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; 1706 1707 const int posLoc = glGetAttribLocation(program.getProgram(), "a_position"); 1708 1709 glEnableVertexAttribArray(posLoc); 1710 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); 1711 1712 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0])); 1713 } 1714 1715 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess()); 1716 1717 int numFailedPixels = 0; 1718 for (int y = 0; y < renderedImg.getHeight(); y++) 1719 { 1720 for (int x = 0; x < renderedImg.getWidth(); x++) 1721 { 1722 if (renderedImg.getPixel(x, y) != tcu::RGBA::white) 1723 numFailedPixels += 1; 1724 } 1725 } 1726 1727 if (numFailedPixels > 0) 1728 { 1729 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg); 1730 log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-white pixels" << TestLog::EndMessage; 1731 return false; 1732 } 1733 else 1734 { 1735 log << TestLog::Message << "Success: got all-white pixels (all uniforms have correct values)" << TestLog::EndMessage; 1736 return true; 1737 } 1738} 1739 1740UniformCase::IterateResult UniformCase::iterate (void) 1741{ 1742 Random rnd (deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed()); 1743 TestLog& log = m_testCtx.getLog(); 1744 vector<BasicUniform> basicUniforms; 1745 vector<BasicUniformReportRef> basicUniformReportsRef; 1746 1747 { 1748 int samplerUnitCounter = 0; 1749 for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++) 1750 generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd); 1751 } 1752 1753 const string vertexSource = generateVertexSource(basicUniforms); 1754 const string fragmentSource = generateFragmentSource(basicUniforms); 1755 const ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource)); 1756 1757 log << program; 1758 1759 if (!program.isOk()) 1760 { 1761 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 1762 return STOP; 1763 } 1764 1765 GLU_CHECK_CALL(glUseProgram(program.getProgram())); 1766 1767 const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd); 1768 m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1769 success ? "Passed" : "Failed"); 1770 1771 return STOP; 1772} 1773 1774class UniformInfoQueryCase : public UniformCase 1775{ 1776public: 1777 UniformInfoQueryCase (Context& context, const char* name, const char* description, CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 additionalFeatures = 0); 1778 bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd); 1779}; 1780 1781UniformInfoQueryCase::UniformInfoQueryCase (Context& context, const char* const name, const char* const description, const CaseShaderType shaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 additionalFeatures) 1782 : UniformCase (context, name, description, shaderType, uniformCollection, additionalFeatures) 1783{ 1784} 1785 1786bool UniformInfoQueryCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) 1787{ 1788 DE_UNREF(basicUniforms); 1789 DE_UNREF(rnd); 1790 1791 const deUint32 programGL = program.getProgram(); 1792 TestLog& log = m_testCtx.getLog(); 1793 vector<BasicUniformReportGL> basicUniformReportsUniform; 1794 1795 const ScopedLogSection section(log, "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()"); 1796 const bool success = getActiveUniforms(basicUniformReportsUniform, basicUniformReportsRef, programGL); 1797 1798 if (!success) 1799 return false; 1800 1801 return true; 1802} 1803 1804class UniformValueCase : public UniformCase 1805{ 1806public: 1807 enum ValueToCheck 1808 { 1809 VALUETOCHECK_INITIAL = 0, //!< Verify the initial values of the uniforms (i.e. check that they're zero). 1810 VALUETOCHECK_ASSIGNED, //!< Assign values to uniforms with glUniform*(), and check those. 1811 1812 VALUETOCHECK_LAST 1813 }; 1814 enum CheckMethod 1815 { 1816 CHECKMETHOD_GET_UNIFORM = 0, //!< Check values with glGetUniform*(). 1817 CHECKMETHOD_RENDER, //!< Check values by rendering with the value-checking shader. 1818 1819 CHECKMETHOD_LAST 1820 }; 1821 enum AssignMethod 1822 { 1823 ASSIGNMETHOD_POINTER = 0, 1824 ASSIGNMETHOD_VALUE, 1825 1826 ASSIGNMETHOD_LAST 1827 }; 1828 1829 UniformValueCase (Context& context, 1830 const char* name, 1831 const char* description, 1832 CaseShaderType shaderType, 1833 const SharedPtr<const UniformCollection>& uniformCollection, 1834 ValueToCheck valueToCheck, 1835 CheckMethod checkMethod, 1836 AssignMethod assignMethod, 1837 deUint32 additionalFeatures = 0); 1838 1839 bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd); 1840 1841 static const char* getValueToCheckName (ValueToCheck valueToCheck); 1842 static const char* getValueToCheckDescription (ValueToCheck valueToCheck); 1843 static const char* getCheckMethodName (CheckMethod checkMethod); 1844 static const char* getCheckMethodDescription (CheckMethod checkMethod); 1845 static const char* getAssignMethodName (AssignMethod checkMethod); 1846 static const char* getAssignMethodDescription (AssignMethod checkMethod); 1847 1848private: 1849 const ValueToCheck m_valueToCheck; 1850 const CheckMethod m_checkMethod; 1851}; 1852 1853const char* UniformValueCase::getValueToCheckName (const ValueToCheck valueToCheck) 1854{ 1855 switch (valueToCheck) 1856 { 1857 case VALUETOCHECK_INITIAL: return "initial"; 1858 case VALUETOCHECK_ASSIGNED: return "assigned"; 1859 default: DE_ASSERT(false); return DE_NULL; 1860 } 1861} 1862 1863const char* UniformValueCase::getValueToCheckDescription (const ValueToCheck valueToCheck) 1864{ 1865 switch (valueToCheck) 1866{ 1867 case VALUETOCHECK_INITIAL: return "Check initial uniform values (zeros)"; 1868 case VALUETOCHECK_ASSIGNED: return "Check assigned uniform values"; 1869 default: DE_ASSERT(false); return DE_NULL; 1870 } 1871} 1872 1873const char* UniformValueCase::getCheckMethodName (const CheckMethod checkMethod) 1874{ 1875 switch (checkMethod) 1876 { 1877 case CHECKMETHOD_GET_UNIFORM: return "get_uniform"; 1878 case CHECKMETHOD_RENDER: return "render"; 1879 default: DE_ASSERT(false); return DE_NULL; 1880 } 1881} 1882 1883const char* UniformValueCase::getCheckMethodDescription (const CheckMethod checkMethod) 1884{ 1885 switch (checkMethod) 1886 { 1887 case CHECKMETHOD_GET_UNIFORM: return "Verify values with glGetUniform*()"; 1888 case CHECKMETHOD_RENDER: return "Verify values by rendering"; 1889 default: DE_ASSERT(false); return DE_NULL; 1890 } 1891} 1892 1893const char* UniformValueCase::getAssignMethodName (const AssignMethod assignMethod) 1894{ 1895 switch (assignMethod) 1896 { 1897 case ASSIGNMETHOD_POINTER: return "by_pointer"; 1898 case ASSIGNMETHOD_VALUE: return "by_value"; 1899 default: DE_ASSERT(false); return DE_NULL; 1900 } 1901} 1902 1903const char* UniformValueCase::getAssignMethodDescription (const AssignMethod assignMethod) 1904{ 1905 switch (assignMethod) 1906 { 1907 case ASSIGNMETHOD_POINTER: return "Assign values by-pointer"; 1908 case ASSIGNMETHOD_VALUE: return "Assign values by-value"; 1909 default: DE_ASSERT(false); return DE_NULL; 1910 } 1911} 1912 1913UniformValueCase::UniformValueCase (Context& context, 1914 const char* const name, 1915 const char* const description, 1916 const CaseShaderType shaderType, 1917 const SharedPtr<const UniformCollection>& uniformCollection, 1918 const ValueToCheck valueToCheck, 1919 const CheckMethod checkMethod, 1920 const AssignMethod assignMethod, 1921 const deUint32 additionalFeatures) 1922 : UniformCase (context, name, description, shaderType, uniformCollection, 1923 (valueToCheck == VALUETOCHECK_INITIAL ? FEATURE_UNIFORMVALUE_ZERO : 0) | (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures) 1924 , m_valueToCheck (valueToCheck) 1925 , m_checkMethod (checkMethod) 1926{ 1927 DE_ASSERT(!(assignMethod == ASSIGNMETHOD_LAST && valueToCheck == VALUETOCHECK_ASSIGNED)); 1928} 1929 1930bool UniformValueCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) 1931{ 1932 DE_UNREF(basicUniformReportsRef); 1933 1934 const deUint32 programGL = program.getProgram(); 1935 TestLog& log = m_testCtx.getLog(); 1936 1937 if (m_valueToCheck == VALUETOCHECK_ASSIGNED) 1938 { 1939 const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments"); 1940 assignUniforms(basicUniforms, programGL, rnd); 1941 } 1942 else 1943 DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL); 1944 1945 if (m_checkMethod == CHECKMETHOD_GET_UNIFORM) 1946 { 1947 vector<VarValue> values; 1948 1949 { 1950 const ScopedLogSection section(log, "GetUniforms", "Uniform value query"); 1951 const bool success = getUniforms(values, basicUniforms, program.getProgram()); 1952 1953 if (!success) 1954 return false; 1955 } 1956 1957 if (m_valueToCheck == VALUETOCHECK_ASSIGNED) 1958 { 1959 const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values"); 1960 const bool success = compareUniformValues(values, basicUniforms); 1961 1962 if (!success) 1963 return false; 1964 } 1965 else 1966 { 1967 DE_ASSERT(m_valueToCheck == VALUETOCHECK_INITIAL); 1968 const ScopedLogSection section(log, "ValueCheck", "Verify that the uniforms have correct initial values (zeros)"); 1969 const bool success = checkUniformDefaultValues(values, basicUniforms); 1970 1971 if (!success) 1972 return false; 1973 } 1974 } 1975 else 1976 { 1977 DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER); 1978 1979 const ScopedLogSection section(log, "RenderTest", "Render test"); 1980 const bool success = renderTest(basicUniforms, program, rnd); 1981 1982 if (!success) 1983 return false; 1984 } 1985 1986 return true; 1987} 1988 1989class RandomUniformCase : public UniformCase 1990{ 1991public: 1992 RandomUniformCase (Context& m_context, const char* name, const char* description, deUint32 seed); 1993 1994 bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd); 1995}; 1996 1997RandomUniformCase::RandomUniformCase (Context& context, const char* const name, const char* const description, const deUint32 seed) 1998 : UniformCase (context, name, description, seed ^ (deUint32)context.getTestContext().getCommandLine().getBaseSeed()) 1999{ 2000} 2001 2002bool RandomUniformCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) 2003{ 2004 // \note Different sampler types may not be bound to same unit when rendering. 2005 const bool renderingPossible = (m_features & FEATURE_UNIFORMVALUE_ZERO) == 0 || !m_uniformCollection->containsSeveralSamplerTypes(); 2006 2007 bool performGetActiveUniforms = rnd.getBool(); 2008 const bool performGetUniforms = rnd.getBool(); 2009 const bool performCheckUniformDefaultValues = performGetUniforms && rnd.getBool(); 2010 const bool performAssignUniforms = rnd.getBool(); 2011 const bool performCompareUniformValues = performGetUniforms && performAssignUniforms && rnd.getBool(); 2012 const bool performRenderTest = renderingPossible && performAssignUniforms && rnd.getBool(); 2013 const deUint32 programGL = program.getProgram(); 2014 TestLog& log = m_testCtx.getLog(); 2015 2016 if (!(performGetActiveUniforms || performGetUniforms || performCheckUniformDefaultValues || performAssignUniforms || performCompareUniformValues || performRenderTest)) 2017 performGetActiveUniforms = true; // Do something at least. 2018 2019#define PERFORM_AND_CHECK(CALL, SECTION_NAME, SECTION_DESCRIPTION) \ 2020 do \ 2021 { \ 2022 const ScopedLogSection section(log, (SECTION_NAME), (SECTION_DESCRIPTION)); \ 2023 const bool success = (CALL); \ 2024 if (!success) \ 2025 return false; \ 2026 } while (false) 2027 2028 if (performGetActiveUniforms) 2029 { 2030 vector<BasicUniformReportGL> reportsUniform; 2031 PERFORM_AND_CHECK(getActiveUniforms(reportsUniform, basicUniformReportsRef, programGL), "InfoGetActiveUniform", "Uniform information queries with glGetActiveUniform()"); 2032 } 2033 2034 { 2035 vector<VarValue> uniformDefaultValues; 2036 2037 if (performGetUniforms) 2038 PERFORM_AND_CHECK(getUniforms(uniformDefaultValues, basicUniforms, programGL), "GetUniformDefaults", "Uniform default value query"); 2039 if (performCheckUniformDefaultValues) 2040 PERFORM_AND_CHECK(checkUniformDefaultValues(uniformDefaultValues, basicUniforms), "DefaultValueCheck", "Verify that the uniforms have correct initial values (zeros)"); 2041 } 2042 2043 { 2044 vector<VarValue> uniformValues; 2045 2046 if (performAssignUniforms) 2047 { 2048 const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments"); 2049 assignUniforms(basicUniforms, programGL, rnd); 2050 } 2051 if (performCompareUniformValues) 2052 { 2053 PERFORM_AND_CHECK(getUniforms(uniformValues, basicUniforms, programGL), "GetUniforms", "Uniform value query"); 2054 PERFORM_AND_CHECK(compareUniformValues(uniformValues, basicUniforms), "ValueCheck", "Verify that the reported values match the assigned values"); 2055 } 2056 } 2057 2058 if (performRenderTest) 2059 PERFORM_AND_CHECK(renderTest(basicUniforms, program, rnd), "RenderTest", "Render test"); 2060 2061#undef PERFORM_AND_CHECK 2062 2063 return true; 2064} 2065 2066UniformApiTests::UniformApiTests (Context& context) 2067 : TestCaseGroup(context, "uniform_api", "Uniform API Tests") 2068{ 2069} 2070 2071UniformApiTests::~UniformApiTests (void) 2072{ 2073} 2074 2075namespace 2076{ 2077 2078// \note Although this is only used in UniformApiTest::init, it needs to be defined here as it's used as a template argument. 2079struct UniformCollectionCase 2080{ 2081 string namePrefix; 2082 SharedPtr<const UniformCollection> uniformCollection; 2083 2084 UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_) 2085 : namePrefix (name ? name + string("_") : "") 2086 , uniformCollection (uniformCollection_) 2087 { 2088 } 2089}; 2090 2091} // anonymous 2092 2093void UniformApiTests::init (void) 2094{ 2095 // Generate sets of UniformCollections that are used by several cases. 2096 2097 enum 2098 { 2099 UNIFORMCOLLECTIONS_BASIC = 0, 2100 UNIFORMCOLLECTIONS_BASIC_ARRAY, 2101 UNIFORMCOLLECTIONS_BASIC_STRUCT, 2102 UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY, 2103 UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, 2104 UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS, 2105 UNIFORMCOLLECTIONS_MULTIPLE_BASIC, 2106 UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY, 2107 UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS, 2108 2109 UNIFORMCOLLECTIONS_LAST 2110 }; 2111 2112 struct UniformCollectionGroup 2113 { 2114 string name; 2115 vector<UniformCollectionCase> cases; 2116 } defaultUniformCollections[UNIFORMCOLLECTIONS_LAST]; 2117 2118 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name = "basic"; 2119 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name = "basic_array"; 2120 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name = "basic_struct"; 2121 defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name = "struct_in_array"; 2122 defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name = "array_in_struct"; 2123 defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name = "nested_structs_arrays"; 2124 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name = "multiple_basic"; 2125 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name = "multiple_basic_array"; 2126 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name = "multiple_nested_structs_arrays"; 2127 2128 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++) 2129 { 2130 const glu::DataType dataType = s_testDataTypes[dataTypeNdx]; 2131 const char* const typeName = glu::getDataTypeName(dataType); 2132 2133 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType))); 2134 2135 if (glu::isDataTypeScalar(dataType) || 2136 (glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4) || 2137 dataType == glu::TYPE_FLOAT_MAT4 || 2138 dataType == glu::TYPE_SAMPLER_2D) 2139 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType))); 2140 2141 if (glu::isDataTypeScalar(dataType) || 2142 dataType == glu::TYPE_FLOAT_MAT4 || 2143 dataType == glu::TYPE_SAMPLER_2D) 2144 { 2145 const glu::DataType secondDataType = glu::isDataTypeScalar(dataType) ? glu::getDataTypeVector(dataType, 4) 2146 : dataType == glu::TYPE_FLOAT_MAT4 ? glu::TYPE_FLOAT_MAT2 2147 : dataType == glu::TYPE_SAMPLER_2D ? glu::TYPE_SAMPLER_CUBE 2148 : glu::TYPE_LAST; 2149 DE_ASSERT(secondDataType != glu::TYPE_LAST); 2150 const char* const secondTypeName = glu::getDataTypeName(secondDataType); 2151 const string name = string("") + typeName + "_" + secondTypeName; 2152 2153 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false))); 2154 defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true))); 2155 defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false))); 2156 defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType))); 2157 } 2158 } 2159 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic())); 2160 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray())); 2161 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs())); 2162 2163 // Info-query cases (check info returned by e.g. glGetActiveUniforms()). 2164 2165 { 2166 TestCaseGroup* const infoQueryGroup = new TestCaseGroup(m_context, "info_query", "Test glGetActiveUniform()"); 2167 addChild(infoQueryGroup); 2168 2169 for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++) 2170 { 2171 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx]; 2172 TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), ""); 2173 infoQueryGroup->addChild(collectionTestGroup); 2174 2175 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2176 { 2177 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2178 2179 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2180 { 2181 const string name = collectionCase.namePrefix + getCaseShaderTypeName((CaseShaderType)shaderType); 2182 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2183 2184 collectionTestGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection)); 2185 } 2186 } 2187 } 2188 2189 // Info-querying cases when unused uniforms are present. 2190 2191 { 2192 TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms"); 2193 infoQueryGroup->addChild(unusedUniformsGroup); 2194 2195 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT]; 2196 2197 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2198 { 2199 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2200 const string collName = collectionCase.namePrefix; 2201 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2202 2203 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2204 { 2205 const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType); 2206 unusedUniformsGroup->addChild(new UniformInfoQueryCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2207 UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER | UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX)); 2208 } 2209 } 2210 } 2211 } 2212 2213 // Cases testing uniform values. 2214 2215 { 2216 TestCaseGroup* const valueGroup = new TestCaseGroup(m_context, "value", "Uniform value tests"); 2217 addChild(valueGroup); 2218 2219 // Cases checking uniforms' initial values (all must be zeros), with glGetUniform*() or by rendering. 2220 2221 { 2222 TestCaseGroup* const initialValuesGroup = new TestCaseGroup(m_context, 2223 UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_INITIAL), 2224 UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_INITIAL)); 2225 valueGroup->addChild(initialValuesGroup); 2226 2227 for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++) 2228 { 2229 const UniformValueCase::CheckMethod checkMethod = (UniformValueCase::CheckMethod)checkMethodI; 2230 TestCaseGroup* const checkMethodGroup = new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod)); 2231 initialValuesGroup->addChild(checkMethodGroup); 2232 2233 for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++) 2234 { 2235 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx]; 2236 TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), ""); 2237 checkMethodGroup->addChild(collectionTestGroup); 2238 2239 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2240 { 2241 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2242 const string collName = collectionCase.namePrefix; 2243 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2244 const bool containsBooleans = uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec); 2245 const bool varyBoolApiType = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans && 2246 (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY); 2247 const int numBoolVariations = varyBoolApiType ? 2 : 1; 2248 2249 if (checkMethod == UniformValueCase::CHECKMETHOD_RENDER && uniformCollection->containsSeveralSamplerTypes()) 2250 continue; // \note Samplers' initial API values (i.e. their texture units) are 0, and no two samplers of different types shall have same unit when rendering. 2251 2252 for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++) 2253 { 2254 const deUint32 booleanTypeFeat = booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT 2255 : 0; 2256 const char* const booleanTypeName = booleanTypeI == 1 ? "int" 2257 : "float"; 2258 const string nameWithApiType = varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName; 2259 2260 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2261 { 2262 const string name = nameWithApiType + getCaseShaderTypeName((CaseShaderType)shaderType); 2263 collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2264 UniformValueCase::VALUETOCHECK_INITIAL, checkMethod, UniformValueCase::ASSIGNMETHOD_LAST, booleanTypeFeat)); 2265 } 2266 } 2267 } 2268 } 2269 } 2270 } 2271 2272 // Cases that first assign values to each uniform, then check the values with glGetUniform*() or by rendering. 2273 2274 { 2275 TestCaseGroup* const assignedValuesGroup = new TestCaseGroup(m_context, 2276 UniformValueCase::getValueToCheckName(UniformValueCase::VALUETOCHECK_ASSIGNED), 2277 UniformValueCase::getValueToCheckDescription(UniformValueCase::VALUETOCHECK_ASSIGNED)); 2278 valueGroup->addChild(assignedValuesGroup); 2279 2280 for (int assignMethodI = 0; assignMethodI < (int)UniformValueCase::ASSIGNMETHOD_LAST; assignMethodI++) 2281 { 2282 const UniformValueCase::AssignMethod assignMethod = (UniformValueCase::AssignMethod)assignMethodI; 2283 TestCaseGroup* const assignMethodGroup = new TestCaseGroup(m_context, UniformValueCase::getAssignMethodName(assignMethod), UniformValueCase::getAssignMethodDescription(assignMethod)); 2284 assignedValuesGroup->addChild(assignMethodGroup); 2285 2286 for (int checkMethodI = 0; checkMethodI < (int)UniformValueCase::CHECKMETHOD_LAST; checkMethodI++) 2287 { 2288 const UniformValueCase::CheckMethod checkMethod = (UniformValueCase::CheckMethod)checkMethodI; 2289 TestCaseGroup* const checkMethodGroup = new TestCaseGroup(m_context, UniformValueCase::getCheckMethodName(checkMethod), UniformValueCase::getCheckMethodDescription(checkMethod)); 2290 assignMethodGroup->addChild(checkMethodGroup); 2291 2292 for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++) 2293 { 2294 const int numArrayFirstElemNameCases = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1; 2295 2296 for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++) 2297 { 2298 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx]; 2299 const string collectionGroupName = collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets"); 2300 TestCaseGroup* collectionTestGroup = DE_NULL; 2301 2302 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2303 { 2304 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2305 const string collName = collectionCase.namePrefix; 2306 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2307 const bool containsBooleans = uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec); 2308 const bool varyBoolApiType = checkMethod == UniformValueCase::CHECKMETHOD_GET_UNIFORM && containsBooleans && 2309 (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY); 2310 const int numBoolVariations = varyBoolApiType ? 2 : 1; 2311 const bool containsMatrices = uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix); 2312 2313 if (containsMatrices && assignMethod != UniformValueCase::ASSIGNMETHOD_POINTER) 2314 continue; 2315 2316 for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++) 2317 { 2318 const deUint32 booleanTypeFeat = booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT 2319 : 0; 2320 const char* const booleanTypeName = booleanTypeI == 1 ? "int" 2321 : "float"; 2322 const string nameWithBoolType = varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName; 2323 const string nameWithMatrixType = nameWithBoolType; 2324 2325 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2326 { 2327 const string name = nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType); 2328 const deUint32 arrayFirstElemNameNoIndexFeat = referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX; 2329 2330 // skip empty groups by creating groups on demand 2331 if (!collectionTestGroup) 2332 { 2333 collectionTestGroup = new TestCaseGroup(m_context, collectionGroupName.c_str(), ""); 2334 checkMethodGroup->addChild(collectionTestGroup); 2335 } 2336 2337 collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2338 UniformValueCase::VALUETOCHECK_ASSIGNED, checkMethod, assignMethod, 2339 booleanTypeFeat | arrayFirstElemNameNoIndexFeat)); 2340 } 2341 } 2342 } 2343 } 2344 } 2345 } 2346 } 2347 2348 // Cases assign multiple basic-array elements with one glUniform*v() (i.e. the count parameter is bigger than 1). 2349 2350 { 2351 static const struct 2352 { 2353 UniformCase::Feature arrayAssignMode; 2354 const char* name; 2355 const char* description; 2356 } arrayAssignGroups[] = 2357 { 2358 { UniformCase::FEATURE_ARRAYASSIGN_FULL, "basic_array_assign_full", "Assign entire basic-type arrays per glUniform*v() call" }, 2359 { UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO, "basic_array_assign_partial", "Assign two elements of a basic-type array per glUniform*v() call" } 2360 }; 2361 2362 for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++) 2363 { 2364 UniformCase::Feature arrayAssignMode = arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode; 2365 const char* const groupName = arrayAssignGroups[arrayAssignGroupNdx].name; 2366 const char* const groupDesc = arrayAssignGroups[arrayAssignGroupNdx].description; 2367 2368 TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc); 2369 assignedValuesGroup->addChild(curArrayAssignGroup); 2370 2371 static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY }; 2372 2373 for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++) 2374 { 2375 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]]; 2376 TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), ""); 2377 curArrayAssignGroup->addChild(collectionTestGroup); 2378 2379 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2380 { 2381 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2382 const string collName = collectionCase.namePrefix; 2383 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2384 2385 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2386 { 2387 const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType); 2388 collectionTestGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2389 UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER, 2390 arrayAssignMode)); 2391 } 2392 } 2393 } 2394 } 2395 } 2396 2397 // Value checking cases when unused uniforms are present. 2398 2399 { 2400 TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms"); 2401 assignedValuesGroup->addChild(unusedUniformsGroup); 2402 2403 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT]; 2404 2405 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2406 { 2407 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2408 const string collName = collectionCase.namePrefix; 2409 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2410 2411 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2412 { 2413 const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType); 2414 unusedUniformsGroup->addChild(new UniformValueCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2415 UniformValueCase::VALUETOCHECK_ASSIGNED, UniformValueCase::CHECKMETHOD_GET_UNIFORM, UniformValueCase::ASSIGNMETHOD_POINTER, 2416 UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER)); 2417 } 2418 } 2419 } 2420 } 2421 } 2422 2423 // Random cases. 2424 2425 { 2426 const int numRandomCases = 100; 2427 TestCaseGroup* const randomGroup = new TestCaseGroup(m_context, "random", "Random cases"); 2428 addChild(randomGroup); 2429 2430 for (int ndx = 0; ndx < numRandomCases; ndx++) 2431 randomGroup->addChild(new RandomUniformCase(m_context, de::toString(ndx).c_str(), "", (deUint32)ndx)); 2432 } 2433} 2434 2435} // Functional 2436} // gles2 2437} // deqp 2438