1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief glProgramUniform*() tests. 22 * 23 * \todo [2013-02-26 nuutti] Much duplication between ES2&3 uniform api 24 * tests and this. Utilities to glshared? 25 *//*--------------------------------------------------------------------*/ 26 27 #include "es31fProgramUniformTests.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 "gluDrawUtil.hpp" 35 #include "tcuRenderTarget.hpp" 36 #include "tcuTestLog.hpp" 37 #include "tcuSurface.hpp" 38 #include "tcuCommandLine.hpp" 39 #include "deRandom.hpp" 40 #include "deStringUtil.hpp" 41 #include "deString.h" 42 #include "deSharedPtr.hpp" 43 #include "deMemory.h" 44 45 #include "glwEnums.hpp" 46 #include "glwFunctions.hpp" 47 48 #include <set> 49 #include <cstring> 50 51 using namespace glw; 52 53 namespace deqp 54 { 55 namespace gles31 56 { 57 namespace Functional 58 { 59 60 using std::vector; 61 using std::string; 62 using tcu::TestLog; 63 using tcu::ScopedLogSection; 64 using glu::ShaderProgram; 65 using glu::StructType; 66 using de::Random; 67 using de::SharedPtr; 68 69 typedef bool (* dataTypePredicate)(glu::DataType); 70 71 enum 72 { 73 MAX_RENDER_WIDTH = 32, 74 MAX_RENDER_HEIGHT = 32, 75 MAX_NUM_SAMPLER_UNIFORMS = 16 76 }; 77 78 static const glu::DataType s_testDataTypes[] = 79 { 80 glu::TYPE_FLOAT, 81 glu::TYPE_FLOAT_VEC2, 82 glu::TYPE_FLOAT_VEC3, 83 glu::TYPE_FLOAT_VEC4, 84 glu::TYPE_FLOAT_MAT2, 85 glu::TYPE_FLOAT_MAT2X3, 86 glu::TYPE_FLOAT_MAT2X4, 87 glu::TYPE_FLOAT_MAT3X2, 88 glu::TYPE_FLOAT_MAT3, 89 glu::TYPE_FLOAT_MAT3X4, 90 glu::TYPE_FLOAT_MAT4X2, 91 glu::TYPE_FLOAT_MAT4X3, 92 glu::TYPE_FLOAT_MAT4, 93 94 glu::TYPE_INT, 95 glu::TYPE_INT_VEC2, 96 glu::TYPE_INT_VEC3, 97 glu::TYPE_INT_VEC4, 98 99 glu::TYPE_UINT, 100 glu::TYPE_UINT_VEC2, 101 glu::TYPE_UINT_VEC3, 102 glu::TYPE_UINT_VEC4, 103 104 glu::TYPE_BOOL, 105 glu::TYPE_BOOL_VEC2, 106 glu::TYPE_BOOL_VEC3, 107 glu::TYPE_BOOL_VEC4, 108 109 glu::TYPE_SAMPLER_2D, 110 glu::TYPE_SAMPLER_CUBE 111 // \note We don't test all sampler types here. 112 }; 113 114 static inline int getGLInt (const glw::Functions& funcs, const deUint32 name) 115 { 116 int val = -1; 117 funcs.getIntegerv(name, &val); 118 return val; 119 } 120 121 static inline tcu::Vec4 vec4FromPtr (const float* const ptr) 122 { 123 tcu::Vec4 result; 124 for (int i = 0; i < 4; i++) 125 result[i] = ptr[i]; 126 return result; 127 } 128 129 static inline string beforeLast (const string& str, const char c) 130 { 131 return str.substr(0, str.find_last_of(c)); 132 } 133 134 static inline void fillWithColor (const tcu::PixelBufferAccess& access, const tcu::Vec4& color) 135 { 136 for (int z = 0; z < access.getDepth(); z++) 137 for (int y = 0; y < access.getHeight(); y++) 138 for (int x = 0; x < access.getWidth(); x++) 139 access.setPixel(color, x, y, z); 140 } 141 142 static inline int getSamplerNumLookupDimensions (const glu::DataType type) 143 { 144 switch (type) 145 { 146 case glu::TYPE_SAMPLER_2D: 147 case glu::TYPE_INT_SAMPLER_2D: 148 case glu::TYPE_UINT_SAMPLER_2D: 149 return 2; 150 151 case glu::TYPE_SAMPLER_3D: 152 case glu::TYPE_INT_SAMPLER_3D: 153 case glu::TYPE_UINT_SAMPLER_3D: 154 case glu::TYPE_SAMPLER_2D_SHADOW: 155 case glu::TYPE_SAMPLER_2D_ARRAY: 156 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 157 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 158 case glu::TYPE_SAMPLER_CUBE: 159 case glu::TYPE_INT_SAMPLER_CUBE: 160 case glu::TYPE_UINT_SAMPLER_CUBE: 161 return 3; 162 163 case glu::TYPE_SAMPLER_CUBE_SHADOW: 164 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 165 return 4; 166 167 default: 168 DE_ASSERT(false); 169 return 0; 170 } 171 } 172 173 static inline glu::DataType getSamplerLookupReturnType (const glu::DataType type) 174 { 175 switch (type) 176 { 177 case glu::TYPE_SAMPLER_2D: 178 case glu::TYPE_SAMPLER_CUBE: 179 case glu::TYPE_SAMPLER_2D_ARRAY: 180 case glu::TYPE_SAMPLER_3D: 181 return glu::TYPE_FLOAT_VEC4; 182 183 case glu::TYPE_UINT_SAMPLER_2D: 184 case glu::TYPE_UINT_SAMPLER_CUBE: 185 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 186 case glu::TYPE_UINT_SAMPLER_3D: 187 return glu::TYPE_UINT_VEC4; 188 189 case glu::TYPE_INT_SAMPLER_2D: 190 case glu::TYPE_INT_SAMPLER_CUBE: 191 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 192 case glu::TYPE_INT_SAMPLER_3D: 193 return glu::TYPE_INT_VEC4; 194 195 case glu::TYPE_SAMPLER_2D_SHADOW: 196 case glu::TYPE_SAMPLER_CUBE_SHADOW: 197 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 198 return glu::TYPE_FLOAT; 199 200 default: 201 DE_ASSERT(false); 202 return glu::TYPE_LAST; 203 } 204 } 205 206 template<glu::DataType T> 207 static bool dataTypeEquals (const glu::DataType t) 208 { 209 return t == T; 210 } 211 212 template<int N> 213 static bool dataTypeIsMatrixWithNRows (const glu::DataType t) 214 { 215 return glu::isDataTypeMatrix(t) && glu::getDataTypeMatrixNumRows(t) == N; 216 } 217 218 static bool typeContainsMatchingBasicType (const glu::VarType& type, const dataTypePredicate predicate) 219 { 220 if (type.isBasicType()) 221 return predicate(type.getBasicType()); 222 else if (type.isArrayType()) 223 return typeContainsMatchingBasicType(type.getElementType(), predicate); 224 else 225 { 226 DE_ASSERT(type.isStructType()); 227 const StructType& structType = *type.getStructPtr(); 228 for (int i = 0; i < structType.getNumMembers(); i++) 229 if (typeContainsMatchingBasicType(structType.getMember(i).getType(), predicate)) 230 return true; 231 return false; 232 } 233 } 234 235 static void getDistinctSamplerTypes (vector<glu::DataType>& dst, const glu::VarType& type) 236 { 237 if (type.isBasicType()) 238 { 239 const glu::DataType basicType = type.getBasicType(); 240 if (glu::isDataTypeSampler(basicType) && std::find(dst.begin(), dst.end(), basicType) == dst.end()) 241 dst.push_back(basicType); 242 } 243 else if (type.isArrayType()) 244 getDistinctSamplerTypes(dst, type.getElementType()); 245 else 246 { 247 DE_ASSERT(type.isStructType()); 248 const StructType& structType = *type.getStructPtr(); 249 for (int i = 0; i < structType.getNumMembers(); i++) 250 getDistinctSamplerTypes(dst, structType.getMember(i).getType()); 251 } 252 } 253 254 static int getNumSamplersInType (const glu::VarType& type) 255 { 256 if (type.isBasicType()) 257 return glu::isDataTypeSampler(type.getBasicType()) ? 1 : 0; 258 else if (type.isArrayType()) 259 return getNumSamplersInType(type.getElementType()) * type.getArraySize(); 260 else 261 { 262 DE_ASSERT(type.isStructType()); 263 const StructType& structType = *type.getStructPtr(); 264 int sum = 0; 265 for (int i = 0; i < structType.getNumMembers(); i++) 266 sum += getNumSamplersInType(structType.getMember(i).getType()); 267 return sum; 268 } 269 } 270 271 namespace 272 { 273 274 struct VarValue 275 { 276 glu::DataType type; 277 278 union 279 { 280 float floatV[4*4]; // At most mat4. \note Matrices here are column-major. 281 deInt32 intV[4]; 282 deUint32 uintV[4]; 283 bool boolV[4]; 284 struct 285 { 286 int unit; 287 union 288 { 289 float floatV[4]; 290 deInt32 intV[4]; 291 deUint32 uintV[4]; 292 } fillColor; 293 } samplerV; 294 } val; 295 }; 296 297 enum CaseShaderType 298 { 299 CASESHADERTYPE_VERTEX = 0, 300 CASESHADERTYPE_FRAGMENT, 301 CASESHADERTYPE_BOTH, 302 303 CASESHADERTYPE_LAST 304 }; 305 306 struct Uniform 307 { 308 string name; 309 glu::VarType type; 310 311 Uniform (const char* const name_, const glu::VarType& type_) : name(name_), type(type_) {} 312 }; 313 314 // A set of uniforms, along with related struct types. 315 class UniformCollection 316 { 317 public: 318 int getNumUniforms (void) const { return (int)m_uniforms.size(); } 319 int getNumStructTypes (void) const { return (int)m_structTypes.size(); } 320 Uniform& getUniform (const int ndx) { return m_uniforms[ndx]; } 321 const Uniform& getUniform (const int ndx) const { return m_uniforms[ndx]; } 322 const StructType* getStructType (const int ndx) const { return m_structTypes[ndx]; } 323 void addUniform (const Uniform& uniform) { m_uniforms.push_back(uniform); } 324 void addStructType (const StructType* const type) { m_structTypes.push_back(type); } 325 326 UniformCollection (void) {} 327 ~UniformCollection (void) 328 { 329 for (int i = 0; i < (int)m_structTypes.size(); i++) 330 delete m_structTypes[i]; 331 } 332 333 // Add the contents of m_uniforms and m_structTypes to receiver, and remove them from this one. 334 // \note receiver takes ownership of the struct types. 335 void moveContents (UniformCollection& receiver) 336 { 337 for (int i = 0; i < (int)m_uniforms.size(); i++) 338 receiver.addUniform(m_uniforms[i]); 339 m_uniforms.clear(); 340 341 for (int i = 0; i < (int)m_structTypes.size(); i++) 342 receiver.addStructType(m_structTypes[i]); 343 m_structTypes.clear(); 344 } 345 346 bool containsMatchingBasicType (const dataTypePredicate predicate) const 347 { 348 for (int i = 0; i < (int)m_uniforms.size(); i++) 349 if (typeContainsMatchingBasicType(m_uniforms[i].type, predicate)) 350 return true; 351 return false; 352 } 353 354 vector<glu::DataType> getSamplerTypes (void) const 355 { 356 vector<glu::DataType> samplerTypes; 357 for (int i = 0; i < (int)m_uniforms.size(); i++) 358 getDistinctSamplerTypes(samplerTypes, m_uniforms[i].type); 359 return samplerTypes; 360 } 361 362 bool containsSeveralSamplerTypes (void) const 363 { 364 return getSamplerTypes().size() > 1; 365 } 366 367 int getNumSamplers (void) const 368 { 369 int sum = 0; 370 for (int i = 0; i < (int)m_uniforms.size(); i++) 371 sum += getNumSamplersInType(m_uniforms[i].type); 372 return sum; 373 } 374 375 static UniformCollection* basic (const glu::DataType type, const char* const nameSuffix = "") 376 { 377 UniformCollection* const res = new UniformCollection; 378 const glu::Precision prec = glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 379 res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(type, prec))); 380 return res; 381 } 382 383 static UniformCollection* basicArray (const glu::DataType type, const char* const nameSuffix = "") 384 { 385 UniformCollection* const res = new UniformCollection; 386 const glu::Precision prec = glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 387 res->m_uniforms.push_back(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(glu::VarType(type, prec), 3))); 388 return res; 389 } 390 391 static UniformCollection* basicStruct (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "") 392 { 393 UniformCollection* const res = new UniformCollection; 394 const glu::Precision prec0 = glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 395 const glu::Precision prec1 = glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 396 397 StructType* const structType = new StructType((string("structType") + nameSuffix).c_str()); 398 structType->addMember("m0", glu::VarType(type0, prec0)); 399 structType->addMember("m1", glu::VarType(type1, prec1)); 400 if (containsArrays) 401 { 402 structType->addMember("m2", glu::VarType(glu::VarType(type0, prec0), 3)); 403 structType->addMember("m3", glu::VarType(glu::VarType(type1, prec1), 3)); 404 } 405 406 res->addStructType(structType); 407 res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType))); 408 409 return res; 410 } 411 412 static UniformCollection* structInArray (const glu::DataType type0, const glu::DataType type1, const bool containsArrays, const char* const nameSuffix = "") 413 { 414 UniformCollection* const res = basicStruct(type0, type1, containsArrays, nameSuffix); 415 res->getUniform(0).type = glu::VarType(res->getUniform(0).type, 3); 416 return res; 417 } 418 419 static UniformCollection* nestedArraysStructs (const glu::DataType type0, const glu::DataType type1, const char* const nameSuffix = "") 420 { 421 UniformCollection* const res = new UniformCollection; 422 const glu::Precision prec0 = glu::isDataTypeBoolOrBVec(type0) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 423 const glu::Precision prec1 = glu::isDataTypeBoolOrBVec(type1) ? glu::PRECISION_LAST : glu::PRECISION_MEDIUMP; 424 StructType* const structType = new StructType((string("structType") + nameSuffix).c_str()); 425 StructType* const subStructType = new StructType((string("subStructType") + nameSuffix).c_str()); 426 StructType* const subSubStructType = new StructType((string("subSubStructType") + nameSuffix).c_str()); 427 428 subSubStructType->addMember("mss0", glu::VarType(type0, prec0)); 429 subSubStructType->addMember("mss1", glu::VarType(type1, prec1)); 430 431 subStructType->addMember("ms0", glu::VarType(type1, prec1)); 432 subStructType->addMember("ms1", glu::VarType(glu::VarType(type0, prec0), 2)); 433 subStructType->addMember("ms2", glu::VarType(glu::VarType(subSubStructType), 2)); 434 435 structType->addMember("m0", glu::VarType(type0, prec0)); 436 structType->addMember("m1", glu::VarType(subStructType)); 437 structType->addMember("m2", glu::VarType(type1, prec1)); 438 439 res->addStructType(subSubStructType); 440 res->addStructType(subStructType); 441 res->addStructType(structType); 442 443 res->addUniform(Uniform((string("u_var") + nameSuffix).c_str(), glu::VarType(structType))); 444 445 return res; 446 } 447 448 static UniformCollection* multipleBasic (const char* const nameSuffix = "") 449 { 450 static const glu::DataType types[] = { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_UINT_VEC4, glu::TYPE_FLOAT_MAT3, glu::TYPE_BOOL_VEC2 }; 451 UniformCollection* const res = new UniformCollection; 452 453 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++) 454 { 455 UniformCollection* const sub = basic(types[i], ("_" + de::toString(i) + nameSuffix).c_str()); 456 sub->moveContents(*res); 457 delete sub; 458 } 459 460 return res; 461 } 462 463 static UniformCollection* multipleBasicArray (const char* const nameSuffix = "") 464 { 465 static const glu::DataType types[] = { glu::TYPE_FLOAT, glu::TYPE_INT_VEC3, glu::TYPE_BOOL_VEC2 }; 466 UniformCollection* const res = new UniformCollection; 467 468 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types); i++) 469 { 470 UniformCollection* const sub = basicArray(types[i], ("_" + de::toString(i) + nameSuffix).c_str()); 471 sub->moveContents(*res); 472 delete sub; 473 } 474 475 return res; 476 } 477 478 static UniformCollection* multipleNestedArraysStructs (const char* const nameSuffix = "") 479 { 480 static const glu::DataType types0[] = { glu::TYPE_FLOAT, glu::TYPE_INT, glu::TYPE_BOOL_VEC4 }; 481 static const glu::DataType types1[] = { glu::TYPE_FLOAT_VEC4, glu::TYPE_INT_VEC4, glu::TYPE_BOOL }; 482 UniformCollection* const res = new UniformCollection; 483 484 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types0) == DE_LENGTH_OF_ARRAY(types1)); 485 486 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types0); i++) 487 { 488 UniformCollection* const sub = nestedArraysStructs(types0[i], types1[i], ("_" + de::toString(i) + nameSuffix).c_str()); 489 sub->moveContents(*res); 490 delete sub; 491 } 492 493 return res; 494 } 495 496 private: 497 // \note Copying these would be cumbersome, since deep-copying both m_uniforms and m_structTypes 498 // would mean that we'd need to update pointers from uniforms to point to the new structTypes. 499 // When the same UniformCollection is needed in several places, a SharedPtr is used instead. 500 UniformCollection (const UniformCollection&); // Not allowed. 501 UniformCollection& operator= (const UniformCollection&); // Not allowed. 502 503 vector<Uniform> m_uniforms; 504 vector<const StructType*> m_structTypes; 505 }; 506 507 }; // anonymous 508 509 static VarValue getSamplerFillValue (const VarValue& sampler) 510 { 511 DE_ASSERT(glu::isDataTypeSampler(sampler.type)); 512 513 VarValue result; 514 result.type = getSamplerLookupReturnType(sampler.type); 515 516 switch (result.type) 517 { 518 case glu::TYPE_FLOAT_VEC4: 519 for (int i = 0; i < 4; i++) 520 result.val.floatV[i] = sampler.val.samplerV.fillColor.floatV[i]; 521 break; 522 case glu::TYPE_UINT_VEC4: 523 for (int i = 0; i < 4; i++) 524 result.val.uintV[i] = sampler.val.samplerV.fillColor.uintV[i]; 525 break; 526 case glu::TYPE_INT_VEC4: 527 for (int i = 0; i < 4; i++) 528 result.val.intV[i] = sampler.val.samplerV.fillColor.intV[i]; 529 break; 530 case glu::TYPE_FLOAT: 531 result.val.floatV[0] = sampler.val.samplerV.fillColor.floatV[0]; 532 break; 533 default: 534 DE_ASSERT(false); 535 } 536 537 return result; 538 } 539 540 static VarValue getSamplerUnitValue (const VarValue& sampler) 541 { 542 DE_ASSERT(glu::isDataTypeSampler(sampler.type)); 543 544 VarValue result; 545 result.type = glu::TYPE_INT; 546 result.val.intV[0] = sampler.val.samplerV.unit; 547 548 return result; 549 } 550 551 static glu::DataType getDataTypeTransposedMatrix (const glu::DataType original) 552 { 553 return glu::getDataTypeMatrix(glu::getDataTypeMatrixNumRows(original), glu::getDataTypeMatrixNumColumns(original)); 554 } 555 556 static VarValue getTransposeMatrix (const VarValue& original) 557 { 558 DE_ASSERT(glu::isDataTypeMatrix(original.type)); 559 560 const int rows = glu::getDataTypeMatrixNumRows(original.type); 561 const int cols = glu::getDataTypeMatrixNumColumns(original.type); 562 VarValue result; 563 result.type = getDataTypeTransposedMatrix(original.type); 564 565 for (int i = 0; i < rows; i++) 566 for (int j = 0; j < cols; j++) 567 result.val.floatV[i*cols + j] = original.val.floatV[j*rows + i]; 568 569 return result; 570 } 571 572 static string shaderVarValueStr (const VarValue& value) 573 { 574 const int numElems = glu::getDataTypeScalarSize(value.type); 575 std::ostringstream result; 576 577 if (numElems > 1) 578 result << glu::getDataTypeName(value.type) << "("; 579 580 for (int i = 0; i < numElems; i++) 581 { 582 if (i > 0) 583 result << ", "; 584 585 if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type)) 586 result << de::floatToString(value.val.floatV[i], 2); 587 else if (glu::isDataTypeIntOrIVec((value.type))) 588 result << de::toString(value.val.intV[i]); 589 else if (glu::isDataTypeUintOrUVec((value.type))) 590 result << de::toString(value.val.uintV[i]) << "u"; 591 else if (glu::isDataTypeBoolOrBVec((value.type))) 592 result << (value.val.boolV[i] ? "true" : "false"); 593 else if (glu::isDataTypeSampler((value.type))) 594 result << shaderVarValueStr(getSamplerFillValue(value)); 595 else 596 DE_ASSERT(false); 597 } 598 599 if (numElems > 1) 600 result << ")"; 601 602 return result.str(); 603 } 604 605 static string apiVarValueStr (const VarValue& value) 606 { 607 const int numElems = glu::getDataTypeScalarSize(value.type); 608 std::ostringstream result; 609 610 if (numElems > 1) 611 result << "("; 612 613 for (int i = 0; i < numElems; i++) 614 { 615 if (i > 0) 616 result << ", "; 617 618 if (glu::isDataTypeFloatOrVec(value.type) || glu::isDataTypeMatrix(value.type)) 619 result << de::floatToString(value.val.floatV[i], 2); 620 else if (glu::isDataTypeIntOrIVec((value.type))) 621 result << de::toString(value.val.intV[i]); 622 else if (glu::isDataTypeUintOrUVec((value.type))) 623 result << de::toString(value.val.uintV[i]); 624 else if (glu::isDataTypeBoolOrBVec((value.type))) 625 result << (value.val.boolV[i] ? "true" : "false"); 626 else if (glu::isDataTypeSampler((value.type))) 627 result << value.val.samplerV.unit; 628 else 629 DE_ASSERT(false); 630 } 631 632 if (numElems > 1) 633 result << ")"; 634 635 return result.str(); 636 } 637 638 static 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. */) 639 { 640 const int numElems = glu::getDataTypeScalarSize(type); 641 VarValue result; 642 result.type = type; 643 644 DE_ASSERT((samplerUnit >= 0) == (glu::isDataTypeSampler(type))); 645 646 if (glu::isDataTypeFloatOrVec(type) || glu::isDataTypeMatrix(type)) 647 { 648 for (int i = 0; i < numElems; i++) 649 result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f); 650 } 651 else if (glu::isDataTypeIntOrIVec(type)) 652 { 653 for (int i = 0; i < numElems; i++) 654 result.val.intV[i] = rnd.getInt(-10, 10); 655 } 656 else if (glu::isDataTypeUintOrUVec(type)) 657 { 658 for (int i = 0; i < numElems; i++) 659 result.val.uintV[i] = (deUint32)rnd.getInt(0, 10); 660 } 661 else if (glu::isDataTypeBoolOrBVec(type)) 662 { 663 for (int i = 0; i < numElems; i++) 664 result.val.boolV[i] = rnd.getBool(); 665 } 666 else if (glu::isDataTypeSampler(type)) 667 { 668 const glu::DataType texResultType = getSamplerLookupReturnType(type); 669 const glu::DataType texResultScalarType = glu::getDataTypeScalarType(texResultType); 670 const int texResultNumDims = glu::getDataTypeScalarSize(texResultType); 671 672 result.val.samplerV.unit = samplerUnit; 673 674 for (int i = 0; i < texResultNumDims; i++) 675 { 676 switch (texResultScalarType) 677 { 678 case glu::TYPE_FLOAT: result.val.samplerV.fillColor.floatV[i] = rnd.getFloat(0.0f, 1.0f); break; 679 case glu::TYPE_INT: result.val.samplerV.fillColor.intV[i] = rnd.getInt(-10, 10); break; 680 case glu::TYPE_UINT: result.val.samplerV.fillColor.uintV[i] = (deUint32)rnd.getInt(0, 10); break; 681 default: 682 DE_ASSERT(false); 683 } 684 } 685 } 686 else 687 DE_ASSERT(false); 688 689 return result; 690 } 691 692 static bool apiVarValueEquals (const VarValue& a, const VarValue& b) 693 { 694 const int size = glu::getDataTypeScalarSize(a.type); 695 const float floatThreshold = 0.05f; 696 697 DE_ASSERT(a.type == b.type); 698 699 if (glu::isDataTypeFloatOrVec(a.type) || glu::isDataTypeMatrix(a.type)) 700 { 701 for (int i = 0; i < size; i++) 702 if (de::abs(a.val.floatV[i] - b.val.floatV[i]) >= floatThreshold) 703 return false; 704 } 705 else if (glu::isDataTypeIntOrIVec(a.type)) 706 { 707 for (int i = 0; i < size; i++) 708 if (a.val.intV[i] != b.val.intV[i]) 709 return false; 710 } 711 else if (glu::isDataTypeUintOrUVec(a.type)) 712 { 713 for (int i = 0; i < size; i++) 714 if (a.val.uintV[i] != b.val.uintV[i]) 715 return false; 716 } 717 else if (glu::isDataTypeBoolOrBVec(a.type)) 718 { 719 for (int i = 0; i < size; i++) 720 if (a.val.boolV[i] != b.val.boolV[i]) 721 return false; 722 } 723 else if (glu::isDataTypeSampler(a.type)) 724 { 725 if (a.val.samplerV.unit != b.val.samplerV.unit) 726 return false; 727 } 728 else 729 DE_ASSERT(false); 730 731 return true; 732 } 733 734 static VarValue getRandomBoolRepresentation (const VarValue& boolValue, const glu::DataType targetScalarType, Random& rnd) 735 { 736 DE_ASSERT(glu::isDataTypeBoolOrBVec(boolValue.type)); 737 738 const int size = glu::getDataTypeScalarSize(boolValue.type); 739 const glu::DataType targetType = size == 1 ? targetScalarType : glu::getDataTypeVector(targetScalarType, size); 740 VarValue result; 741 result.type = targetType; 742 743 switch (targetScalarType) 744 { 745 case glu::TYPE_INT: 746 for (int i = 0; i < size; i++) 747 { 748 if (boolValue.val.boolV[i]) 749 { 750 result.val.intV[i] = rnd.getInt(-10, 10); 751 if (result.val.intV[i] == 0) 752 result.val.intV[i] = 1; 753 } 754 else 755 result.val.intV[i] = 0; 756 } 757 break; 758 759 case glu::TYPE_UINT: 760 for (int i = 0; i < size; i++) 761 { 762 if (boolValue.val.boolV[i]) 763 result.val.uintV[i] = rnd.getInt(1, 10); 764 else 765 result.val.uintV[i] = 0; 766 } 767 break; 768 769 case glu::TYPE_FLOAT: 770 for (int i = 0; i < size; i++) 771 { 772 if (boolValue.val.boolV[i]) 773 { 774 result.val.floatV[i] = rnd.getFloat(-10.0f, 10.0f); 775 if (result.val.floatV[i] == 0.0f) 776 result.val.floatV[i] = 1.0f; 777 } 778 else 779 result.val.floatV[i] = 0; 780 } 781 break; 782 783 default: 784 DE_ASSERT(false); 785 } 786 787 return result; 788 } 789 790 static const char* getCaseShaderTypeName (const CaseShaderType type) 791 { 792 switch (type) 793 { 794 case CASESHADERTYPE_VERTEX: return "vertex"; 795 case CASESHADERTYPE_FRAGMENT: return "fragment"; 796 case CASESHADERTYPE_BOTH: return "both"; 797 default: 798 DE_ASSERT(false); 799 return DE_NULL; 800 } 801 } 802 803 class UniformCase : public TestCase, protected glu::CallLogWrapper 804 { 805 public: 806 enum Feature 807 { 808 // ARRAYUSAGE_ONLY_MIDDLE_INDEX: only middle index of each array is used in shader. If not given, use all indices. 809 FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX = 1<<0, 810 811 // UNIFORMFUNC_VALUE: use pass-by-value versions of uniform assignment funcs, e.g. glProgramUniform1f(), where possible. If not given, use pass-by-pointer versions. 812 FEATURE_UNIFORMFUNC_VALUE = 1<<1, 813 814 // MATRIXMODE_ROWMAJOR: pass matrices to GL in row major form. If not given, use column major. 815 FEATURE_MATRIXMODE_ROWMAJOR = 1<<2, 816 817 // ARRAYASSIGN: how basic-type arrays are assigned with glProgramUniform*(). If none given, assign each element of an array separately. 818 FEATURE_ARRAYASSIGN_FULL = 1<<3, //!< Assign all elements of an array with one glProgramUniform*(). 819 FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO = 1<<4, //!< Assign two elements per one glProgramUniform*(). 820 821 // 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). 822 FEATURE_UNIFORMUSAGE_EVERY_OTHER = 1<<5, 823 824 // BOOLEANAPITYPE: type used to pass booleans to and from GL api. If none given, use float. 825 FEATURE_BOOLEANAPITYPE_INT = 1<<6, 826 FEATURE_BOOLEANAPITYPE_UINT = 1<<7, 827 828 // 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. 829 FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX = 1<<8 830 }; 831 832 UniformCase (Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection); 833 UniformCase (Context& context, const char* name, const char* description, CaseShaderType caseType, const SharedPtr<const UniformCollection>& uniformCollection, deUint32 features); 834 virtual ~UniformCase (void); 835 836 virtual void init (void); 837 virtual void deinit (void); 838 839 IterateResult iterate (void); 840 841 protected: 842 // A basic uniform is a uniform (possibly struct or array member) whose type is a basic type (e.g. float, ivec4, sampler2d). 843 struct BasicUniform 844 { 845 string name; 846 glu::DataType type; 847 bool isUsedInShader; 848 VarValue finalValue; //!< The value we ultimately want to set for this uniform. 849 850 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. 851 int elemNdx; //!< If this is a member of a basic-typed array, elemNdx is the index in that array. Otherwise -1. 852 int rootSize; //!< If this is a member of a basic-typed array, rootSize is the size of that array. Otherwise 1. 853 854 BasicUniform (const char* const name_, 855 const glu::DataType type_, 856 const bool isUsedInShader_, 857 const VarValue& finalValue_, 858 const char* const rootName_ = DE_NULL, 859 const int elemNdx_ = -1, 860 const int rootSize_ = 1) 861 : name (name_) 862 , type (type_) 863 , isUsedInShader (isUsedInShader_) 864 , finalValue (finalValue_) 865 , rootName (rootName_ == DE_NULL ? name_ : rootName_) 866 , elemNdx (elemNdx_) 867 , rootSize (rootSize_) 868 { 869 } 870 871 static vector<BasicUniform>::const_iterator findWithName (const vector<BasicUniform>& vec, const char* const name) 872 { 873 for (vector<BasicUniform>::const_iterator it = vec.begin(); it != vec.end(); it++) 874 { 875 if (it->name == name) 876 return it; 877 } 878 return vec.end(); 879 } 880 }; 881 882 // Reference values for info that is expected to be reported by glGetActiveUniform() or glGetActiveUniformsiv(). 883 struct BasicUniformReportRef 884 { 885 string name; 886 // \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. 887 int minSize; 888 int maxSize; 889 glu::DataType type; 890 bool isUsedInShader; 891 892 BasicUniformReportRef (const char* const name_, const int minS, const int maxS, const glu::DataType type_, const bool used) 893 : name(name_), minSize(minS), maxSize(maxS), type(type_), isUsedInShader(used) { DE_ASSERT(minSize <= maxSize); } 894 BasicUniformReportRef (const char* const name_, const glu::DataType type_, const bool used) 895 : name(name_), minSize(1), maxSize(1), type(type_), isUsedInShader(used) {} 896 }; 897 898 // Get uniform values with glGetUniform*() and put to valuesDst. Uniforms that get -1 from glGetUniformLocation() get glu::TYPE_INVALID. 899 bool getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, deUint32 programGL); 900 // Assign the basicUniforms[].finalValue values for uniforms. \note rnd parameter is for booleans (true can be any nonzero value). 901 void assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd); 902 // Compare the uniform values given in values (obtained with glGetUniform*()) with the basicUniform.finalValue values. 903 bool compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms); 904 // Render and check that all pixels are green (i.e. all uniform comparisons passed). 905 bool renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd); 906 907 virtual bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) = 0; 908 909 const deUint32 m_features; 910 const SharedPtr<const UniformCollection> m_uniformCollection; 911 912 private: 913 // Generates the basic uniforms, based on the uniform with name varName and type varType, in the same manner as are expected 914 // to be returned by glGetActiveUniform(), e.g. generates a name like var[0] for arrays, and recursively generates struct member names. 915 void generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, 916 vector<BasicUniformReportRef>& basicUniformReportsDst, 917 const glu::VarType& varType, 918 const char* varName, 919 bool isParentActive, 920 int& samplerUnitCounter, 921 Random& rnd) const; 922 923 void writeUniformDefinitions (std::ostringstream& dst) const; 924 void writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const; 925 void writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* variableName) const; 926 927 string generateVertexSource (const vector<BasicUniform>& basicUniforms) const; 928 string generateFragmentSource (const vector<BasicUniform>& basicUniforms) const; 929 930 void setupTexture (const VarValue& value); 931 932 const CaseShaderType m_caseShaderType; 933 934 vector<glu::Texture2D*> m_textures2d; 935 vector<glu::TextureCube*> m_texturesCube; 936 vector<deUint32> m_filledTextureUnits; 937 }; 938 939 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection, const deUint32 features) 940 : TestCase (context, name, description) 941 , CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog()) 942 , m_features (features) 943 , m_uniformCollection (uniformCollection) 944 , m_caseShaderType (caseShaderType) 945 { 946 } 947 948 UniformCase::UniformCase (Context& context, const char* const name, const char* const description, const CaseShaderType caseShaderType, const SharedPtr<const UniformCollection>& uniformCollection) 949 : TestCase (context, name, description) 950 , CallLogWrapper (context.getRenderContext().getFunctions(), m_testCtx.getLog()) 951 , m_features (0) 952 , m_uniformCollection (uniformCollection) 953 , m_caseShaderType (caseShaderType) 954 { 955 } 956 957 void UniformCase::init (void) 958 { 959 { 960 const glw::Functions& funcs = m_context.getRenderContext().getFunctions(); 961 const int numSamplerUniforms = m_uniformCollection->getNumSamplers(); 962 const int vertexTexUnitsRequired = m_caseShaderType != CASESHADERTYPE_FRAGMENT ? numSamplerUniforms : 0; 963 const int fragmentTexUnitsRequired = m_caseShaderType != CASESHADERTYPE_VERTEX ? numSamplerUniforms : 0; 964 const int combinedTexUnitsRequired = vertexTexUnitsRequired + fragmentTexUnitsRequired; 965 const int vertexTexUnitsSupported = getGLInt(funcs, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); 966 const int fragmentTexUnitsSupported = getGLInt(funcs, GL_MAX_TEXTURE_IMAGE_UNITS); 967 const int combinedTexUnitsSupported = getGLInt(funcs, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); 968 969 DE_ASSERT(numSamplerUniforms <= MAX_NUM_SAMPLER_UNIFORMS); 970 971 if (vertexTexUnitsRequired > vertexTexUnitsSupported) 972 throw tcu::NotSupportedError(de::toString(vertexTexUnitsRequired) + " vertex texture units required, " + de::toString(vertexTexUnitsSupported) + " supported"); 973 if (fragmentTexUnitsRequired > fragmentTexUnitsSupported) 974 throw tcu::NotSupportedError(de::toString(fragmentTexUnitsRequired) + " fragment texture units required, " + de::toString(fragmentTexUnitsSupported) + " supported"); 975 if (combinedTexUnitsRequired > combinedTexUnitsSupported) 976 throw tcu::NotSupportedError(de::toString(combinedTexUnitsRequired) + " combined texture units required, " + de::toString(combinedTexUnitsSupported) + " supported"); 977 } 978 979 enableLogging(true); 980 } 981 982 void UniformCase::deinit (void) 983 { 984 for (int i = 0; i < (int)m_textures2d.size(); i++) 985 delete m_textures2d[i]; 986 m_textures2d.clear(); 987 988 for (int i = 0; i < (int)m_texturesCube.size(); i++) 989 delete m_texturesCube[i]; 990 m_texturesCube.clear(); 991 992 m_filledTextureUnits.clear(); 993 } 994 995 UniformCase::~UniformCase (void) 996 { 997 UniformCase::deinit(); 998 } 999 1000 void UniformCase::generateBasicUniforms (vector<BasicUniform>& basicUniformsDst, vector<BasicUniformReportRef>& basicUniformReportsDst, const glu::VarType& varType, const char* const varName, const bool isParentActive, int& samplerUnitCounter, Random& rnd) const 1001 { 1002 if (varType.isBasicType()) 1003 { 1004 const bool isActive = isParentActive && (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true); 1005 const glu::DataType type = varType.getBasicType(); 1006 const VarValue value = glu::isDataTypeSampler(type) ? generateRandomVarValue(type, rnd, samplerUnitCounter++) 1007 : generateRandomVarValue(varType.getBasicType(), rnd); 1008 1009 basicUniformsDst.push_back(BasicUniform(varName, varType.getBasicType(), isActive, value)); 1010 basicUniformReportsDst.push_back(BasicUniformReportRef(varName, varType.getBasicType(), isActive)); 1011 } 1012 else if (varType.isArrayType()) 1013 { 1014 const int size = varType.getArraySize(); 1015 const string arrayRootName = string("") + varName + "[0]"; 1016 vector<bool> isElemActive; 1017 1018 for (int elemNdx = 0; elemNdx < varType.getArraySize(); elemNdx++) 1019 { 1020 const string indexedName = string("") + varName + "[" + de::toString(elemNdx) + "]"; 1021 const bool isCurElemActive = isParentActive && 1022 (m_features & FEATURE_UNIFORMUSAGE_EVERY_OTHER ? basicUniformsDst.size() % 2 == 0 : true) && 1023 (m_features & FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX ? elemNdx == size/2 : true); 1024 1025 isElemActive.push_back(isCurElemActive); 1026 1027 if (varType.getElementType().isBasicType()) 1028 { 1029 // \note We don't want separate entries in basicUniformReportsDst for elements of basic-type arrays. 1030 const glu::DataType elemBasicType = varType.getElementType().getBasicType(); 1031 const VarValue value = glu::isDataTypeSampler(elemBasicType) ? generateRandomVarValue(elemBasicType, rnd, samplerUnitCounter++) 1032 : generateRandomVarValue(elemBasicType, rnd); 1033 1034 basicUniformsDst.push_back(BasicUniform(indexedName.c_str(), elemBasicType, isCurElemActive, value, arrayRootName.c_str(), elemNdx, size)); 1035 } 1036 else 1037 generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, varType.getElementType(), indexedName.c_str(), isCurElemActive, samplerUnitCounter, rnd); 1038 } 1039 1040 if (varType.getElementType().isBasicType()) 1041 { 1042 int minSize; 1043 for (minSize = varType.getArraySize(); minSize > 0 && !isElemActive[minSize-1]; minSize--); 1044 1045 basicUniformReportsDst.push_back(BasicUniformReportRef(arrayRootName.c_str(), minSize, size, varType.getElementType().getBasicType(), isParentActive && minSize > 0)); 1046 } 1047 } 1048 else 1049 { 1050 DE_ASSERT(varType.isStructType()); 1051 1052 const StructType& structType = *varType.getStructPtr(); 1053 1054 for (int i = 0; i < structType.getNumMembers(); i++) 1055 { 1056 const glu::StructMember& member = structType.getMember(i); 1057 const string memberFullName = string("") + varName + "." + member.getName(); 1058 1059 generateBasicUniforms(basicUniformsDst, basicUniformReportsDst, member.getType(), memberFullName.c_str(), isParentActive, samplerUnitCounter, rnd); 1060 } 1061 } 1062 } 1063 1064 void UniformCase::writeUniformDefinitions (std::ostringstream& dst) const 1065 { 1066 for (int i = 0; i < (int)m_uniformCollection->getNumStructTypes(); i++) 1067 dst << glu::declare(m_uniformCollection->getStructType(i)) << ";\n"; 1068 1069 for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++) 1070 dst << "uniform " << glu::declare(m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str()) << ";\n"; 1071 1072 dst << "\n"; 1073 1074 { 1075 static const struct 1076 { 1077 dataTypePredicate requiringTypes[2]; 1078 const char* definition; 1079 } compareFuncs[] = 1080 { 1081 { { glu::isDataTypeFloatOrVec, glu::isDataTypeMatrix }, "mediump float compare_float (mediump float a, mediump float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }" }, 1082 { { 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); }" }, 1083 { { 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); }" }, 1084 { { 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); }" }, 1085 { { 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]); }" }, 1086 { { dataTypeEquals<glu::TYPE_FLOAT_MAT2X3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat2x3 (mediump mat2x3 a, mediump mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }" }, 1087 { { dataTypeEquals<glu::TYPE_FLOAT_MAT2X4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat2x4 (mediump mat2x4 a, mediump mat2x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }" }, 1088 { { dataTypeEquals<glu::TYPE_FLOAT_MAT3X2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat3x2 (mediump mat3x2 a, mediump mat3x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }" }, 1089 { { 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]); }" }, 1090 { { dataTypeEquals<glu::TYPE_FLOAT_MAT3X4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat3x4 (mediump mat3x4 a, mediump mat3x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }" }, 1091 { { dataTypeEquals<glu::TYPE_FLOAT_MAT4X2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat4x2 (mediump mat4x2 a, mediump mat4x2 b){ return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }" }, 1092 { { dataTypeEquals<glu::TYPE_FLOAT_MAT4X3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_mat4x3 (mediump mat4x3 a, mediump mat4x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }" }, 1093 { { 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]); }" }, 1094 { { 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; }" }, 1095 { { 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; }" }, 1096 { { 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; }" }, 1097 { { 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; }" }, 1098 { { dataTypeEquals<glu::TYPE_UINT>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_uint (mediump uint a, mediump uint b) { return a == b ? 1.0 : 0.0; }" }, 1099 { { dataTypeEquals<glu::TYPE_UINT_VEC2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_uvec2 (mediump uvec2 a, mediump uvec2 b) { return a == b ? 1.0 : 0.0; }" }, 1100 { { dataTypeEquals<glu::TYPE_UINT_VEC3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_uvec3 (mediump uvec3 a, mediump uvec3 b) { return a == b ? 1.0 : 0.0; }" }, 1101 { { dataTypeEquals<glu::TYPE_UINT_VEC4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_uvec4 (mediump uvec4 a, mediump uvec4 b) { return a == b ? 1.0 : 0.0; }" }, 1102 { { dataTypeEquals<glu::TYPE_BOOL>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }" }, 1103 { { dataTypeEquals<glu::TYPE_BOOL_VEC2>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }" }, 1104 { { dataTypeEquals<glu::TYPE_BOOL_VEC3>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }" }, 1105 { { dataTypeEquals<glu::TYPE_BOOL_VEC4>, dataTypeEquals<glu::TYPE_INVALID> }, "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }" } 1106 }; 1107 1108 const vector<glu::DataType> samplerTypes = m_uniformCollection->getSamplerTypes(); 1109 1110 for (int compFuncNdx = 0; compFuncNdx < DE_LENGTH_OF_ARRAY(compareFuncs); compFuncNdx++) 1111 { 1112 const dataTypePredicate (&typeReq)[2] = compareFuncs[compFuncNdx].requiringTypes; 1113 bool containsTypeSampler = false; 1114 1115 for (int i = 0; i < (int)samplerTypes.size(); i++) 1116 { 1117 if (glu::isDataTypeSampler(samplerTypes[i])) 1118 { 1119 const glu::DataType retType = getSamplerLookupReturnType(samplerTypes[i]); 1120 if (typeReq[0](retType) || typeReq[1](retType)) 1121 { 1122 containsTypeSampler = true; 1123 break; 1124 } 1125 } 1126 } 1127 1128 if (containsTypeSampler || m_uniformCollection->containsMatchingBasicType(typeReq[0]) || m_uniformCollection->containsMatchingBasicType(typeReq[1])) 1129 dst << compareFuncs[compFuncNdx].definition << "\n"; 1130 } 1131 } 1132 } 1133 1134 void UniformCase::writeUniformCompareExpr (std::ostringstream& dst, const BasicUniform& uniform) const 1135 { 1136 if (glu::isDataTypeSampler(uniform.type)) 1137 dst << "compare_" << glu::getDataTypeName(getSamplerLookupReturnType(uniform.type)) << "(texture(" << uniform.name << ", vec" << getSamplerNumLookupDimensions(uniform.type) << "(0.0))"; 1138 else 1139 dst << "compare_" << glu::getDataTypeName(uniform.type) << "(" << uniform.name; 1140 1141 dst << ", " << shaderVarValueStr(uniform.finalValue) << ")"; 1142 } 1143 1144 void UniformCase::writeUniformComparisons (std::ostringstream& dst, const vector<BasicUniform>& basicUniforms, const char* const variableName) const 1145 { 1146 for (int i = 0; i < (int)basicUniforms.size(); i++) 1147 { 1148 const BasicUniform& unif = basicUniforms[i]; 1149 1150 if (unif.isUsedInShader) 1151 { 1152 dst << "\t" << variableName << " *= "; 1153 writeUniformCompareExpr(dst, basicUniforms[i]); 1154 dst << ";\n"; 1155 } 1156 else 1157 dst << "\t// UNUSED: " << basicUniforms[i].name << "\n"; 1158 } 1159 } 1160 1161 string UniformCase::generateVertexSource (const vector<BasicUniform>& basicUniforms) const 1162 { 1163 const bool isVertexCase = m_caseShaderType == CASESHADERTYPE_VERTEX || m_caseShaderType == CASESHADERTYPE_BOTH; 1164 std::ostringstream result; 1165 1166 result << "#version 310 es\n" 1167 "in highp vec4 a_position;\n" 1168 "out mediump float v_vtxOut;\n" 1169 "\n"; 1170 1171 if (isVertexCase) 1172 writeUniformDefinitions(result); 1173 1174 result << "\n" 1175 "void main (void)\n" 1176 "{\n" 1177 " gl_Position = a_position;\n" 1178 " v_vtxOut = 1.0;\n"; 1179 1180 if (isVertexCase) 1181 writeUniformComparisons(result, basicUniforms, "v_vtxOut"); 1182 1183 result << "}\n"; 1184 1185 return result.str(); 1186 } 1187 1188 string UniformCase::generateFragmentSource (const vector<BasicUniform>& basicUniforms) const 1189 { 1190 const bool isFragmentCase = m_caseShaderType == CASESHADERTYPE_FRAGMENT || m_caseShaderType == CASESHADERTYPE_BOTH; 1191 std::ostringstream result; 1192 1193 result << "#version 310 es\n" 1194 "in mediump float v_vtxOut;\n" 1195 "\n"; 1196 1197 if (isFragmentCase) 1198 writeUniformDefinitions(result); 1199 1200 result << "\n" 1201 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 1202 "\n" 1203 "void main (void)\n" 1204 "{\n" 1205 " mediump float result = v_vtxOut;\n"; 1206 1207 if (isFragmentCase) 1208 writeUniformComparisons(result, basicUniforms, "result"); 1209 1210 result << " dEQP_FragColor = vec4(1.0-result, result, 0.0, 1.0);\n" 1211 "}\n"; 1212 1213 return result.str(); 1214 } 1215 1216 void UniformCase::setupTexture (const VarValue& value) 1217 { 1218 // \note No handling for samplers other than 2D or cube. 1219 1220 enableLogging(false); 1221 1222 DE_ASSERT(getSamplerLookupReturnType(value.type) == glu::TYPE_FLOAT_VEC4); 1223 1224 const int width = 32; 1225 const int height = 32; 1226 const tcu::Vec4 color = vec4FromPtr(&value.val.samplerV.fillColor.floatV[0]); 1227 1228 if (value.type == glu::TYPE_SAMPLER_2D) 1229 { 1230 glu::Texture2D* texture = new glu::Texture2D(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width, height); 1231 tcu::Texture2D& refTexture = texture->getRefTexture(); 1232 m_textures2d.push_back(texture); 1233 1234 refTexture.allocLevel(0); 1235 fillWithColor(refTexture.getLevel(0), color); 1236 1237 GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit)); 1238 m_filledTextureUnits.push_back(value.val.samplerV.unit); 1239 texture->upload(); 1240 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 1241 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 1242 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 1243 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 1244 } 1245 else if (value.type == glu::TYPE_SAMPLER_CUBE) 1246 { 1247 DE_STATIC_ASSERT(width == height); 1248 glu::TextureCube* texture = new glu::TextureCube(m_context.getRenderContext(), GL_RGBA, GL_UNSIGNED_BYTE, width); 1249 tcu::TextureCube& refTexture = texture->getRefTexture(); 1250 m_texturesCube.push_back(texture); 1251 1252 for (int face = 0; face < (int)tcu::CUBEFACE_LAST; face++) 1253 { 1254 refTexture.allocLevel((tcu::CubeFace)face, 0); 1255 fillWithColor(refTexture.getLevelFace(0, (tcu::CubeFace)face), color); 1256 } 1257 1258 GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0 + value.val.samplerV.unit)); 1259 m_filledTextureUnits.push_back(value.val.samplerV.unit); 1260 texture->upload(); 1261 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 1262 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 1263 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 1264 GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 1265 1266 } 1267 else 1268 DE_ASSERT(false); 1269 1270 enableLogging(true); 1271 } 1272 1273 bool UniformCase::getUniforms (vector<VarValue>& valuesDst, const vector<BasicUniform>& basicUniforms, const deUint32 programGL) 1274 { 1275 TestLog& log = m_testCtx.getLog(); 1276 bool success = true; 1277 1278 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1279 { 1280 const BasicUniform& uniform = basicUniforms[unifNdx]; 1281 const string queryName = m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name; 1282 const int location = glGetUniformLocation(programGL, queryName.c_str()); 1283 const int size = glu::getDataTypeScalarSize(uniform.type); 1284 VarValue value; 1285 1286 deMemset(&value, 0xcd, sizeof(value)); // Initialize to known garbage. 1287 1288 if (location == -1) 1289 { 1290 value.type = glu::TYPE_INVALID; 1291 valuesDst.push_back(value); 1292 if (uniform.isUsedInShader) 1293 { 1294 log << TestLog::Message << "// FAILURE: " << uniform.name << " was used in shader, but has location -1" << TestLog::EndMessage; 1295 success = false; 1296 } 1297 continue; 1298 } 1299 1300 value.type = uniform.type; 1301 1302 DE_STATIC_ASSERT(sizeof(GLint) == sizeof(value.val.intV[0])); 1303 DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(value.val.uintV[0])); 1304 DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(value.val.floatV[0])); 1305 1306 if (glu::isDataTypeFloatOrVec(uniform.type) || glu::isDataTypeMatrix(uniform.type)) 1307 GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0])); 1308 else if (glu::isDataTypeIntOrIVec(uniform.type)) 1309 GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0])); 1310 else if (glu::isDataTypeUintOrUVec(uniform.type)) 1311 GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0])); 1312 else if (glu::isDataTypeBoolOrBVec(uniform.type)) 1313 { 1314 if (m_features & FEATURE_BOOLEANAPITYPE_INT) 1315 { 1316 GLU_CHECK_CALL(glGetUniformiv(programGL, location, &value.val.intV[0])); 1317 for (int i = 0; i < size; i++) 1318 value.val.boolV[i] = value.val.intV[i] != 0; 1319 } 1320 else if (m_features & FEATURE_BOOLEANAPITYPE_UINT) 1321 { 1322 GLU_CHECK_CALL(glGetUniformuiv(programGL, location, &value.val.uintV[0])); 1323 for (int i = 0; i < size; i++) 1324 value.val.boolV[i] = value.val.uintV[i] != 0; 1325 } 1326 else // Default: use float. 1327 { 1328 GLU_CHECK_CALL(glGetUniformfv(programGL, location, &value.val.floatV[0])); 1329 for (int i = 0; i < size; i++) 1330 value.val.boolV[i] = value.val.floatV[i] != 0.0f; 1331 } 1332 } 1333 else if (glu::isDataTypeSampler(uniform.type)) 1334 { 1335 GLint unit = -1; 1336 GLU_CHECK_CALL(glGetUniformiv(programGL, location, &unit)); 1337 value.val.samplerV.unit = unit; 1338 } 1339 else 1340 DE_ASSERT(false); 1341 1342 valuesDst.push_back(value); 1343 1344 log << TestLog::Message << "// Got " << uniform.name << " value " << apiVarValueStr(value) << TestLog::EndMessage; 1345 } 1346 1347 return success; 1348 } 1349 1350 void UniformCase::assignUniforms (const vector<BasicUniform>& basicUniforms, deUint32 programGL, Random& rnd) 1351 { 1352 TestLog& log = m_testCtx.getLog(); 1353 const bool transpose = (m_features & FEATURE_MATRIXMODE_ROWMAJOR) != 0; 1354 const GLboolean transposeGL = transpose ? GL_TRUE : GL_FALSE; 1355 const glu::DataType boolApiType = m_features & FEATURE_BOOLEANAPITYPE_INT ? glu::TYPE_INT 1356 : m_features & FEATURE_BOOLEANAPITYPE_UINT ? glu::TYPE_UINT 1357 : glu::TYPE_FLOAT; 1358 1359 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1360 { 1361 const BasicUniform& uniform = basicUniforms[unifNdx]; 1362 const bool isArrayMember = uniform.elemNdx >= 0; 1363 const string queryName = m_features & FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX && uniform.elemNdx == 0 ? beforeLast(uniform.name, '[') : uniform.name; 1364 const int numValuesToAssign = !isArrayMember ? 1 1365 : m_features & FEATURE_ARRAYASSIGN_FULL ? (uniform.elemNdx == 0 ? uniform.rootSize : 0) 1366 : m_features & FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO ? (uniform.elemNdx % 2 == 0 ? 2 : 0) 1367 : /* Default: assign array elements separately */ 1; 1368 1369 DE_ASSERT(numValuesToAssign >= 0); 1370 DE_ASSERT(numValuesToAssign == 1 || isArrayMember); 1371 1372 if (numValuesToAssign == 0) 1373 { 1374 log << TestLog::Message << "// Uniform " << uniform.name << " is covered by another glProgramUniform*v() call to the same array" << TestLog::EndMessage; 1375 continue; 1376 } 1377 1378 const int location = glGetUniformLocation(programGL, queryName.c_str()); 1379 const int typeSize = glu::getDataTypeScalarSize(uniform.type); 1380 const bool assignByValue = m_features & FEATURE_UNIFORMFUNC_VALUE && !glu::isDataTypeMatrix(uniform.type) && numValuesToAssign == 1; 1381 vector<VarValue> valuesToAssign; 1382 1383 for (int i = 0; i < numValuesToAssign; i++) 1384 { 1385 const string curName = isArrayMember ? beforeLast(uniform.rootName, '[') + "[" + de::toString(uniform.elemNdx+i) + "]" : uniform.name; 1386 VarValue unifValue; 1387 1388 if (isArrayMember) 1389 { 1390 const vector<BasicUniform>::const_iterator elemUnif = BasicUniform::findWithName(basicUniforms, curName.c_str()); 1391 if (elemUnif == basicUniforms.end()) 1392 continue; 1393 unifValue = elemUnif->finalValue; 1394 } 1395 else 1396 unifValue = uniform.finalValue; 1397 1398 const VarValue apiValue = glu::isDataTypeBoolOrBVec(unifValue.type) ? getRandomBoolRepresentation(unifValue, boolApiType, rnd) 1399 : glu::isDataTypeSampler(unifValue.type) ? getSamplerUnitValue(unifValue) 1400 : unifValue; 1401 1402 valuesToAssign.push_back(glu::isDataTypeMatrix(apiValue.type) && transpose ? getTransposeMatrix(apiValue) : apiValue); 1403 1404 if (glu::isDataTypeBoolOrBVec(uniform.type)) 1405 log << TestLog::Message << "// Using type " << glu::getDataTypeName(boolApiType) << " to set boolean value " << apiVarValueStr(unifValue) << " for " << curName << TestLog::EndMessage; 1406 else if (glu::isDataTypeSampler(uniform.type)) 1407 log << TestLog::Message << "// Texture for the sampler uniform " << curName << " will be filled with color " << apiVarValueStr(getSamplerFillValue(uniform.finalValue)) << TestLog::EndMessage; 1408 } 1409 1410 DE_ASSERT(!valuesToAssign.empty()); 1411 1412 if (glu::isDataTypeFloatOrVec(valuesToAssign[0].type)) 1413 { 1414 if (assignByValue) 1415 { 1416 const float* const ptr = &valuesToAssign[0].val.floatV[0]; 1417 1418 switch (typeSize) 1419 { 1420 case 1: GLU_CHECK_CALL(glProgramUniform1f(programGL, location, ptr[0])); break; 1421 case 2: GLU_CHECK_CALL(glProgramUniform2f(programGL, location, ptr[0], ptr[1])); break; 1422 case 3: GLU_CHECK_CALL(glProgramUniform3f(programGL, location, ptr[0], ptr[1], ptr[2])); break; 1423 case 4: GLU_CHECK_CALL(glProgramUniform4f(programGL, location, ptr[0], ptr[1], ptr[2], ptr[3])); break; 1424 default: 1425 DE_ASSERT(false); 1426 } 1427 } 1428 else 1429 { 1430 vector<float> buffer(valuesToAssign.size() * typeSize); 1431 for (int i = 0; i < (int)buffer.size(); i++) 1432 buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize]; 1433 1434 DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0])); 1435 switch (typeSize) 1436 { 1437 case 1: GLU_CHECK_CALL(glProgramUniform1fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1438 case 2: GLU_CHECK_CALL(glProgramUniform2fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1439 case 3: GLU_CHECK_CALL(glProgramUniform3fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1440 case 4: GLU_CHECK_CALL(glProgramUniform4fv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1441 default: 1442 DE_ASSERT(false); 1443 } 1444 } 1445 } 1446 else if (glu::isDataTypeMatrix(valuesToAssign[0].type)) 1447 { 1448 DE_ASSERT(!assignByValue); 1449 1450 vector<float> buffer(valuesToAssign.size() * typeSize); 1451 for (int i = 0; i < (int)buffer.size(); i++) 1452 buffer[i] = valuesToAssign[i / typeSize].val.floatV[i % typeSize]; 1453 1454 DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(buffer[0])); 1455 switch (uniform.type) 1456 { 1457 case glu::TYPE_FLOAT_MAT2: GLU_CHECK_CALL(glProgramUniformMatrix2fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1458 case glu::TYPE_FLOAT_MAT3: GLU_CHECK_CALL(glProgramUniformMatrix3fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1459 case glu::TYPE_FLOAT_MAT4: GLU_CHECK_CALL(glProgramUniformMatrix4fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1460 case glu::TYPE_FLOAT_MAT2X3: GLU_CHECK_CALL(glProgramUniformMatrix2x3fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1461 case glu::TYPE_FLOAT_MAT2X4: GLU_CHECK_CALL(glProgramUniformMatrix2x4fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1462 case glu::TYPE_FLOAT_MAT3X2: GLU_CHECK_CALL(glProgramUniformMatrix3x2fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1463 case glu::TYPE_FLOAT_MAT3X4: GLU_CHECK_CALL(glProgramUniformMatrix3x4fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1464 case glu::TYPE_FLOAT_MAT4X2: GLU_CHECK_CALL(glProgramUniformMatrix4x2fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1465 case glu::TYPE_FLOAT_MAT4X3: GLU_CHECK_CALL(glProgramUniformMatrix4x3fv (programGL, location, (GLsizei)valuesToAssign.size(), transposeGL, &buffer[0])); break; 1466 default: 1467 DE_ASSERT(false); 1468 } 1469 } 1470 else if (glu::isDataTypeIntOrIVec(valuesToAssign[0].type)) 1471 { 1472 if (assignByValue) 1473 { 1474 const deInt32* const ptr = &valuesToAssign[0].val.intV[0]; 1475 1476 switch (typeSize) 1477 { 1478 case 1: GLU_CHECK_CALL(glProgramUniform1i(programGL, location, ptr[0])); break; 1479 case 2: GLU_CHECK_CALL(glProgramUniform2i(programGL, location, ptr[0], ptr[1])); break; 1480 case 3: GLU_CHECK_CALL(glProgramUniform3i(programGL, location, ptr[0], ptr[1], ptr[2])); break; 1481 case 4: GLU_CHECK_CALL(glProgramUniform4i(programGL, location, ptr[0], ptr[1], ptr[2], ptr[3])); break; 1482 default: 1483 DE_ASSERT(false); 1484 } 1485 } 1486 else 1487 { 1488 vector<deInt32> buffer(valuesToAssign.size() * typeSize); 1489 for (int i = 0; i < (int)buffer.size(); i++) 1490 buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize]; 1491 1492 DE_STATIC_ASSERT(sizeof(GLint) == sizeof(buffer[0])); 1493 switch (typeSize) 1494 { 1495 case 1: GLU_CHECK_CALL(glProgramUniform1iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1496 case 2: GLU_CHECK_CALL(glProgramUniform2iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1497 case 3: GLU_CHECK_CALL(glProgramUniform3iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1498 case 4: GLU_CHECK_CALL(glProgramUniform4iv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1499 default: 1500 DE_ASSERT(false); 1501 } 1502 } 1503 } 1504 else if (glu::isDataTypeUintOrUVec(valuesToAssign[0].type)) 1505 { 1506 if (assignByValue) 1507 { 1508 const deUint32* const ptr = &valuesToAssign[0].val.uintV[0]; 1509 1510 switch (typeSize) 1511 { 1512 case 1: GLU_CHECK_CALL(glProgramUniform1ui(programGL, location, ptr[0])); break; 1513 case 2: GLU_CHECK_CALL(glProgramUniform2ui(programGL, location, ptr[0], ptr[1])); break; 1514 case 3: GLU_CHECK_CALL(glProgramUniform3ui(programGL, location, ptr[0], ptr[1], ptr[2])); break; 1515 case 4: GLU_CHECK_CALL(glProgramUniform4ui(programGL, location, ptr[0], ptr[1], ptr[2], ptr[3])); break; 1516 default: 1517 DE_ASSERT(false); 1518 } 1519 } 1520 else 1521 { 1522 vector<deUint32> buffer(valuesToAssign.size() * typeSize); 1523 for (int i = 0; i < (int)buffer.size(); i++) 1524 buffer[i] = valuesToAssign[i / typeSize].val.intV[i % typeSize]; 1525 1526 DE_STATIC_ASSERT(sizeof(GLuint) == sizeof(buffer[0])); 1527 switch (typeSize) 1528 { 1529 case 1: GLU_CHECK_CALL(glProgramUniform1uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1530 case 2: GLU_CHECK_CALL(glProgramUniform2uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1531 case 3: GLU_CHECK_CALL(glProgramUniform3uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1532 case 4: GLU_CHECK_CALL(glProgramUniform4uiv(programGL, location, (GLsizei)valuesToAssign.size(), &buffer[0])); break; 1533 default: 1534 DE_ASSERT(false); 1535 } 1536 } 1537 } 1538 else if (glu::isDataTypeSampler(valuesToAssign[0].type)) 1539 { 1540 if (assignByValue) 1541 GLU_CHECK_CALL(glProgramUniform1i(programGL, location, uniform.finalValue.val.samplerV.unit)); 1542 else 1543 { 1544 const GLint unit = uniform.finalValue.val.samplerV.unit; 1545 GLU_CHECK_CALL(glProgramUniform1iv(programGL, location, (GLsizei)valuesToAssign.size(), &unit)); 1546 } 1547 } 1548 else 1549 DE_ASSERT(false); 1550 } 1551 } 1552 1553 bool UniformCase::compareUniformValues (const vector<VarValue>& values, const vector<BasicUniform>& basicUniforms) 1554 { 1555 TestLog& log = m_testCtx.getLog(); 1556 bool success = true; 1557 1558 for (int unifNdx = 0; unifNdx < (int)basicUniforms.size(); unifNdx++) 1559 { 1560 const BasicUniform& uniform = basicUniforms[unifNdx]; 1561 const VarValue& unifValue = values[unifNdx]; 1562 1563 log << TestLog::Message << "// Checking uniform " << uniform.name << TestLog::EndMessage; 1564 1565 if (unifValue.type == glu::TYPE_INVALID) // This happens when glGetUniformLocation() returned -1. 1566 continue; 1567 1568 if (!apiVarValueEquals(unifValue, uniform.finalValue)) 1569 { 1570 log << TestLog::Message << "// FAILURE: value obtained with glGetUniform*() for uniform " << uniform.name << " differs from value set with glProgramUniform*()" << TestLog::EndMessage; 1571 success = false; 1572 } 1573 } 1574 1575 return success; 1576 } 1577 1578 bool UniformCase::renderTest (const vector<BasicUniform>& basicUniforms, const ShaderProgram& program, Random& rnd) 1579 { 1580 TestLog& log = m_testCtx.getLog(); 1581 const tcu::RenderTarget& renderTarget = m_context.getRenderTarget(); 1582 const int viewportW = de::min<int>(renderTarget.getWidth(), MAX_RENDER_WIDTH); 1583 const int viewportH = de::min<int>(renderTarget.getHeight(), MAX_RENDER_HEIGHT); 1584 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportW); 1585 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportH); 1586 tcu::Surface renderedImg (viewportW, viewportH); 1587 1588 // Assert that no two samplers of different types have the same texture unit - this is an error in GL. 1589 for (int i = 0; i < (int)basicUniforms.size(); i++) 1590 { 1591 if (glu::isDataTypeSampler(basicUniforms[i].type)) 1592 { 1593 for (int j = 0; j < i; j++) 1594 { 1595 if (glu::isDataTypeSampler(basicUniforms[j].type) && basicUniforms[i].type != basicUniforms[j].type) 1596 DE_ASSERT(basicUniforms[i].finalValue.val.samplerV.unit != basicUniforms[j].finalValue.val.samplerV.unit); 1597 } 1598 } 1599 } 1600 1601 for (int i = 0; i < (int)basicUniforms.size(); i++) 1602 { 1603 if (glu::isDataTypeSampler(basicUniforms[i].type) && std::find(m_filledTextureUnits.begin(), m_filledTextureUnits.end(), basicUniforms[i].finalValue.val.samplerV.unit) == m_filledTextureUnits.end()) 1604 { 1605 log << TestLog::Message << "// Filling texture at unit " << apiVarValueStr(basicUniforms[i].finalValue) << " with color " << shaderVarValueStr(basicUniforms[i].finalValue) << TestLog::EndMessage; 1606 setupTexture(basicUniforms[i].finalValue); 1607 } 1608 } 1609 1610 GLU_CHECK_CALL(glViewport(viewportX, viewportY, viewportW, viewportH)); 1611 GLU_CHECK_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); 1612 GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT)); 1613 GLU_CHECK_CALL(glUseProgram(program.getProgram())); 1614 1615 { 1616 static const float position[] = 1617 { 1618 -1.0f, -1.0f, 0.0f, 1.0f, 1619 -1.0f, +1.0f, 0.0f, 1.0f, 1620 +1.0f, -1.0f, 0.0f, 1.0f, 1621 +1.0f, +1.0f, 0.0f, 1.0f 1622 }; 1623 static const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; 1624 const glu::VertexArrayBinding binding = glu::va::Float("a_position", 4, 4, 0, &position[0]); 1625 1626 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &binding, glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 1627 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess()); 1628 } 1629 1630 int numFailedPixels = 0; 1631 for (int y = 0; y < renderedImg.getHeight(); y++) 1632 { 1633 for (int x = 0; x < renderedImg.getWidth(); x++) 1634 { 1635 if (renderedImg.getPixel(x, y) != tcu::RGBA::green) 1636 numFailedPixels += 1; 1637 } 1638 } 1639 1640 if (numFailedPixels > 0) 1641 { 1642 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg); 1643 log << TestLog::Message << "FAILURE: image comparison failed, got " << numFailedPixels << " non-green pixels" << TestLog::EndMessage; 1644 return false; 1645 } 1646 else 1647 { 1648 log << TestLog::Message << "Success: got all-green pixels (all uniforms have correct values)" << TestLog::EndMessage; 1649 return true; 1650 } 1651 } 1652 1653 UniformCase::IterateResult UniformCase::iterate (void) 1654 { 1655 Random rnd (deStringHash(getName()) ^ (deUint32)m_context.getTestContext().getCommandLine().getBaseSeed()); 1656 TestLog& log = m_testCtx.getLog(); 1657 vector<BasicUniform> basicUniforms; 1658 vector<BasicUniformReportRef> basicUniformReportsRef; 1659 1660 { 1661 int samplerUnitCounter = 0; 1662 for (int i = 0; i < (int)m_uniformCollection->getNumUniforms(); i++) 1663 generateBasicUniforms(basicUniforms, basicUniformReportsRef, m_uniformCollection->getUniform(i).type, m_uniformCollection->getUniform(i).name.c_str(), true, samplerUnitCounter, rnd); 1664 } 1665 1666 const string vertexSource = generateVertexSource(basicUniforms); 1667 const string fragmentSource = generateFragmentSource(basicUniforms); 1668 const ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(vertexSource, fragmentSource)); 1669 1670 // A dummy program that we'll give to glUseProgram before we actually need 1671 // the real program above, to see if an implementation tries to use the 1672 // currently active program for something inappropriate (instead of the 1673 // program given as argument to, say, glProgramUniform*). 1674 const ShaderProgram dummyProgram (m_context.getRenderContext(), glu::makeVtxFragSources("#version 310 es\n" 1675 "void main (void) { gl_Position = vec4(1.0); }\n", 1676 1677 "#version 310 es\n" 1678 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 1679 "void main (void) { dEQP_FragColor = vec4(0.0, 0.0, 1.0, 1.0); }\n")); 1680 1681 log << program; 1682 1683 if (!program.isOk()) 1684 { 1685 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 1686 return STOP; 1687 } 1688 1689 if (!dummyProgram.isOk()) 1690 { 1691 log << dummyProgram; 1692 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compilation of dummy program failed"); 1693 return STOP; 1694 } 1695 1696 log << TestLog::Message << "// Note: calling glUseProgram with a dummy program (will only use the real program once it's needed for rendering)" << TestLog::EndMessage; 1697 glUseProgram(dummyProgram.getProgram()); 1698 1699 const bool success = test(basicUniforms, basicUniformReportsRef, program, rnd); 1700 m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1701 success ? "Passed" : "Failed"); 1702 1703 return STOP; 1704 } 1705 1706 class UniformAssignCase : public UniformCase 1707 { 1708 public: 1709 enum CheckMethod 1710 { 1711 CHECKMETHOD_GET_UNIFORM = 0, //!< Check values with glGetUniform*(). 1712 CHECKMETHOD_RENDER, //!< Check values by rendering with the value-checking shader. 1713 1714 CHECKMETHOD_LAST 1715 }; 1716 enum AssignMethod 1717 { 1718 ASSIGNMETHOD_POINTER = 0, 1719 ASSIGNMETHOD_VALUE, 1720 1721 ASSIGNMETHOD_LAST 1722 }; 1723 1724 UniformAssignCase (Context& context, 1725 const char* name, 1726 const char* description, 1727 CaseShaderType shaderType, 1728 const SharedPtr<const UniformCollection>& uniformCollection, 1729 CheckMethod checkMethod, 1730 AssignMethod assignMethod, 1731 deUint32 additionalFeatures = 0); 1732 1733 bool test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd); 1734 1735 static const char* getCheckMethodName (CheckMethod checkMethod); 1736 static const char* getCheckMethodDescription (CheckMethod checkMethod); 1737 static const char* getAssignMethodName (AssignMethod checkMethod); 1738 static const char* getAssignMethodDescription (AssignMethod checkMethod); 1739 1740 private: 1741 const CheckMethod m_checkMethod; 1742 }; 1743 1744 const char* UniformAssignCase::getCheckMethodName (const CheckMethod checkMethod) 1745 { 1746 switch (checkMethod) 1747 { 1748 case CHECKMETHOD_GET_UNIFORM: return "get_uniform"; 1749 case CHECKMETHOD_RENDER: return "render"; 1750 default: DE_ASSERT(false); return DE_NULL; 1751 } 1752 } 1753 1754 const char* UniformAssignCase::getCheckMethodDescription (const CheckMethod checkMethod) 1755 { 1756 switch (checkMethod) 1757 { 1758 case CHECKMETHOD_GET_UNIFORM: return "Verify values with glGetUniform*()"; 1759 case CHECKMETHOD_RENDER: return "Verify values by rendering"; 1760 default: DE_ASSERT(false); return DE_NULL; 1761 } 1762 } 1763 1764 const char* UniformAssignCase::getAssignMethodName (const AssignMethod assignMethod) 1765 { 1766 switch (assignMethod) 1767 { 1768 case ASSIGNMETHOD_POINTER: return "by_pointer"; 1769 case ASSIGNMETHOD_VALUE: return "by_value"; 1770 default: DE_ASSERT(false); return DE_NULL; 1771 } 1772 } 1773 1774 const char* UniformAssignCase::getAssignMethodDescription (const AssignMethod assignMethod) 1775 { 1776 switch (assignMethod) 1777 { 1778 case ASSIGNMETHOD_POINTER: return "Assign values by-pointer"; 1779 case ASSIGNMETHOD_VALUE: return "Assign values by-value"; 1780 default: DE_ASSERT(false); return DE_NULL; 1781 } 1782 } 1783 1784 UniformAssignCase::UniformAssignCase (Context& context, 1785 const char* const name, 1786 const char* const description, 1787 const CaseShaderType shaderType, 1788 const SharedPtr<const UniformCollection>& uniformCollection, 1789 const CheckMethod checkMethod, 1790 const AssignMethod assignMethod, 1791 const deUint32 additionalFeatures) 1792 : UniformCase (context, name, description, shaderType, uniformCollection, 1793 (assignMethod == ASSIGNMETHOD_VALUE ? FEATURE_UNIFORMFUNC_VALUE : 0) | additionalFeatures) 1794 , m_checkMethod (checkMethod) 1795 { 1796 DE_ASSERT(assignMethod != ASSIGNMETHOD_LAST); 1797 } 1798 1799 bool UniformAssignCase::test (const vector<BasicUniform>& basicUniforms, const vector<BasicUniformReportRef>& basicUniformReportsRef, const ShaderProgram& program, Random& rnd) 1800 { 1801 DE_UNREF(basicUniformReportsRef); 1802 1803 const deUint32 programGL = program.getProgram(); 1804 TestLog& log = m_testCtx.getLog(); 1805 1806 { 1807 const ScopedLogSection section(log, "UniformAssign", "Uniform value assignments"); 1808 assignUniforms(basicUniforms, programGL, rnd); 1809 } 1810 1811 if (m_checkMethod == CHECKMETHOD_GET_UNIFORM) 1812 { 1813 vector<VarValue> values; 1814 1815 { 1816 const ScopedLogSection section(log, "GetUniforms", "Uniform value query"); 1817 const bool success = getUniforms(values, basicUniforms, program.getProgram()); 1818 1819 if (!success) 1820 return false; 1821 } 1822 1823 { 1824 const ScopedLogSection section(log, "ValueCheck", "Verify that the reported values match the assigned values"); 1825 const bool success = compareUniformValues(values, basicUniforms); 1826 1827 if (!success) 1828 return false; 1829 } 1830 } 1831 else 1832 { 1833 DE_ASSERT(m_checkMethod == CHECKMETHOD_RENDER); 1834 1835 const ScopedLogSection section(log, "RenderTest", "Render test"); 1836 const bool success = renderTest(basicUniforms, program, rnd); 1837 1838 if (!success) 1839 return false; 1840 } 1841 1842 return true; 1843 } 1844 1845 ProgramUniformTests::ProgramUniformTests (Context& context) 1846 : TestCaseGroup(context, "program_uniform", "glProgramUniform*() tests") 1847 { 1848 } 1849 1850 ProgramUniformTests::~ProgramUniformTests (void) 1851 { 1852 } 1853 1854 namespace 1855 { 1856 1857 // \note Although this is only used in ProgramUniformTests::init, it needs to be defined here as it's used as a template argument. 1858 struct UniformCollectionCase 1859 { 1860 string namePrefix; 1861 SharedPtr<const UniformCollection> uniformCollection; 1862 1863 UniformCollectionCase (const char* const name, const UniformCollection* uniformCollection_) 1864 : namePrefix (name ? name + string("_") : "") 1865 , uniformCollection (uniformCollection_) 1866 { 1867 } 1868 }; 1869 1870 } // anonymous 1871 1872 void ProgramUniformTests::init (void) 1873 { 1874 // Generate sets of UniformCollections that are used by several cases. 1875 1876 enum 1877 { 1878 UNIFORMCOLLECTIONS_BASIC = 0, 1879 UNIFORMCOLLECTIONS_BASIC_ARRAY, 1880 UNIFORMCOLLECTIONS_BASIC_STRUCT, 1881 UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY, 1882 UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, 1883 UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS, 1884 UNIFORMCOLLECTIONS_MULTIPLE_BASIC, 1885 UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY, 1886 UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS, 1887 1888 UNIFORMCOLLECTIONS_LAST 1889 }; 1890 1891 struct UniformCollectionGroup 1892 { 1893 string name; 1894 vector<UniformCollectionCase> cases; 1895 } defaultUniformCollections[UNIFORMCOLLECTIONS_LAST]; 1896 1897 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].name = "basic"; 1898 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].name = "basic_array"; 1899 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].name = "basic_struct"; 1900 defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].name = "struct_in_array"; 1901 defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].name = "array_in_struct"; 1902 defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].name = "nested_structs_arrays"; 1903 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].name = "multiple_basic"; 1904 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].name = "multiple_basic_array"; 1905 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].name = "multiple_nested_structs_arrays"; 1906 1907 for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(s_testDataTypes); dataTypeNdx++) 1908 { 1909 const glu::DataType dataType = s_testDataTypes[dataTypeNdx]; 1910 const char* const typeName = glu::getDataTypeName(dataType); 1911 1912 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basic(dataType))); 1913 1914 if (glu::isDataTypeScalar(dataType) || 1915 (glu::isDataTypeVector(dataType) && glu::getDataTypeScalarSize(dataType) == 4) || 1916 dataType == glu::TYPE_FLOAT_MAT4 || 1917 dataType == glu::TYPE_SAMPLER_2D) 1918 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_ARRAY].cases.push_back(UniformCollectionCase(typeName, UniformCollection::basicArray(dataType))); 1919 1920 if (glu::isDataTypeScalar(dataType) || 1921 dataType == glu::TYPE_FLOAT_MAT4 || 1922 dataType == glu::TYPE_SAMPLER_2D) 1923 { 1924 const glu::DataType secondDataType = glu::isDataTypeScalar(dataType) ? glu::getDataTypeVector(dataType, 4) 1925 : dataType == glu::TYPE_FLOAT_MAT4 ? glu::TYPE_FLOAT_MAT2 1926 : dataType == glu::TYPE_SAMPLER_2D ? glu::TYPE_SAMPLER_CUBE 1927 : glu::TYPE_LAST; 1928 DE_ASSERT(secondDataType != glu::TYPE_LAST); 1929 const char* const secondTypeName = glu::getDataTypeName(secondDataType); 1930 const string name = string("") + typeName + "_" + secondTypeName; 1931 1932 defaultUniformCollections[UNIFORMCOLLECTIONS_BASIC_STRUCT].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, false))); 1933 defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::basicStruct(dataType, secondDataType, true))); 1934 defaultUniformCollections[UNIFORMCOLLECTIONS_STRUCT_IN_ARRAY].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::structInArray(dataType, secondDataType, false))); 1935 defaultUniformCollections[UNIFORMCOLLECTIONS_NESTED_STRUCTS_ARRAYS].cases.push_back (UniformCollectionCase(name.c_str(), UniformCollection::nestedArraysStructs(dataType, secondDataType))); 1936 } 1937 } 1938 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleBasic())); 1939 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleBasicArray())); 1940 defaultUniformCollections[UNIFORMCOLLECTIONS_MULTIPLE_NESTED_STRUCTS_ARRAYS].cases.push_back (UniformCollectionCase(DE_NULL, UniformCollection::multipleNestedArraysStructs())); 1941 1942 // Basic by-pointer or by-value uniform assignment cases. 1943 1944 for (int assignMethodI = 0; assignMethodI < (int)UniformAssignCase::ASSIGNMETHOD_LAST; assignMethodI++) 1945 { 1946 const UniformAssignCase::AssignMethod assignMethod = (UniformAssignCase::AssignMethod)assignMethodI; 1947 TestCaseGroup* const assignMethodGroup = new TestCaseGroup(m_context, UniformAssignCase::getAssignMethodName(assignMethod), UniformAssignCase::getAssignMethodDescription(assignMethod)); 1948 addChild(assignMethodGroup); 1949 1950 for (int checkMethodI = 0; checkMethodI < (int)UniformAssignCase::CHECKMETHOD_LAST; checkMethodI++) 1951 { 1952 const UniformAssignCase::CheckMethod checkMethod = (UniformAssignCase::CheckMethod)checkMethodI; 1953 TestCaseGroup* const checkMethodGroup = new TestCaseGroup(m_context, UniformAssignCase::getCheckMethodName(checkMethod), UniformAssignCase::getCheckMethodDescription(checkMethod)); 1954 assignMethodGroup->addChild(checkMethodGroup); 1955 1956 for (int collectionGroupNdx = 0; collectionGroupNdx < (int)UNIFORMCOLLECTIONS_LAST; collectionGroupNdx++) 1957 { 1958 const int numArrayFirstElemNameCases = checkMethod == UniformAssignCase::CHECKMETHOD_GET_UNIFORM && collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY ? 2 : 1; 1959 1960 for (int referToFirstArrayElemWithoutIndexI = 0; referToFirstArrayElemWithoutIndexI < numArrayFirstElemNameCases; referToFirstArrayElemWithoutIndexI++) 1961 { 1962 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[collectionGroupNdx]; 1963 const string collectionGroupName = collectionGroup.name + (referToFirstArrayElemWithoutIndexI == 0 ? "" : "_first_elem_without_brackets"); 1964 TestCaseGroup* collectionTestGroup = DE_NULL; 1965 1966 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 1967 { 1968 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 1969 const string collName = collectionCase.namePrefix; 1970 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 1971 const bool containsBooleans = uniformCollection->containsMatchingBasicType(glu::isDataTypeBoolOrBVec); 1972 const bool varyBoolApiType = checkMethod == UniformAssignCase::CHECKMETHOD_GET_UNIFORM && containsBooleans && 1973 (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY); 1974 const int numBoolVariations = varyBoolApiType ? 3 : 1; 1975 const bool containsMatrices = uniformCollection->containsMatchingBasicType(glu::isDataTypeMatrix); 1976 const bool varyMatrixMode = containsMatrices && 1977 (collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC || collectionGroupNdx == UNIFORMCOLLECTIONS_BASIC_ARRAY); 1978 const int numMatVariations = varyMatrixMode ? 2 : 1; 1979 1980 if (containsMatrices && assignMethod != UniformAssignCase::ASSIGNMETHOD_POINTER) 1981 continue; 1982 1983 for (int booleanTypeI = 0; booleanTypeI < numBoolVariations; booleanTypeI++) 1984 { 1985 const deUint32 booleanTypeFeat = booleanTypeI == 1 ? UniformCase::FEATURE_BOOLEANAPITYPE_INT 1986 : booleanTypeI == 2 ? UniformCase::FEATURE_BOOLEANAPITYPE_UINT 1987 : 0; 1988 const char* const booleanTypeName = booleanTypeI == 1 ? "int" 1989 : booleanTypeI == 2 ? "uint" 1990 : "float"; 1991 const string nameWithBoolType = varyBoolApiType ? collName + "api_" + booleanTypeName + "_" : collName; 1992 1993 for (int matrixTypeI = 0; matrixTypeI < numMatVariations; matrixTypeI++) 1994 { 1995 const string nameWithMatrixType = nameWithBoolType + (matrixTypeI == 1 ? "row_major_" : ""); 1996 1997 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 1998 { 1999 const string name = nameWithMatrixType + getCaseShaderTypeName((CaseShaderType)shaderType); 2000 const deUint32 arrayFirstElemNameNoIndexFeat = referToFirstArrayElemWithoutIndexI == 0 ? 0 : UniformCase::FEATURE_ARRAY_FIRST_ELEM_NAME_NO_INDEX; 2001 2002 // skip empty groups by creating groups on demand 2003 if (!collectionTestGroup) 2004 { 2005 collectionTestGroup = new TestCaseGroup(m_context, collectionGroupName.c_str(), ""); 2006 checkMethodGroup->addChild(collectionTestGroup); 2007 } 2008 2009 collectionTestGroup->addChild(new UniformAssignCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2010 checkMethod, assignMethod, 2011 booleanTypeFeat | arrayFirstElemNameNoIndexFeat | (matrixTypeI == 1 ? UniformCase::FEATURE_MATRIXMODE_ROWMAJOR : 0))); 2012 } 2013 } 2014 } 2015 } 2016 } 2017 } 2018 } 2019 } 2020 2021 // Cases that assign multiple basic-array elements with one glProgramUniform*v() (i.e. the count parameter is bigger than 1). 2022 2023 { 2024 static const struct 2025 { 2026 UniformCase::Feature arrayAssignMode; 2027 const char* name; 2028 const char* description; 2029 } arrayAssignGroups[] = 2030 { 2031 { UniformCase::FEATURE_ARRAYASSIGN_FULL, "basic_array_assign_full", "Assign entire basic-type arrays per glProgramUniform*v() call" }, 2032 { UniformCase::FEATURE_ARRAYASSIGN_BLOCKS_OF_TWO, "basic_array_assign_partial", "Assign two elements of a basic-type array per glProgramUniform*v() call" } 2033 }; 2034 2035 for (int arrayAssignGroupNdx = 0; arrayAssignGroupNdx < DE_LENGTH_OF_ARRAY(arrayAssignGroups); arrayAssignGroupNdx++) 2036 { 2037 UniformCase::Feature arrayAssignMode = arrayAssignGroups[arrayAssignGroupNdx].arrayAssignMode; 2038 const char* const groupName = arrayAssignGroups[arrayAssignGroupNdx].name; 2039 const char* const groupDesc = arrayAssignGroups[arrayAssignGroupNdx].description; 2040 2041 TestCaseGroup* const curArrayAssignGroup = new TestCaseGroup(m_context, groupName, groupDesc); 2042 addChild(curArrayAssignGroup); 2043 2044 static const int basicArrayCollectionGroups[] = { UNIFORMCOLLECTIONS_BASIC_ARRAY, UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT, UNIFORMCOLLECTIONS_MULTIPLE_BASIC_ARRAY }; 2045 2046 for (int collectionGroupNdx = 0; collectionGroupNdx < DE_LENGTH_OF_ARRAY(basicArrayCollectionGroups); collectionGroupNdx++) 2047 { 2048 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[basicArrayCollectionGroups[collectionGroupNdx]]; 2049 TestCaseGroup* const collectionTestGroup = new TestCaseGroup(m_context, collectionGroup.name.c_str(), ""); 2050 curArrayAssignGroup->addChild(collectionTestGroup); 2051 2052 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2053 { 2054 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2055 const string collName = collectionCase.namePrefix; 2056 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2057 2058 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2059 { 2060 const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType); 2061 collectionTestGroup->addChild(new UniformAssignCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2062 UniformAssignCase::CHECKMETHOD_GET_UNIFORM, UniformAssignCase::ASSIGNMETHOD_POINTER, 2063 arrayAssignMode)); 2064 } 2065 } 2066 } 2067 } 2068 } 2069 2070 // Cases with unused uniforms. 2071 2072 { 2073 TestCaseGroup* const unusedUniformsGroup = new TestCaseGroup(m_context, "unused_uniforms", "Test with unused uniforms"); 2074 addChild(unusedUniformsGroup); 2075 2076 const UniformCollectionGroup& collectionGroup = defaultUniformCollections[UNIFORMCOLLECTIONS_ARRAY_IN_STRUCT]; 2077 2078 for (int collectionNdx = 0; collectionNdx < (int)collectionGroup.cases.size(); collectionNdx++) 2079 { 2080 const UniformCollectionCase& collectionCase = collectionGroup.cases[collectionNdx]; 2081 const string collName = collectionCase.namePrefix; 2082 const SharedPtr<const UniformCollection>& uniformCollection = collectionCase.uniformCollection; 2083 2084 for (int shaderType = 0; shaderType < (int)CASESHADERTYPE_LAST; shaderType++) 2085 { 2086 const string name = collName + getCaseShaderTypeName((CaseShaderType)shaderType); 2087 unusedUniformsGroup->addChild(new UniformAssignCase(m_context, name.c_str(), "", (CaseShaderType)shaderType, uniformCollection, 2088 UniformAssignCase::CHECKMETHOD_GET_UNIFORM, UniformAssignCase::ASSIGNMETHOD_POINTER, 2089 UniformCase::FEATURE_ARRAYUSAGE_ONLY_MIDDLE_INDEX | UniformCase::FEATURE_UNIFORMUSAGE_EVERY_OTHER)); 2090 } 2091 } 2092 } 2093 } 2094 2095 } // Functional 2096 } // gles31 2097 } // deqp 2098