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 Opaque type (sampler, buffer, atomic counter, ...) indexing tests. 22 * 23 * \todo [2014-03-05 pyry] Extend with following: 24 * + sampler: different filtering modes, multiple sizes, incomplete textures 25 * + SSBO: write, atomic op, unsized array .length() 26 *//*--------------------------------------------------------------------*/ 27 28 #include "es31fOpaqueTypeIndexingTests.hpp" 29 #include "tcuTexture.hpp" 30 #include "tcuTestLog.hpp" 31 #include "tcuFormatUtil.hpp" 32 #include "tcuVectorUtil.hpp" 33 #include "gluShaderUtil.hpp" 34 #include "gluShaderProgram.hpp" 35 #include "gluObjectWrapper.hpp" 36 #include "gluTextureUtil.hpp" 37 #include "gluRenderContext.hpp" 38 #include "gluProgramInterfaceQuery.hpp" 39 #include "gluContextInfo.hpp" 40 #include "glsShaderExecUtil.hpp" 41 #include "glwFunctions.hpp" 42 #include "glwEnums.hpp" 43 #include "deUniquePtr.hpp" 44 #include "deStringUtil.hpp" 45 #include "deRandom.hpp" 46 47 #include <sstream> 48 49 namespace deqp 50 { 51 namespace gles31 52 { 53 namespace Functional 54 { 55 56 namespace 57 { 58 59 using namespace gls::ShaderExecUtil; 60 using namespace glu; 61 using std::string; 62 using std::vector; 63 using tcu::TextureFormat; 64 using tcu::TestLog; 65 66 typedef de::UniquePtr<ShaderExecutor> ShaderExecutorPtr; 67 68 enum IndexExprType 69 { 70 INDEX_EXPR_TYPE_CONST_LITERAL = 0, 71 INDEX_EXPR_TYPE_CONST_EXPRESSION, 72 INDEX_EXPR_TYPE_UNIFORM, 73 INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, 74 75 INDEX_EXPR_TYPE_LAST 76 }; 77 78 enum TextureType 79 { 80 TEXTURE_TYPE_1D = 0, 81 TEXTURE_TYPE_2D, 82 TEXTURE_TYPE_CUBE, 83 TEXTURE_TYPE_2D_ARRAY, 84 TEXTURE_TYPE_3D, 85 86 TEXTURE_TYPE_LAST 87 }; 88 89 static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars) 90 { 91 for (int varNdx = 0; varNdx < numVars; varNdx++) 92 str << "uniform highp int " << varPrefix << varNdx << ";\n"; 93 } 94 95 static void uploadUniformIndices (const glw::Functions& gl, deUint32 program, const char* varPrefix, int numIndices, const int* indices) 96 { 97 for (int varNdx = 0; varNdx < numIndices; varNdx++) 98 { 99 const string varName = varPrefix + de::toString(varNdx); 100 const int loc = gl.getUniformLocation(program, varName.c_str()); 101 TCU_CHECK_MSG(loc >= 0, ("No location assigned for uniform '" + varName + "'").c_str()); 102 103 gl.uniform1i(loc, indices[varNdx]); 104 } 105 } 106 107 template<typename T> 108 static T maxElement (const std::vector<T>& elements) 109 { 110 T maxElem = elements[0]; 111 112 for (size_t ndx = 1; ndx < elements.size(); ndx++) 113 maxElem = de::max(maxElem, elements[ndx]); 114 115 return maxElem; 116 } 117 118 static TextureType getTextureType (glu::DataType samplerType) 119 { 120 switch (samplerType) 121 { 122 case glu::TYPE_SAMPLER_1D: 123 case glu::TYPE_INT_SAMPLER_1D: 124 case glu::TYPE_UINT_SAMPLER_1D: 125 case glu::TYPE_SAMPLER_1D_SHADOW: 126 return TEXTURE_TYPE_1D; 127 128 case glu::TYPE_SAMPLER_2D: 129 case glu::TYPE_INT_SAMPLER_2D: 130 case glu::TYPE_UINT_SAMPLER_2D: 131 case glu::TYPE_SAMPLER_2D_SHADOW: 132 return TEXTURE_TYPE_2D; 133 134 case glu::TYPE_SAMPLER_CUBE: 135 case glu::TYPE_INT_SAMPLER_CUBE: 136 case glu::TYPE_UINT_SAMPLER_CUBE: 137 case glu::TYPE_SAMPLER_CUBE_SHADOW: 138 return TEXTURE_TYPE_CUBE; 139 140 case glu::TYPE_SAMPLER_2D_ARRAY: 141 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 142 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 143 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 144 return TEXTURE_TYPE_2D_ARRAY; 145 146 case glu::TYPE_SAMPLER_3D: 147 case glu::TYPE_INT_SAMPLER_3D: 148 case glu::TYPE_UINT_SAMPLER_3D: 149 return TEXTURE_TYPE_3D; 150 151 default: 152 throw tcu::InternalError("Invalid sampler type"); 153 } 154 } 155 156 static bool isShadowSampler (glu::DataType samplerType) 157 { 158 return samplerType == glu::TYPE_SAMPLER_1D_SHADOW || 159 samplerType == glu::TYPE_SAMPLER_2D_SHADOW || 160 samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW || 161 samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW; 162 } 163 164 static glu::DataType getSamplerOutputType (glu::DataType samplerType) 165 { 166 switch (samplerType) 167 { 168 case glu::TYPE_SAMPLER_1D: 169 case glu::TYPE_SAMPLER_2D: 170 case glu::TYPE_SAMPLER_CUBE: 171 case glu::TYPE_SAMPLER_2D_ARRAY: 172 case glu::TYPE_SAMPLER_3D: 173 return glu::TYPE_FLOAT_VEC4; 174 175 case glu::TYPE_SAMPLER_1D_SHADOW: 176 case glu::TYPE_SAMPLER_2D_SHADOW: 177 case glu::TYPE_SAMPLER_CUBE_SHADOW: 178 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 179 return glu::TYPE_FLOAT; 180 181 case glu::TYPE_INT_SAMPLER_1D: 182 case glu::TYPE_INT_SAMPLER_2D: 183 case glu::TYPE_INT_SAMPLER_CUBE: 184 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 185 case glu::TYPE_INT_SAMPLER_3D: 186 return glu::TYPE_INT_VEC4; 187 188 case glu::TYPE_UINT_SAMPLER_1D: 189 case glu::TYPE_UINT_SAMPLER_2D: 190 case glu::TYPE_UINT_SAMPLER_CUBE: 191 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 192 case glu::TYPE_UINT_SAMPLER_3D: 193 return glu::TYPE_UINT_VEC4; 194 195 default: 196 throw tcu::InternalError("Invalid sampler type"); 197 } 198 } 199 200 static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType) 201 { 202 const glu::DataType outType = getSamplerOutputType(samplerType); 203 const glu::DataType outScalarType = glu::getDataTypeScalarType(outType); 204 205 switch (outScalarType) 206 { 207 case glu::TYPE_FLOAT: 208 if (isShadowSampler(samplerType)) 209 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); 210 else 211 return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); 212 213 case glu::TYPE_INT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8); 214 case glu::TYPE_UINT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8); 215 216 default: 217 throw tcu::InternalError("Invalid sampler type"); 218 } 219 } 220 221 static glu::DataType getSamplerCoordType (glu::DataType samplerType) 222 { 223 const TextureType texType = getTextureType(samplerType); 224 int numCoords = 0; 225 226 switch (texType) 227 { 228 case TEXTURE_TYPE_1D: numCoords = 1; break; 229 case TEXTURE_TYPE_2D: numCoords = 2; break; 230 case TEXTURE_TYPE_2D_ARRAY: numCoords = 3; break; 231 case TEXTURE_TYPE_CUBE: numCoords = 3; break; 232 case TEXTURE_TYPE_3D: numCoords = 3; break; 233 default: 234 DE_ASSERT(false); 235 } 236 237 if (isShadowSampler(samplerType)) 238 numCoords += 1; 239 240 DE_ASSERT(de::inRange(numCoords, 1, 4)); 241 242 return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords); 243 } 244 245 static deUint32 getGLTextureTarget (TextureType texType) 246 { 247 switch (texType) 248 { 249 case TEXTURE_TYPE_1D: return GL_TEXTURE_1D; 250 case TEXTURE_TYPE_2D: return GL_TEXTURE_2D; 251 case TEXTURE_TYPE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY; 252 case TEXTURE_TYPE_CUBE: return GL_TEXTURE_CUBE_MAP; 253 case TEXTURE_TYPE_3D: return GL_TEXTURE_3D; 254 default: 255 DE_ASSERT(false); 256 return 0; 257 } 258 } 259 260 static void setupTexture (const glw::Functions& gl, 261 deUint32 texture, 262 glu::DataType samplerType, 263 tcu::TextureFormat texFormat, 264 const void* color) 265 { 266 const TextureType texType = getTextureType(samplerType); 267 const deUint32 texTarget = getGLTextureTarget(texType); 268 const deUint32 intFormat = glu::getInternalFormat(texFormat); 269 const glu::TransferFormat transferFmt = glu::getTransferFormat(texFormat); 270 271 // \todo [2014-03-04 pyry] Use larger than 1x1 textures? 272 273 gl.bindTexture(texTarget, texture); 274 275 switch (texType) 276 { 277 case TEXTURE_TYPE_1D: 278 gl.texStorage1D(texTarget, 1, intFormat, 1); 279 gl.texSubImage1D(texTarget, 0, 0, 1, transferFmt.format, transferFmt.dataType, color); 280 break; 281 282 case TEXTURE_TYPE_2D: 283 gl.texStorage2D(texTarget, 1, intFormat, 1, 1); 284 gl.texSubImage2D(texTarget, 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color); 285 break; 286 287 case TEXTURE_TYPE_2D_ARRAY: 288 case TEXTURE_TYPE_3D: 289 gl.texStorage3D(texTarget, 1, intFormat, 1, 1, 1); 290 gl.texSubImage3D(texTarget, 0, 0, 0, 0, 1, 1, 1, transferFmt.format, transferFmt.dataType, color); 291 break; 292 293 case TEXTURE_TYPE_CUBE: 294 gl.texStorage2D(texTarget, 1, intFormat, 1, 1); 295 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 296 gl.texSubImage2D(glu::getGLCubeFace((tcu::CubeFace)face), 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color); 297 break; 298 299 default: 300 DE_ASSERT(false); 301 } 302 303 gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 304 gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 305 306 if (isShadowSampler(samplerType)) 307 gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 308 309 GLU_EXPECT_NO_ERROR(gl.getError(), "Texture setup failed"); 310 } 311 312 class SamplerIndexingCase : public TestCase 313 { 314 public: 315 SamplerIndexingCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType); 316 ~SamplerIndexingCase (void); 317 318 void init (void); 319 IterateResult iterate (void); 320 321 private: 322 SamplerIndexingCase (const SamplerIndexingCase&); 323 SamplerIndexingCase& operator= (const SamplerIndexingCase&); 324 325 void getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const; 326 327 const glu::ShaderType m_shaderType; 328 const glu::DataType m_samplerType; 329 const IndexExprType m_indexExprType; 330 }; 331 332 SamplerIndexingCase::SamplerIndexingCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType) 333 : TestCase (context, name, description) 334 , m_shaderType (shaderType) 335 , m_samplerType (samplerType) 336 , m_indexExprType (indexExprType) 337 { 338 } 339 340 SamplerIndexingCase::~SamplerIndexingCase (void) 341 { 342 } 343 344 void SamplerIndexingCase::init (void) 345 { 346 const char* extName = "GL_EXT_gpu_shader5"; 347 348 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && 349 !m_context.getContextInfo().isExtensionSupported(extName)) 350 throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of sampler arrays"); 351 } 352 353 void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const 354 { 355 const char* samplersName = "sampler"; 356 const char* coordsName = "coords"; 357 const char* indicesPrefix = "index"; 358 const char* resultPrefix = "result"; 359 const DataType coordType = getSamplerCoordType(m_samplerType); 360 const DataType outType = getSamplerOutputType(m_samplerType); 361 std::ostringstream global, code; 362 363 spec->inputs.push_back(Symbol(coordsName, VarType(coordType, PRECISION_HIGHP))); 364 365 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL) 366 global << "#extension GL_EXT_gpu_shader5 : require\n"; 367 368 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 369 global << "const highp int indexBase = 1;\n"; 370 371 global << 372 "uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << numSamplers << "];\n"; 373 374 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 375 { 376 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 377 { 378 const string varName = indicesPrefix + de::toString(lookupNdx); 379 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP))); 380 } 381 } 382 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 383 declareUniformIndexVars(global, indicesPrefix, numLookups); 384 385 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 386 { 387 const string varName = resultPrefix + de::toString(lookupNdx); 388 spec->outputs.push_back(Symbol(varName, VarType(outType, PRECISION_HIGHP))); 389 } 390 391 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 392 { 393 code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "["; 394 395 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 396 code << lookupIndices[lookupNdx]; 397 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 398 code << "indexBase + " << (lookupIndices[lookupNdx]-1); 399 else 400 code << indicesPrefix << lookupNdx; 401 402 code << "], " << coordsName << ");\n"; 403 } 404 405 spec->version = GLSL_VERSION_310_ES; 406 spec->globalDeclarations = global.str(); 407 spec->source = code.str(); 408 } 409 410 static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd) 411 { 412 DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1); 413 414 if (access.getFormat().order == TextureFormat::D) 415 { 416 // \note Texture uses odd values, lookup even values to avoid precision issues. 417 const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f }; 418 419 for (int ndx = 0; ndx < access.getWidth(); ndx++) 420 access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0); 421 } 422 else 423 { 424 TCU_CHECK_INTERNAL(access.getFormat().order == TextureFormat::RGBA && access.getFormat().getPixelSize() == 4); 425 426 for (int ndx = 0; ndx < access.getWidth(); ndx++) 427 *((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32(); 428 } 429 } 430 431 SamplerIndexingCase::IterateResult SamplerIndexingCase::iterate (void) 432 { 433 const int numInvocations = 64; 434 const int numSamplers = 8; 435 const int numLookups = 4; 436 const DataType coordType = getSamplerCoordType(m_samplerType); 437 const DataType outputType = getSamplerOutputType(m_samplerType); 438 const TextureFormat texFormat = getSamplerTextureFormat(m_samplerType); 439 const int outLookupStride = numInvocations*getDataTypeScalarSize(outputType); 440 vector<int> lookupIndices (numLookups); 441 vector<float> coords; 442 vector<deUint32> outData; 443 vector<deUint8> texData (numSamplers * texFormat.getPixelSize()); 444 const tcu::PixelBufferAccess refTexAccess (texFormat, numSamplers, 1, 1, &texData[0]); 445 ShaderSpec shaderSpec; 446 de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 447 448 for (int ndx = 0; ndx < numLookups; ndx++) 449 lookupIndices[ndx] = rnd.getInt(0, numSamplers-1); 450 451 getShaderSpec(&shaderSpec, numSamplers, numLookups, &lookupIndices[0]); 452 453 coords.resize(numInvocations * getDataTypeScalarSize(coordType)); 454 455 if (isShadowSampler(m_samplerType)) 456 { 457 // Use different comparison value per invocation. 458 // \note Texture uses odd values, comparison even values. 459 const int numCoordComps = getDataTypeScalarSize(coordType); 460 const float cmpValues[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }; 461 462 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 463 coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues)); 464 } 465 466 fillTextureData(refTexAccess, rnd); 467 468 outData.resize(numLookups*outLookupStride); 469 470 { 471 const RenderContext& renderCtx = m_context.getRenderContext(); 472 const glw::Functions& gl = renderCtx.getFunctions(); 473 ShaderExecutorPtr executor (createExecutor(m_context.getRenderContext(), m_shaderType, shaderSpec)); 474 TextureVector textures (renderCtx, numSamplers); 475 vector<void*> inputs; 476 vector<void*> outputs; 477 vector<int> expandedIndices; 478 const int maxIndex = maxElement(lookupIndices); 479 480 m_testCtx.getLog() << *executor; 481 482 if (!executor->isOk()) 483 TCU_FAIL("Compile failed"); 484 485 executor->useProgram(); 486 487 // \todo [2014-03-05 pyry] Do we want to randomize tex unit assignments? 488 for (int samplerNdx = 0; samplerNdx < numSamplers; samplerNdx++) 489 { 490 const string samplerName = string("sampler[") + de::toString(samplerNdx) + "]"; 491 const int samplerLoc = gl.getUniformLocation(executor->getProgram(), samplerName.c_str()); 492 493 if (samplerNdx > maxIndex && samplerLoc < 0) 494 continue; // Unused uniform eliminated by compiler 495 496 TCU_CHECK_MSG(samplerLoc >= 0, (string("No location for uniform '") + samplerName + "' found").c_str()); 497 498 gl.activeTexture(GL_TEXTURE0 + samplerNdx); 499 setupTexture(gl, textures[samplerNdx], m_samplerType, texFormat, &texData[samplerNdx*texFormat.getPixelSize()]); 500 501 gl.uniform1i(samplerLoc, samplerNdx); 502 } 503 504 inputs.push_back(&coords[0]); 505 506 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 507 { 508 expandedIndices.resize(numInvocations * lookupIndices.size()); 509 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 510 { 511 for (int invNdx = 0; invNdx < numInvocations; invNdx++) 512 expandedIndices[lookupNdx*numInvocations + invNdx] = lookupIndices[lookupNdx]; 513 } 514 515 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 516 inputs.push_back(&expandedIndices[lookupNdx*numInvocations]); 517 } 518 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 519 uploadUniformIndices(gl, executor->getProgram(), "index", numLookups, &lookupIndices[0]); 520 521 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 522 outputs.push_back(&outData[outLookupStride*lookupNdx]); 523 524 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 525 526 executor->execute(numInvocations, &inputs[0], &outputs[0]); 527 } 528 529 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 530 531 if (isShadowSampler(m_samplerType)) 532 { 533 const tcu::Sampler refSampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 534 tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0.0f, false /* non-normalized */, 535 tcu::Sampler::COMPAREMODE_LESS); 536 const int numCoordComps = getDataTypeScalarSize(coordType); 537 538 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1); 539 540 // Each invocation may have different results. 541 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 542 { 543 const float coord = coords[invocationNdx*numCoordComps + (numCoordComps-1)]; 544 545 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 546 { 547 const int texNdx = lookupIndices[lookupNdx]; 548 const float result = *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]); 549 const float reference = refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0)); 550 551 if (de::abs(result-reference) > 0.005f) 552 { 553 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected " 554 << reference << ", got " << result 555 << TestLog::EndMessage; 556 557 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 558 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result"); 559 } 560 } 561 } 562 } 563 else 564 { 565 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4); 566 567 // Validate results from first invocation 568 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 569 { 570 const int texNdx = lookupIndices[lookupNdx]; 571 const deUint8* resPtr = (const deUint8*)&outData[lookupNdx*outLookupStride]; 572 bool isOk; 573 574 if (outputType == TYPE_FLOAT_VEC4) 575 { 576 const float threshold = 1.0f / 256.0f; 577 const tcu::Vec4 reference = refTexAccess.getPixel(texNdx, 0); 578 const float* floatPtr = (const float*)resPtr; 579 const tcu::Vec4 result (floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]); 580 581 isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold))); 582 583 if (!isOk) 584 { 585 m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected " 586 << reference << ", got " << result 587 << TestLog::EndMessage; 588 } 589 } 590 else 591 { 592 const tcu::UVec4 reference = refTexAccess.getPixelUint(texNdx, 0); 593 const deUint32* uintPtr = (const deUint32*)resPtr; 594 const tcu::UVec4 result (uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]); 595 596 isOk = boolAll(equal(reference, result)); 597 598 if (!isOk) 599 { 600 m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected " 601 << reference << ", got " << result 602 << TestLog::EndMessage; 603 } 604 } 605 606 if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 607 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result"); 608 } 609 610 // Check results of other invocations against first one 611 for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++) 612 { 613 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 614 { 615 const deUint32* refPtr = &outData[lookupNdx*outLookupStride]; 616 const deUint32* resPtr = refPtr + invocationNdx*4; 617 bool isOk = true; 618 619 for (int ndx = 0; ndx < 4; ndx++) 620 isOk = isOk && (refPtr[ndx] == resPtr[ndx]); 621 622 if (!isOk) 623 { 624 m_testCtx.getLog() << TestLog::Message << "ERROR: invocation " << invocationNdx << " result " 625 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4)) 626 << " for lookup " << lookupNdx << " doesn't match result from first invocation " 627 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4)) 628 << TestLog::EndMessage; 629 630 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 631 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsistent lookup results"); 632 } 633 } 634 } 635 } 636 637 return STOP; 638 } 639 640 class BlockArrayIndexingCase : public TestCase 641 { 642 public: 643 enum BlockType 644 { 645 BLOCKTYPE_UNIFORM = 0, 646 BLOCKTYPE_BUFFER, 647 648 BLOCKTYPE_LAST 649 }; 650 BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType); 651 ~BlockArrayIndexingCase (void); 652 653 void init (void); 654 IterateResult iterate (void); 655 656 private: 657 BlockArrayIndexingCase (const BlockArrayIndexingCase&); 658 BlockArrayIndexingCase& operator= (const BlockArrayIndexingCase&); 659 660 void getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const; 661 662 const BlockType m_blockType; 663 const IndexExprType m_indexExprType; 664 const ShaderType m_shaderType; 665 666 const int m_numInstances; 667 }; 668 669 BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType) 670 : TestCase (context, name, description) 671 , m_blockType (blockType) 672 , m_indexExprType (indexExprType) 673 , m_shaderType (shaderType) 674 , m_numInstances (4) 675 { 676 } 677 678 BlockArrayIndexingCase::~BlockArrayIndexingCase (void) 679 { 680 } 681 682 void BlockArrayIndexingCase::init (void) 683 { 684 const char* extName = "GL_EXT_gpu_shader5"; 685 686 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && 687 !m_context.getContextInfo().isExtensionSupported(extName)) 688 throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of interface blocks"); 689 690 if (m_blockType == BLOCKTYPE_BUFFER) 691 { 692 const deUint32 limitPnames[] = 693 { 694 GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, 695 GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, 696 GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, 697 GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, 698 GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, 699 GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 700 }; 701 702 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 703 int maxBlocks = 0; 704 705 gl.getIntegerv(limitPnames[m_shaderType], &maxBlocks); 706 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()"); 707 708 if (maxBlocks < m_numInstances) 709 throw tcu::NotSupportedError("Not enough shader storage blocks supported for shader type"); 710 } 711 } 712 713 void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const 714 { 715 const int binding = 2; 716 const char* blockName = "Block"; 717 const char* instanceName = "block"; 718 const char* indicesPrefix = "index"; 719 const char* resultPrefix = "result"; 720 const char* interfaceName = m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer"; 721 const char* layout = m_blockType == BLOCKTYPE_UNIFORM ? "std140" : "std430"; 722 std::ostringstream global, code; 723 724 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL) 725 global << "#extension GL_EXT_gpu_shader5 : require\n"; 726 727 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 728 global << "const highp int indexBase = 1;\n"; 729 730 global << 731 "layout(" << layout << ", binding = " << binding << ") " << interfaceName << " " << blockName << "\n" 732 "{\n" 733 " uint value;\n" 734 "} " << instanceName << "[" << numInstances << "];\n"; 735 736 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 737 { 738 for (int readNdx = 0; readNdx < numReads; readNdx++) 739 { 740 const string varName = indicesPrefix + de::toString(readNdx); 741 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP))); 742 } 743 } 744 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 745 declareUniformIndexVars(global, indicesPrefix, numReads); 746 747 for (int readNdx = 0; readNdx < numReads; readNdx++) 748 { 749 const string varName = resultPrefix + de::toString(readNdx); 750 spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP))); 751 } 752 753 for (int readNdx = 0; readNdx < numReads; readNdx++) 754 { 755 code << resultPrefix << readNdx << " = " << instanceName << "["; 756 757 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 758 code << readIndices[readNdx]; 759 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 760 code << "indexBase + " << (readIndices[readNdx]-1); 761 else 762 code << indicesPrefix << readNdx; 763 764 code << "].value;\n"; 765 } 766 767 spec->version = GLSL_VERSION_310_ES; 768 spec->globalDeclarations = global.str(); 769 spec->source = code.str(); 770 } 771 772 BlockArrayIndexingCase::IterateResult BlockArrayIndexingCase::iterate (void) 773 { 774 const int numInvocations = 32; 775 const int numInstances = m_numInstances; 776 const int numReads = 4; 777 vector<int> readIndices (numReads); 778 vector<deUint32> inValues (numInstances); 779 vector<deUint32> outValues (numInvocations*numReads); 780 ShaderSpec shaderSpec; 781 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType)); 782 783 for (int readNdx = 0; readNdx < numReads; readNdx++) 784 readIndices[readNdx] = rnd.getInt(0, numInstances-1); 785 786 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 787 inValues[instanceNdx] = rnd.getUint32(); 788 789 getShaderSpec(&shaderSpec, numInstances, numReads, &readIndices[0]); 790 791 { 792 const RenderContext& renderCtx = m_context.getRenderContext(); 793 const glw::Functions& gl = renderCtx.getFunctions(); 794 const int baseBinding = 2; 795 const BufferVector buffers (renderCtx, numInstances); 796 const deUint32 bufTarget = m_blockType == BLOCKTYPE_BUFFER ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER; 797 ShaderExecutorPtr shaderExecutor (createExecutor(renderCtx, m_shaderType, shaderSpec)); 798 vector<int> expandedIndices; 799 vector<void*> inputs; 800 vector<void*> outputs; 801 802 m_testCtx.getLog() << *shaderExecutor; 803 804 if (!shaderExecutor->isOk()) 805 TCU_FAIL("Compile failed"); 806 807 shaderExecutor->useProgram(); 808 809 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 810 { 811 gl.bindBuffer(bufTarget, buffers[instanceNdx]); 812 gl.bufferData(bufTarget, (glw::GLsizeiptr)sizeof(deUint32), &inValues[instanceNdx], GL_STATIC_DRAW); 813 gl.bindBufferBase(bufTarget, baseBinding+instanceNdx, buffers[instanceNdx]); 814 } 815 816 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 817 { 818 expandedIndices.resize(numInvocations * readIndices.size()); 819 820 for (int readNdx = 0; readNdx < numReads; readNdx++) 821 { 822 int* dst = &expandedIndices[numInvocations*readNdx]; 823 std::fill(dst, dst+numInvocations, readIndices[readNdx]); 824 } 825 826 for (int readNdx = 0; readNdx < numReads; readNdx++) 827 inputs.push_back(&expandedIndices[readNdx*numInvocations]); 828 } 829 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 830 uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numReads, &readIndices[0]); 831 832 for (int readNdx = 0; readNdx < numReads; readNdx++) 833 outputs.push_back(&outValues[readNdx*numInvocations]); 834 835 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 836 837 shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]); 838 } 839 840 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 841 842 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 843 { 844 for (int readNdx = 0; readNdx < numReads; readNdx++) 845 { 846 const deUint32 refValue = inValues[readIndices[readNdx]]; 847 const deUint32 resValue = outValues[readNdx*numInvocations + invocationNdx]; 848 849 if (refValue != resValue) 850 { 851 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx 852 << ", read " << readNdx << ": expected " 853 << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue) 854 << TestLog::EndMessage; 855 856 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 857 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value"); 858 } 859 } 860 } 861 862 return STOP; 863 } 864 865 class AtomicCounterIndexingCase : public TestCase 866 { 867 public: 868 AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType); 869 ~AtomicCounterIndexingCase (void); 870 871 void init (void); 872 IterateResult iterate (void); 873 874 private: 875 AtomicCounterIndexingCase (const AtomicCounterIndexingCase&); 876 AtomicCounterIndexingCase& operator= (const AtomicCounterIndexingCase&); 877 878 void getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const; 879 880 const IndexExprType m_indexExprType; 881 const glu::ShaderType m_shaderType; 882 }; 883 884 AtomicCounterIndexingCase::AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType) 885 : TestCase (context, name, description) 886 , m_indexExprType (indexExprType) 887 , m_shaderType (shaderType) 888 { 889 } 890 891 AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void) 892 { 893 } 894 895 void AtomicCounterIndexingCase::init (void) 896 { 897 const char* extName = "GL_EXT_gpu_shader5"; 898 899 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && 900 !m_context.getContextInfo().isExtensionSupported(extName)) 901 throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of atomic counters"); 902 903 if (m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT) 904 { 905 int numAtomicCounterBuffers = 0; 906 m_context.getRenderContext().getFunctions().getIntegerv(m_shaderType == glu::SHADERTYPE_VERTEX ? GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 907 : GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, 908 &numAtomicCounterBuffers); 909 910 if (numAtomicCounterBuffers == 0) 911 throw tcu::NotSupportedError(string("Atomic counters not supported in ") + glu::getShaderTypeName(m_shaderType) + " shader"); 912 } 913 } 914 915 void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const 916 { 917 const char* indicesPrefix = "index"; 918 const char* resultPrefix = "result"; 919 std::ostringstream global, code; 920 921 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL) 922 global << "#extension GL_EXT_gpu_shader5 : require\n"; 923 924 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 925 global << "const highp int indexBase = 1;\n"; 926 927 global << 928 "layout(binding = 0) uniform atomic_uint counter[" << numCounters << "];\n"; 929 930 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 931 { 932 for (int opNdx = 0; opNdx < numOps; opNdx++) 933 { 934 const string varName = indicesPrefix + de::toString(opNdx); 935 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP))); 936 } 937 } 938 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 939 declareUniformIndexVars(global, indicesPrefix, numOps); 940 941 for (int opNdx = 0; opNdx < numOps; opNdx++) 942 { 943 const string varName = resultPrefix + de::toString(opNdx); 944 spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP))); 945 } 946 947 for (int opNdx = 0; opNdx < numOps; opNdx++) 948 { 949 code << resultPrefix << opNdx << " = atomicCounterIncrement(counter["; 950 951 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 952 code << opIndices[opNdx]; 953 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 954 code << "indexBase + " << (opIndices[opNdx]-1); 955 else 956 code << indicesPrefix << opNdx; 957 958 code << "]);\n"; 959 } 960 961 spec->version = GLSL_VERSION_310_ES; 962 spec->globalDeclarations = global.str(); 963 spec->source = code.str(); 964 } 965 966 AtomicCounterIndexingCase::IterateResult AtomicCounterIndexingCase::iterate (void) 967 { 968 const RenderContext& renderCtx = m_context.getRenderContext(); 969 const glw::Functions& gl = renderCtx.getFunctions(); 970 const Buffer counterBuffer (renderCtx); 971 972 const int numInvocations = 32; 973 const int numCounters = 4; 974 const int numOps = 4; 975 vector<int> opIndices (numOps); 976 vector<deUint32> outValues (numInvocations*numOps); 977 ShaderSpec shaderSpec; 978 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 979 980 for (int opNdx = 0; opNdx < numOps; opNdx++) 981 opIndices[opNdx] = rnd.getInt(0, numOps-1); 982 983 getShaderSpec(&shaderSpec, numCounters, numOps, &opIndices[0]); 984 985 { 986 const BufferVector buffers (renderCtx, numCounters); 987 ShaderExecutorPtr shaderExecutor (createExecutor(renderCtx, m_shaderType, shaderSpec)); 988 vector<int> expandedIndices; 989 vector<void*> inputs; 990 vector<void*> outputs; 991 992 m_testCtx.getLog() << *shaderExecutor; 993 994 if (!shaderExecutor->isOk()) 995 TCU_FAIL("Compile failed"); 996 997 { 998 const int bufSize = getProgramResourceInt(gl, shaderExecutor->getProgram(), GL_ATOMIC_COUNTER_BUFFER, 0, GL_BUFFER_DATA_SIZE); 999 const int maxNdx = maxElement(opIndices); 1000 std::vector<deUint8> emptyData (numCounters*4, 0); 1001 1002 if (bufSize < (maxNdx+1)*4) 1003 TCU_FAIL((string("GL reported invalid buffer size " + de::toString(bufSize)).c_str())); 1004 1005 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *counterBuffer); 1006 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_DRAW); 1007 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, *counterBuffer); 1008 GLU_EXPECT_NO_ERROR(gl.getError(), "Atomic counter buffer initialization failed"); 1009 } 1010 1011 shaderExecutor->useProgram(); 1012 1013 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 1014 { 1015 expandedIndices.resize(numInvocations * opIndices.size()); 1016 1017 for (int opNdx = 0; opNdx < numOps; opNdx++) 1018 { 1019 int* dst = &expandedIndices[numInvocations*opNdx]; 1020 std::fill(dst, dst+numInvocations, opIndices[opNdx]); 1021 } 1022 1023 for (int opNdx = 0; opNdx < numOps; opNdx++) 1024 inputs.push_back(&expandedIndices[opNdx*numInvocations]); 1025 } 1026 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 1027 uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numOps, &opIndices[0]); 1028 1029 for (int opNdx = 0; opNdx < numOps; opNdx++) 1030 outputs.push_back(&outValues[opNdx*numInvocations]); 1031 1032 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 1033 1034 shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]); 1035 } 1036 1037 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1038 1039 { 1040 vector<int> numHits (numCounters, 0); // Number of hits per counter. 1041 vector<deUint32> counterValues (numCounters); 1042 vector<vector<bool> > counterMasks (numCounters); 1043 1044 for (int opNdx = 0; opNdx < numOps; opNdx++) 1045 numHits[opIndices[opNdx]] += 1; 1046 1047 // Read counter values 1048 { 1049 const void* mapPtr = DE_NULL; 1050 1051 try 1052 { 1053 mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, numCounters*4, GL_MAP_READ_BIT); 1054 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER)"); 1055 TCU_CHECK(mapPtr); 1056 std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]); 1057 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 1058 } 1059 catch (...) 1060 { 1061 if (mapPtr) 1062 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 1063 throw; 1064 } 1065 } 1066 1067 // Verify counter values 1068 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1069 { 1070 const deUint32 refCount = (deUint32)(numHits[counterNdx]*numInvocations); 1071 const deUint32 resCount = counterValues[counterNdx]; 1072 1073 if (refCount != resCount) 1074 { 1075 m_testCtx.getLog() << TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount 1076 << ", expected " << refCount 1077 << TestLog::EndMessage; 1078 1079 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1080 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid atomic counter value"); 1081 } 1082 } 1083 1084 // Allocate bitmasks - one bit per each valid result value 1085 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1086 { 1087 const int counterValue = numHits[counterNdx]*numInvocations; 1088 counterMasks[counterNdx].resize(counterValue, false); 1089 } 1090 1091 // Verify result values from shaders 1092 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 1093 { 1094 for (int opNdx = 0; opNdx < numOps; opNdx++) 1095 { 1096 const int counterNdx = opIndices[opNdx]; 1097 const deUint32 resValue = outValues[opNdx*numInvocations + invocationNdx]; 1098 const bool rangeOk = de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size()); 1099 const bool notSeen = rangeOk && !counterMasks[counterNdx][resValue]; 1100 const bool isOk = rangeOk && notSeen; 1101 1102 if (!isOk) 1103 { 1104 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx 1105 << ", op " << opNdx << ": got invalid result value " 1106 << resValue 1107 << TestLog::EndMessage; 1108 1109 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1110 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value"); 1111 } 1112 else 1113 { 1114 // Mark as used - no other invocation should see this value from same counter. 1115 counterMasks[counterNdx][resValue] = true; 1116 } 1117 } 1118 } 1119 1120 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1121 { 1122 // Consistency check - all masks should be 1 now 1123 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1124 { 1125 for (vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++) 1126 TCU_CHECK_INTERNAL(*i); 1127 } 1128 } 1129 } 1130 1131 return STOP; 1132 } 1133 1134 } // anonymous 1135 1136 OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (Context& context) 1137 : TestCaseGroup(context, "opaque_type_indexing", "Opaque Type Indexing Tests") 1138 { 1139 } 1140 1141 OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void) 1142 { 1143 } 1144 1145 void OpaqueTypeIndexingTests::init (void) 1146 { 1147 static const struct 1148 { 1149 IndexExprType type; 1150 const char* name; 1151 const char* description; 1152 } indexingTypes[] = 1153 { 1154 { INDEX_EXPR_TYPE_CONST_LITERAL, "const_literal", "Indexing by constant literal" }, 1155 { INDEX_EXPR_TYPE_CONST_EXPRESSION, "const_expression", "Indexing by constant expression" }, 1156 { INDEX_EXPR_TYPE_UNIFORM, "uniform", "Indexing by uniform value" }, 1157 { INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, "dynamically_uniform", "Indexing by dynamically uniform expression" } 1158 }; 1159 1160 static const struct 1161 { 1162 ShaderType type; 1163 const char* name; 1164 } shaderTypes[] = 1165 { 1166 { SHADERTYPE_VERTEX, "vertex" }, 1167 { SHADERTYPE_FRAGMENT, "fragment" }, 1168 { SHADERTYPE_COMPUTE, "compute" } 1169 }; 1170 1171 // .sampler 1172 { 1173 static const DataType samplerTypes[] = 1174 { 1175 // \note 1D images will be added by a later extension. 1176 // TYPE_SAMPLER_1D, 1177 TYPE_SAMPLER_2D, 1178 TYPE_SAMPLER_CUBE, 1179 TYPE_SAMPLER_2D_ARRAY, 1180 TYPE_SAMPLER_3D, 1181 // TYPE_SAMPLER_1D_SHADOW, 1182 TYPE_SAMPLER_2D_SHADOW, 1183 TYPE_SAMPLER_CUBE_SHADOW, 1184 TYPE_SAMPLER_2D_ARRAY_SHADOW, 1185 // TYPE_INT_SAMPLER_1D, 1186 TYPE_INT_SAMPLER_2D, 1187 TYPE_INT_SAMPLER_CUBE, 1188 TYPE_INT_SAMPLER_2D_ARRAY, 1189 TYPE_INT_SAMPLER_3D, 1190 // TYPE_UINT_SAMPLER_1D, 1191 TYPE_UINT_SAMPLER_2D, 1192 TYPE_UINT_SAMPLER_CUBE, 1193 TYPE_UINT_SAMPLER_2D_ARRAY, 1194 TYPE_UINT_SAMPLER_3D, 1195 }; 1196 1197 tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests"); 1198 addChild(samplerGroup); 1199 1200 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++) 1201 { 1202 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type; 1203 tcu::TestCaseGroup* const indexGroup = new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description); 1204 samplerGroup->addChild(indexGroup); 1205 1206 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 1207 { 1208 const ShaderType shaderType = shaderTypes[shaderTypeNdx].type; 1209 tcu::TestCaseGroup* const shaderGroup = new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, ""); 1210 indexGroup->addChild(shaderGroup); 1211 1212 for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++) 1213 { 1214 const DataType samplerType = samplerTypes[samplerTypeNdx]; 1215 const char* samplerName = getDataTypeName(samplerType); 1216 const string caseName = de::toLower(samplerName); 1217 1218 shaderGroup->addChild(new SamplerIndexingCase(m_context, caseName.c_str(), "", shaderType, samplerType, indexExprType)); 1219 } 1220 } 1221 } 1222 } 1223 1224 // .ubo / .ssbo / .atomic_counter 1225 { 1226 tcu::TestCaseGroup* const uboGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Uniform Block Instance Array Indexing Tests"); 1227 tcu::TestCaseGroup* const ssboGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Buffer Block Instance Array Indexing Tests"); 1228 tcu::TestCaseGroup* const acGroup = new tcu::TestCaseGroup(m_testCtx, "atomic_counter", "Atomic Counter Array Indexing Tests"); 1229 addChild(uboGroup); 1230 addChild(ssboGroup); 1231 addChild(acGroup); 1232 1233 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++) 1234 { 1235 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type; 1236 const char* indexExprName = indexingTypes[indexTypeNdx].name; 1237 const char* indexExprDesc = indexingTypes[indexTypeNdx].description; 1238 1239 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 1240 { 1241 const ShaderType shaderType = shaderTypes[shaderTypeNdx].type; 1242 const string name = string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name; 1243 1244 uboGroup->addChild (new BlockArrayIndexingCase (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_UNIFORM, indexExprType, shaderType)); 1245 acGroup->addChild (new AtomicCounterIndexingCase (m_context, name.c_str(), indexExprDesc, indexExprType, shaderType)); 1246 1247 if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1248 ssboGroup->addChild (new BlockArrayIndexingCase (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER, indexExprType, shaderType)); 1249 } 1250 } 1251 } 1252 } 1253 1254 } // Functional 1255 } // gles31 1256 } // deqp 1257