es31fOpaqueTypeIndexingTests.cpp revision fb059fdb43c8b6073ada028a68124263c59a000a
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 49namespace deqp 50{ 51namespace gles31 52{ 53namespace Functional 54{ 55 56namespace 57{ 58 59using namespace gls::ShaderExecUtil; 60using namespace glu; 61using std::string; 62using std::vector; 63using tcu::TextureFormat; 64using tcu::TestLog; 65 66typedef de::UniquePtr<ShaderExecutor> ShaderExecutorPtr; 67 68enum 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 78enum 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 90static 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 96static 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 108template<typename T> 109static 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 119static 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 163static 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 172static 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 212static 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 233static 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 258static 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 273static 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 332class SamplerIndexingCase : public TestCase 333{ 334public: 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 341private: 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 352SamplerIndexingCase::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 360SamplerIndexingCase::~SamplerIndexingCase (void) 361{ 362} 363 364void 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} 384 385void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices, const RenderContext& renderContext) const 386{ 387 const char* samplersName = "sampler"; 388 const char* coordsName = "coords"; 389 const char* indicesPrefix = "index"; 390 const char* resultPrefix = "result"; 391 const DataType coordType = getSamplerCoordType(m_samplerType); 392 const DataType outType = getSamplerOutputType(m_samplerType); 393 const bool isES32 = contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); 394 std::ostringstream global; 395 std::ostringstream code; 396 397 spec->inputs.push_back(Symbol(coordsName, VarType(coordType, PRECISION_HIGHP))); 398 399 if (!isES32 && m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION) 400 global << "#extension GL_EXT_gpu_shader5 : require\n"; 401 402 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 403 global << "const highp int indexBase = 1;\n"; 404 405 global << 406 "uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << numSamplers << "];\n"; 407 408 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 409 { 410 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 411 { 412 const string varName = indicesPrefix + de::toString(lookupNdx); 413 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP))); 414 } 415 } 416 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 417 declareUniformIndexVars(global, indicesPrefix, numLookups); 418 419 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 420 { 421 const string varName = resultPrefix + de::toString(lookupNdx); 422 spec->outputs.push_back(Symbol(varName, VarType(outType, PRECISION_HIGHP))); 423 } 424 425 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 426 { 427 code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "["; 428 429 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 430 code << lookupIndices[lookupNdx]; 431 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 432 code << "indexBase + " << (lookupIndices[lookupNdx]-1); 433 else 434 code << indicesPrefix << lookupNdx; 435 436 437 code << "], " << coordsName << (m_samplerType == TYPE_SAMPLER_CUBE_ARRAY_SHADOW ? ", 0.0" : "") << ");\n"; 438 } 439 440 spec->version = isES32 ? GLSL_VERSION_320_ES : GLSL_VERSION_310_ES; 441 spec->globalDeclarations = global.str(); 442 spec->source = code.str(); 443} 444 445static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd) 446{ 447 DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1); 448 449 if (access.getFormat().order == TextureFormat::D) 450 { 451 // \note Texture uses odd values, lookup even values to avoid precision issues. 452 const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f }; 453 454 for (int ndx = 0; ndx < access.getWidth(); ndx++) 455 access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0); 456 } 457 else 458 { 459 TCU_CHECK_INTERNAL(access.getFormat().order == TextureFormat::RGBA && access.getFormat().getPixelSize() == 4); 460 461 for (int ndx = 0; ndx < access.getWidth(); ndx++) 462 *((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32(); 463 } 464} 465 466SamplerIndexingCase::IterateResult SamplerIndexingCase::iterate (void) 467{ 468 const int numInvocations = 64; 469 const int numSamplers = 8; 470 const int numLookups = 4; 471 const DataType coordType = getSamplerCoordType(m_samplerType); 472 const DataType outputType = getSamplerOutputType(m_samplerType); 473 const TextureFormat texFormat = getSamplerTextureFormat(m_samplerType); 474 const int outLookupStride = numInvocations*getDataTypeScalarSize(outputType); 475 vector<int> lookupIndices (numLookups); 476 vector<float> coords; 477 vector<deUint32> outData; 478 vector<deUint8> texData (numSamplers * texFormat.getPixelSize()); 479 const tcu::PixelBufferAccess refTexAccess (texFormat, numSamplers, 1, 1, &texData[0]); 480 481 ShaderSpec shaderSpec; 482 de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 483 484 for (int ndx = 0; ndx < numLookups; ndx++) 485 lookupIndices[ndx] = rnd.getInt(0, numSamplers-1); 486 487 getShaderSpec(&shaderSpec, numSamplers, numLookups, &lookupIndices[0], m_context.getRenderContext()); 488 489 coords.resize(numInvocations * getDataTypeScalarSize(coordType)); 490 491 if (m_samplerType != TYPE_SAMPLER_CUBE_ARRAY_SHADOW && isShadowSampler(m_samplerType)) 492 { 493 // Use different comparison value per invocation. 494 // \note Texture uses odd values, comparison even values. 495 const int numCoordComps = getDataTypeScalarSize(coordType); 496 const float cmpValues[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }; 497 498 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 499 coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues)); 500 } 501 502 fillTextureData(refTexAccess, rnd); 503 504 outData.resize(numLookups*outLookupStride); 505 506 { 507 const RenderContext& renderCtx = m_context.getRenderContext(); 508 const glw::Functions& gl = renderCtx.getFunctions(); 509 ShaderExecutorPtr executor (createExecutor(m_context.getRenderContext(), m_shaderType, shaderSpec)); 510 TextureVector textures (renderCtx, numSamplers); 511 vector<void*> inputs; 512 vector<void*> outputs; 513 vector<int> expandedIndices; 514 const int maxIndex = maxElement(lookupIndices); 515 516 m_testCtx.getLog() << *executor; 517 518 if (!executor->isOk()) 519 TCU_FAIL("Compile failed"); 520 521 executor->useProgram(); 522 523 // \todo [2014-03-05 pyry] Do we want to randomize tex unit assignments? 524 for (int samplerNdx = 0; samplerNdx < numSamplers; samplerNdx++) 525 { 526 const string samplerName = string("sampler[") + de::toString(samplerNdx) + "]"; 527 const int samplerLoc = gl.getUniformLocation(executor->getProgram(), samplerName.c_str()); 528 529 if (samplerNdx > maxIndex && samplerLoc < 0) 530 continue; // Unused uniform eliminated by compiler 531 532 TCU_CHECK_MSG(samplerLoc >= 0, (string("No location for uniform '") + samplerName + "' found").c_str()); 533 534 gl.activeTexture(GL_TEXTURE0 + samplerNdx); 535 setupTexture(gl, textures[samplerNdx], m_samplerType, texFormat, &texData[samplerNdx*texFormat.getPixelSize()]); 536 537 gl.uniform1i(samplerLoc, samplerNdx); 538 } 539 540 inputs.push_back(&coords[0]); 541 542 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 543 { 544 expandedIndices.resize(numInvocations * lookupIndices.size()); 545 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 546 { 547 for (int invNdx = 0; invNdx < numInvocations; invNdx++) 548 expandedIndices[lookupNdx*numInvocations + invNdx] = lookupIndices[lookupNdx]; 549 } 550 551 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 552 inputs.push_back(&expandedIndices[lookupNdx*numInvocations]); 553 } 554 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 555 uploadUniformIndices(gl, executor->getProgram(), "index", numLookups, &lookupIndices[0]); 556 557 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 558 outputs.push_back(&outData[outLookupStride*lookupNdx]); 559 560 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 561 562 executor->execute(numInvocations, &inputs[0], &outputs[0]); 563 } 564 565 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 566 567 if (isShadowSampler(m_samplerType)) 568 { 569 const tcu::Sampler refSampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 570 tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0.0f, false /* non-normalized */, 571 tcu::Sampler::COMPAREMODE_LESS); 572 const int numCoordComps = getDataTypeScalarSize(coordType); 573 574 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1); 575 576 // Each invocation may have different results. 577 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 578 { 579 const float coord = coords[invocationNdx*numCoordComps + (numCoordComps-1)]; 580 581 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 582 { 583 const int texNdx = lookupIndices[lookupNdx]; 584 const float result = *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]); 585 const float reference = refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0)); 586 587 if (de::abs(result-reference) > 0.005f) 588 { 589 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected " 590 << reference << ", got " << result 591 << TestLog::EndMessage; 592 593 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 594 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result"); 595 } 596 } 597 } 598 } 599 else 600 { 601 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4); 602 603 // Validate results from first invocation 604 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 605 { 606 const int texNdx = lookupIndices[lookupNdx]; 607 const deUint8* resPtr = (const deUint8*)&outData[lookupNdx*outLookupStride]; 608 bool isOk; 609 610 if (outputType == TYPE_FLOAT_VEC4) 611 { 612 const float threshold = 1.0f / 256.0f; 613 const tcu::Vec4 reference = refTexAccess.getPixel(texNdx, 0); 614 const float* floatPtr = (const float*)resPtr; 615 const tcu::Vec4 result (floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]); 616 617 isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold))); 618 619 if (!isOk) 620 { 621 m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected " 622 << reference << ", got " << result 623 << TestLog::EndMessage; 624 } 625 } 626 else 627 { 628 const tcu::UVec4 reference = refTexAccess.getPixelUint(texNdx, 0); 629 const deUint32* uintPtr = (const deUint32*)resPtr; 630 const tcu::UVec4 result (uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]); 631 632 isOk = boolAll(equal(reference, result)); 633 634 if (!isOk) 635 { 636 m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected " 637 << reference << ", got " << result 638 << TestLog::EndMessage; 639 } 640 } 641 642 if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 643 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result"); 644 } 645 646 // Check results of other invocations against first one 647 for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++) 648 { 649 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 650 { 651 const deUint32* refPtr = &outData[lookupNdx*outLookupStride]; 652 const deUint32* resPtr = refPtr + invocationNdx*4; 653 bool isOk = true; 654 655 for (int ndx = 0; ndx < 4; ndx++) 656 isOk = isOk && (refPtr[ndx] == resPtr[ndx]); 657 658 if (!isOk) 659 { 660 m_testCtx.getLog() << TestLog::Message << "ERROR: invocation " << invocationNdx << " result " 661 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4)) 662 << " for lookup " << lookupNdx << " doesn't match result from first invocation " 663 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4)) 664 << TestLog::EndMessage; 665 666 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 667 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsistent lookup results"); 668 } 669 } 670 } 671 } 672 673 return STOP; 674} 675 676class BlockArrayIndexingCase : public TestCase 677{ 678public: 679 enum BlockType 680 { 681 BLOCKTYPE_UNIFORM = 0, 682 BLOCKTYPE_BUFFER, 683 684 BLOCKTYPE_LAST 685 }; 686 BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType); 687 ~BlockArrayIndexingCase (void); 688 689 void init (void); 690 IterateResult iterate (void); 691 692private: 693 BlockArrayIndexingCase (const BlockArrayIndexingCase&); 694 BlockArrayIndexingCase& operator= (const BlockArrayIndexingCase&); 695 696 void getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices, const RenderContext& renderContext) const; 697 698 const BlockType m_blockType; 699 const IndexExprType m_indexExprType; 700 const ShaderType m_shaderType; 701 702 const int m_numInstances; 703}; 704 705BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType) 706 : TestCase (context, name, description) 707 , m_blockType (blockType) 708 , m_indexExprType (indexExprType) 709 , m_shaderType (shaderType) 710 , m_numInstances (4) 711{ 712} 713 714BlockArrayIndexingCase::~BlockArrayIndexingCase (void) 715{ 716} 717 718void BlockArrayIndexingCase::init (void) 719{ 720 if (!contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) 721 { 722 if (m_shaderType == SHADERTYPE_GEOMETRY) 723 TCU_CHECK_AND_THROW(NotSupportedError, 724 m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"), 725 "GL_EXT_geometry_shader extension is required to run geometry shader tests."); 726 727 if (m_shaderType == SHADERTYPE_TESSELLATION_CONTROL || m_shaderType == SHADERTYPE_TESSELLATION_EVALUATION) 728 TCU_CHECK_AND_THROW(NotSupportedError, 729 m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"), 730 "GL_EXT_tessellation_shader extension is required to run tessellation shader tests."); 731 732 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION) 733 TCU_CHECK_AND_THROW(NotSupportedError, 734 m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"), 735 "GL_EXT_gpu_shader5 extension is required for dynamic indexing of interface blocks."); 736 } 737 738 if (m_blockType == BLOCKTYPE_BUFFER) 739 { 740 const deUint32 limitPnames[] = 741 { 742 GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, 743 GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, 744 GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, 745 GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, 746 GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, 747 GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 748 }; 749 750 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 751 int maxBlocks = 0; 752 753 gl.getIntegerv(limitPnames[m_shaderType], &maxBlocks); 754 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()"); 755 756 if (maxBlocks < 2 + m_numInstances) 757 throw tcu::NotSupportedError("Not enough shader storage blocks supported for shader type"); 758 } 759} 760 761void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices, const RenderContext& renderContext) const 762{ 763 const int binding = 2; 764 const char* blockName = "Block"; 765 const char* instanceName = "block"; 766 const char* indicesPrefix = "index"; 767 const char* resultPrefix = "result"; 768 const char* interfaceName = m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer"; 769 const char* layout = m_blockType == BLOCKTYPE_UNIFORM ? "std140" : "std430"; 770 const bool isES32 = contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); 771 std::ostringstream global; 772 std::ostringstream code; 773 774 if (!isES32 && m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION) 775 global << "#extension GL_EXT_gpu_shader5 : require\n"; 776 777 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 778 global << "const highp int indexBase = 1;\n"; 779 780 global << 781 "layout(" << layout << ", binding = " << binding << ") " << interfaceName << " " << blockName << "\n" 782 "{\n" 783 " uint value;\n" 784 "} " << instanceName << "[" << numInstances << "];\n"; 785 786 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 787 { 788 for (int readNdx = 0; readNdx < numReads; readNdx++) 789 { 790 const string varName = indicesPrefix + de::toString(readNdx); 791 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP))); 792 } 793 } 794 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 795 declareUniformIndexVars(global, indicesPrefix, numReads); 796 797 for (int readNdx = 0; readNdx < numReads; readNdx++) 798 { 799 const string varName = resultPrefix + de::toString(readNdx); 800 spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP))); 801 } 802 803 for (int readNdx = 0; readNdx < numReads; readNdx++) 804 { 805 code << resultPrefix << readNdx << " = " << instanceName << "["; 806 807 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 808 code << readIndices[readNdx]; 809 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 810 code << "indexBase + " << (readIndices[readNdx]-1); 811 else 812 code << indicesPrefix << readNdx; 813 814 code << "].value;\n"; 815 } 816 817 spec->version = isES32 ? GLSL_VERSION_320_ES : GLSL_VERSION_310_ES; 818 spec->globalDeclarations = global.str(); 819 spec->source = code.str(); 820} 821 822BlockArrayIndexingCase::IterateResult BlockArrayIndexingCase::iterate (void) 823{ 824 const int numInvocations = 32; 825 const int numInstances = m_numInstances; 826 const int numReads = 4; 827 vector<int> readIndices (numReads); 828 vector<deUint32> inValues (numInstances); 829 vector<deUint32> outValues (numInvocations*numReads); 830 ShaderSpec shaderSpec; 831 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType)); 832 833 for (int readNdx = 0; readNdx < numReads; readNdx++) 834 readIndices[readNdx] = rnd.getInt(0, numInstances-1); 835 836 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 837 inValues[instanceNdx] = rnd.getUint32(); 838 839 getShaderSpec(&shaderSpec, numInstances, numReads, &readIndices[0], m_context.getRenderContext()); 840 841 { 842 const RenderContext& renderCtx = m_context.getRenderContext(); 843 const glw::Functions& gl = renderCtx.getFunctions(); 844 const int baseBinding = 2; 845 const BufferVector buffers (renderCtx, numInstances); 846 const deUint32 bufTarget = m_blockType == BLOCKTYPE_BUFFER ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER; 847 ShaderExecutorPtr shaderExecutor (createExecutor(renderCtx, m_shaderType, shaderSpec)); 848 vector<int> expandedIndices; 849 vector<void*> inputs; 850 vector<void*> outputs; 851 852 m_testCtx.getLog() << *shaderExecutor; 853 854 if (!shaderExecutor->isOk()) 855 TCU_FAIL("Compile failed"); 856 857 shaderExecutor->useProgram(); 858 859 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 860 { 861 gl.bindBuffer(bufTarget, buffers[instanceNdx]); 862 gl.bufferData(bufTarget, (glw::GLsizeiptr)sizeof(deUint32), &inValues[instanceNdx], GL_STATIC_DRAW); 863 gl.bindBufferBase(bufTarget, baseBinding+instanceNdx, buffers[instanceNdx]); 864 } 865 866 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 867 { 868 expandedIndices.resize(numInvocations * readIndices.size()); 869 870 for (int readNdx = 0; readNdx < numReads; readNdx++) 871 { 872 int* dst = &expandedIndices[numInvocations*readNdx]; 873 std::fill(dst, dst+numInvocations, readIndices[readNdx]); 874 } 875 876 for (int readNdx = 0; readNdx < numReads; readNdx++) 877 inputs.push_back(&expandedIndices[readNdx*numInvocations]); 878 } 879 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 880 uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numReads, &readIndices[0]); 881 882 for (int readNdx = 0; readNdx < numReads; readNdx++) 883 outputs.push_back(&outValues[readNdx*numInvocations]); 884 885 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 886 887 shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]); 888 } 889 890 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 891 892 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 893 { 894 for (int readNdx = 0; readNdx < numReads; readNdx++) 895 { 896 const deUint32 refValue = inValues[readIndices[readNdx]]; 897 const deUint32 resValue = outValues[readNdx*numInvocations + invocationNdx]; 898 899 if (refValue != resValue) 900 { 901 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx 902 << ", read " << readNdx << ": expected " 903 << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue) 904 << TestLog::EndMessage; 905 906 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 907 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value"); 908 } 909 } 910 } 911 912 return STOP; 913} 914 915class AtomicCounterIndexingCase : public TestCase 916{ 917public: 918 AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType); 919 ~AtomicCounterIndexingCase (void); 920 921 void init (void); 922 IterateResult iterate (void); 923 924private: 925 AtomicCounterIndexingCase (const AtomicCounterIndexingCase&); 926 AtomicCounterIndexingCase& operator= (const AtomicCounterIndexingCase&); 927 928 void getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices, const RenderContext& renderContext) const; 929 930 const IndexExprType m_indexExprType; 931 const glu::ShaderType m_shaderType; 932}; 933 934AtomicCounterIndexingCase::AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType) 935 : TestCase (context, name, description) 936 , m_indexExprType (indexExprType) 937 , m_shaderType (shaderType) 938{ 939} 940 941AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void) 942{ 943} 944 945void AtomicCounterIndexingCase::init (void) 946{ 947 if (!contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) 948 { 949 if (m_shaderType == SHADERTYPE_GEOMETRY) 950 TCU_CHECK_AND_THROW(NotSupportedError, 951 m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"), 952 "GL_EXT_geometry_shader extension is required to run geometry shader tests."); 953 954 if (m_shaderType == SHADERTYPE_TESSELLATION_CONTROL || m_shaderType == SHADERTYPE_TESSELLATION_EVALUATION) 955 TCU_CHECK_AND_THROW(NotSupportedError, 956 m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"), 957 "GL_EXT_tessellation_shader extension is required to run tessellation shader tests."); 958 959 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION) 960 TCU_CHECK_AND_THROW(NotSupportedError, 961 m_context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"), 962 "GL_EXT_gpu_shader5 extension is required for dynamic indexing of atomic counters."); 963 } 964 965 if (m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT) 966 { 967 int numAtomicCounterBuffers = 0; 968 m_context.getRenderContext().getFunctions().getIntegerv(m_shaderType == glu::SHADERTYPE_VERTEX ? GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 969 : GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, 970 &numAtomicCounterBuffers); 971 972 if (numAtomicCounterBuffers == 0) 973 { 974 const string message = "Atomic counters not supported in " + string(glu::getShaderTypeName(m_shaderType)) + " shader"; 975 TCU_THROW(NotSupportedError, message.c_str()); 976 } 977 } 978} 979 980void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices, const RenderContext& renderContext) const 981{ 982 const char* indicesPrefix = "index"; 983 const char* resultPrefix = "result"; 984 const bool isES32 = contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); 985 std::ostringstream global; 986 std::ostringstream code; 987 988 if (!isES32 && m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION) 989 global << "#extension GL_EXT_gpu_shader5 : require\n"; 990 991 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 992 global << "const highp int indexBase = 1;\n"; 993 994 global << 995 "layout(binding = 0) uniform atomic_uint counter[" << numCounters << "];\n"; 996 997 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 998 { 999 for (int opNdx = 0; opNdx < numOps; opNdx++) 1000 { 1001 const string varName = indicesPrefix + de::toString(opNdx); 1002 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP))); 1003 } 1004 } 1005 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 1006 declareUniformIndexVars(global, indicesPrefix, numOps); 1007 1008 for (int opNdx = 0; opNdx < numOps; opNdx++) 1009 { 1010 const string varName = resultPrefix + de::toString(opNdx); 1011 spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP))); 1012 } 1013 1014 for (int opNdx = 0; opNdx < numOps; opNdx++) 1015 { 1016 code << resultPrefix << opNdx << " = atomicCounterIncrement(counter["; 1017 1018 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 1019 code << opIndices[opNdx]; 1020 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1021 code << "indexBase + " << (opIndices[opNdx]-1); 1022 else 1023 code << indicesPrefix << opNdx; 1024 1025 code << "]);\n"; 1026 } 1027 1028 spec->version = isES32 ? GLSL_VERSION_320_ES : GLSL_VERSION_310_ES; 1029 spec->globalDeclarations = global.str(); 1030 spec->source = code.str(); 1031} 1032 1033AtomicCounterIndexingCase::IterateResult AtomicCounterIndexingCase::iterate (void) 1034{ 1035 const RenderContext& renderCtx = m_context.getRenderContext(); 1036 const glw::Functions& gl = renderCtx.getFunctions(); 1037 const Buffer counterBuffer (renderCtx); 1038 1039 const int numInvocations = 32; 1040 const int numCounters = 4; 1041 const int numOps = 4; 1042 vector<int> opIndices (numOps); 1043 vector<deUint32> outValues (numInvocations*numOps); 1044 ShaderSpec shaderSpec; 1045 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 1046 1047 for (int opNdx = 0; opNdx < numOps; opNdx++) 1048 opIndices[opNdx] = rnd.getInt(0, numOps-1); 1049 1050 getShaderSpec(&shaderSpec, numCounters, numOps, &opIndices[0], m_context.getRenderContext()); 1051 1052 { 1053 const BufferVector buffers (renderCtx, numCounters); 1054 ShaderExecutorPtr shaderExecutor (createExecutor(renderCtx, m_shaderType, shaderSpec)); 1055 vector<int> expandedIndices; 1056 vector<void*> inputs; 1057 vector<void*> outputs; 1058 1059 m_testCtx.getLog() << *shaderExecutor; 1060 1061 if (!shaderExecutor->isOk()) 1062 TCU_FAIL("Compile failed"); 1063 1064 { 1065 const int bufSize = getProgramResourceInt(gl, shaderExecutor->getProgram(), GL_ATOMIC_COUNTER_BUFFER, 0, GL_BUFFER_DATA_SIZE); 1066 const int maxNdx = maxElement(opIndices); 1067 std::vector<deUint8> emptyData (numCounters*4, 0); 1068 1069 if (bufSize < (maxNdx+1)*4) 1070 TCU_FAIL((string("GL reported invalid buffer size " + de::toString(bufSize)).c_str())); 1071 1072 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *counterBuffer); 1073 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_DRAW); 1074 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, *counterBuffer); 1075 GLU_EXPECT_NO_ERROR(gl.getError(), "Atomic counter buffer initialization failed"); 1076 } 1077 1078 shaderExecutor->useProgram(); 1079 1080 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 1081 { 1082 expandedIndices.resize(numInvocations * opIndices.size()); 1083 1084 for (int opNdx = 0; opNdx < numOps; opNdx++) 1085 { 1086 int* dst = &expandedIndices[numInvocations*opNdx]; 1087 std::fill(dst, dst+numInvocations, opIndices[opNdx]); 1088 } 1089 1090 for (int opNdx = 0; opNdx < numOps; opNdx++) 1091 inputs.push_back(&expandedIndices[opNdx*numInvocations]); 1092 } 1093 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 1094 uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numOps, &opIndices[0]); 1095 1096 for (int opNdx = 0; opNdx < numOps; opNdx++) 1097 outputs.push_back(&outValues[opNdx*numInvocations]); 1098 1099 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed"); 1100 1101 shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]); 1102 } 1103 1104 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1105 1106 { 1107 vector<int> numHits (numCounters, 0); // Number of hits per counter. 1108 vector<deUint32> counterValues (numCounters); 1109 vector<vector<bool> > counterMasks (numCounters); 1110 1111 for (int opNdx = 0; opNdx < numOps; opNdx++) 1112 numHits[opIndices[opNdx]] += 1; 1113 1114 // Read counter values 1115 { 1116 const void* mapPtr = DE_NULL; 1117 1118 try 1119 { 1120 mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, numCounters*4, GL_MAP_READ_BIT); 1121 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER)"); 1122 TCU_CHECK(mapPtr); 1123 std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]); 1124 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 1125 } 1126 catch (...) 1127 { 1128 if (mapPtr) 1129 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 1130 throw; 1131 } 1132 } 1133 1134 // Verify counter values 1135 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1136 { 1137 const deUint32 refCount = (deUint32)(numHits[counterNdx]*numInvocations); 1138 const deUint32 resCount = counterValues[counterNdx]; 1139 1140 if (refCount != resCount) 1141 { 1142 m_testCtx.getLog() << TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount 1143 << ", expected " << refCount 1144 << TestLog::EndMessage; 1145 1146 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1147 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid atomic counter value"); 1148 } 1149 } 1150 1151 // Allocate bitmasks - one bit per each valid result value 1152 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1153 { 1154 const int counterValue = numHits[counterNdx]*numInvocations; 1155 counterMasks[counterNdx].resize(counterValue, false); 1156 } 1157 1158 // Verify result values from shaders 1159 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 1160 { 1161 for (int opNdx = 0; opNdx < numOps; opNdx++) 1162 { 1163 const int counterNdx = opIndices[opNdx]; 1164 const deUint32 resValue = outValues[opNdx*numInvocations + invocationNdx]; 1165 const bool rangeOk = de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size()); 1166 const bool notSeen = rangeOk && !counterMasks[counterNdx][resValue]; 1167 const bool isOk = rangeOk && notSeen; 1168 1169 if (!isOk) 1170 { 1171 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx 1172 << ", op " << opNdx << ": got invalid result value " 1173 << resValue 1174 << TestLog::EndMessage; 1175 1176 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1177 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value"); 1178 } 1179 else 1180 { 1181 // Mark as used - no other invocation should see this value from same counter. 1182 counterMasks[counterNdx][resValue] = true; 1183 } 1184 } 1185 } 1186 1187 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) 1188 { 1189 // Consistency check - all masks should be 1 now 1190 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1191 { 1192 for (vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++) 1193 TCU_CHECK_INTERNAL(*i); 1194 } 1195 } 1196 } 1197 1198 return STOP; 1199} 1200 1201} // anonymous 1202 1203OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (Context& context) 1204 : TestCaseGroup(context, "opaque_type_indexing", "Opaque Type Indexing Tests") 1205{ 1206} 1207 1208OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void) 1209{ 1210} 1211 1212void OpaqueTypeIndexingTests::init (void) 1213{ 1214 static const struct 1215 { 1216 IndexExprType type; 1217 const char* name; 1218 const char* description; 1219 } indexingTypes[] = 1220 { 1221 { INDEX_EXPR_TYPE_CONST_LITERAL, "const_literal", "Indexing by constant literal" }, 1222 { INDEX_EXPR_TYPE_CONST_EXPRESSION, "const_expression", "Indexing by constant expression" }, 1223 { INDEX_EXPR_TYPE_UNIFORM, "uniform", "Indexing by uniform value" }, 1224 { INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, "dynamically_uniform", "Indexing by dynamically uniform expression" } 1225 }; 1226 1227 static const struct 1228 { 1229 ShaderType type; 1230 const char* name; 1231 } shaderTypes[] = 1232 { 1233 { SHADERTYPE_VERTEX, "vertex" }, 1234 { SHADERTYPE_FRAGMENT, "fragment" }, 1235 { SHADERTYPE_COMPUTE, "compute" }, 1236 { SHADERTYPE_GEOMETRY, "geometry" }, 1237 { SHADERTYPE_TESSELLATION_CONTROL, "tessellation_control" }, 1238 { SHADERTYPE_TESSELLATION_EVALUATION, "tessellation_evaluation" } 1239 }; 1240 1241 // .sampler 1242 { 1243 static const DataType samplerTypes[] = 1244 { 1245 // \note 1D images will be added by a later extension. 1246// TYPE_SAMPLER_1D, 1247 TYPE_SAMPLER_2D, 1248 TYPE_SAMPLER_CUBE, 1249 TYPE_SAMPLER_2D_ARRAY, 1250 TYPE_SAMPLER_3D, 1251// TYPE_SAMPLER_1D_SHADOW, 1252 TYPE_SAMPLER_2D_SHADOW, 1253 TYPE_SAMPLER_CUBE_SHADOW, 1254 TYPE_SAMPLER_2D_ARRAY_SHADOW, 1255// TYPE_INT_SAMPLER_1D, 1256 TYPE_INT_SAMPLER_2D, 1257 TYPE_INT_SAMPLER_CUBE, 1258 TYPE_INT_SAMPLER_2D_ARRAY, 1259 TYPE_INT_SAMPLER_3D, 1260// TYPE_UINT_SAMPLER_1D, 1261 TYPE_UINT_SAMPLER_2D, 1262 TYPE_UINT_SAMPLER_CUBE, 1263 TYPE_UINT_SAMPLER_2D_ARRAY, 1264 TYPE_UINT_SAMPLER_3D, 1265 TYPE_SAMPLER_CUBE_ARRAY, 1266 TYPE_SAMPLER_CUBE_ARRAY_SHADOW, 1267 TYPE_INT_SAMPLER_CUBE_ARRAY, 1268 TYPE_UINT_SAMPLER_CUBE_ARRAY 1269 }; 1270 1271 tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests"); 1272 addChild(samplerGroup); 1273 1274 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++) 1275 { 1276 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type; 1277 tcu::TestCaseGroup* const indexGroup = new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description); 1278 samplerGroup->addChild(indexGroup); 1279 1280 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 1281 { 1282 const ShaderType shaderType = shaderTypes[shaderTypeNdx].type; 1283 tcu::TestCaseGroup* const shaderGroup = new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, ""); 1284 indexGroup->addChild(shaderGroup); 1285 1286 for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++) 1287 { 1288 const DataType samplerType = samplerTypes[samplerTypeNdx]; 1289 const char* samplerName = getDataTypeName(samplerType); 1290 const string caseName = de::toLower(samplerName); 1291 1292 shaderGroup->addChild(new SamplerIndexingCase(m_context, caseName.c_str(), "", shaderType, samplerType, indexExprType)); 1293 } 1294 } 1295 } 1296 } 1297 1298 // .ubo / .ssbo / .atomic_counter 1299 { 1300 tcu::TestCaseGroup* const uboGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Uniform Block Instance Array Indexing Tests"); 1301 tcu::TestCaseGroup* const ssboGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Buffer Block Instance Array Indexing Tests"); 1302 tcu::TestCaseGroup* const acGroup = new tcu::TestCaseGroup(m_testCtx, "atomic_counter", "Atomic Counter Array Indexing Tests"); 1303 addChild(uboGroup); 1304 addChild(ssboGroup); 1305 addChild(acGroup); 1306 1307 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++) 1308 { 1309 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type; 1310 const char* indexExprName = indexingTypes[indexTypeNdx].name; 1311 const char* indexExprDesc = indexingTypes[indexTypeNdx].description; 1312 1313 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 1314 { 1315 const ShaderType shaderType = shaderTypes[shaderTypeNdx].type; 1316 const string name = string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name; 1317 1318 uboGroup->addChild (new BlockArrayIndexingCase (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_UNIFORM, indexExprType, shaderType)); 1319 acGroup->addChild (new AtomicCounterIndexingCase (m_context, name.c_str(), indexExprDesc, indexExprType, shaderType)); 1320 1321 if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1322 ssboGroup->addChild (new BlockArrayIndexingCase (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER, indexExprType, shaderType)); 1323 } 1324 } 1325 } 1326} 1327 1328} // Functional 1329} // gles31 1330} // deqp 1331