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