1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 The Khronos Group Inc. 6 * Copyright (c) 2015 Samsung Electronics Co., Ltd. 7 * Copyright (c) 2016 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Opaque type (sampler, buffer, atomic counter, ...) indexing tests. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "vktOpaqueTypeIndexingTests.hpp" 27 28 #include "tcuTexture.hpp" 29 #include "tcuTestLog.hpp" 30 #include "tcuVectorUtil.hpp" 31 #include "tcuTextureUtil.hpp" 32 33 #include "deStringUtil.hpp" 34 #include "deRandom.hpp" 35 36 #include "vktShaderExecutor.hpp" 37 38 #include <sstream> 39 40 namespace vkt 41 { 42 namespace shaderexecutor 43 { 44 45 namespace 46 { 47 48 enum IndexExprType 49 { 50 INDEX_EXPR_TYPE_CONST_LITERAL = 0, 51 INDEX_EXPR_TYPE_CONST_EXPRESSION, 52 INDEX_EXPR_TYPE_UNIFORM, 53 INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, 54 55 INDEX_EXPR_TYPE_LAST 56 }; 57 58 enum TextureType 59 { 60 TEXTURE_TYPE_1D = 0, 61 TEXTURE_TYPE_2D, 62 TEXTURE_TYPE_CUBE, 63 TEXTURE_TYPE_2D_ARRAY, 64 TEXTURE_TYPE_3D, 65 66 TEXTURE_TYPE_LAST 67 }; 68 69 class OpaqueTypeIndexingCase : public TestCase 70 { 71 public: 72 OpaqueTypeIndexingCase (tcu::TestContext& testCtx, 73 const char* name, 74 const char* description, 75 const glu::ShaderType shaderType, 76 const IndexExprType indexExprType); 77 virtual ~OpaqueTypeIndexingCase (void); 78 virtual void initPrograms (vk::SourceCollections& programCollection) const 79 { 80 m_executor->setShaderSources(programCollection); 81 } 82 virtual TestInstance* createInstance (Context& context) const = 0; 83 void init (void); 84 85 protected: 86 const char* m_name; 87 const glu::ShaderType m_shaderType; 88 const IndexExprType m_indexExprType; 89 ShaderSpec m_shaderSpec; 90 de::MovePtr<ShaderExecutor> m_executor; 91 UniformSetup* m_uniformSetup; 92 }; 93 94 class OpaqueTypeIndexingTestInstance : public TestInstance 95 { 96 public: 97 OpaqueTypeIndexingTestInstance (Context& context, 98 const glu::ShaderType shaderType, 99 const ShaderSpec& shaderSpec, 100 ShaderExecutor& executor, 101 const char* name, 102 UniformSetup* uniformSetup, 103 const IndexExprType indexExprType); 104 virtual ~OpaqueTypeIndexingTestInstance (void); 105 106 virtual tcu::TestStatus iterate (void) = 0; 107 108 protected: 109 void checkSupported (const VkDescriptorType descriptorType); 110 111 protected: 112 tcu::TestContext& m_testCtx; 113 const glu::ShaderType m_shaderType; 114 const ShaderSpec& m_shaderSpec; 115 const char* m_name; 116 const IndexExprType m_indexExprType; 117 ShaderExecutor& m_executor; 118 UniformSetup* m_uniformSetup; 119 }; 120 121 OpaqueTypeIndexingCase::OpaqueTypeIndexingCase (tcu::TestContext& testCtx, 122 const char* name, 123 const char* description, 124 const glu::ShaderType shaderType, 125 const IndexExprType indexExprType) 126 : TestCase (testCtx, name, description) 127 , m_name (name) 128 , m_shaderType (shaderType) 129 , m_indexExprType (indexExprType) 130 , m_executor (DE_NULL) 131 , m_uniformSetup (new UniformSetup()) 132 { 133 } 134 135 OpaqueTypeIndexingCase::~OpaqueTypeIndexingCase (void) 136 { 137 } 138 139 void OpaqueTypeIndexingCase::init (void) 140 { 141 DE_ASSERT(!m_executor); 142 143 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_shaderType, m_shaderSpec)); 144 m_testCtx.getLog() << *m_executor; 145 } 146 147 OpaqueTypeIndexingTestInstance::OpaqueTypeIndexingTestInstance (Context& context, 148 const glu::ShaderType shaderType, 149 const ShaderSpec& shaderSpec, 150 ShaderExecutor& executor, 151 const char* name, 152 UniformSetup* uniformSetup, 153 const IndexExprType indexExprType) 154 : TestInstance (context) 155 , m_testCtx (context.getTestContext()) 156 , m_shaderType (shaderType) 157 , m_shaderSpec (shaderSpec) 158 , m_name (name) 159 , m_indexExprType (indexExprType) 160 , m_executor (executor) 161 , m_uniformSetup (uniformSetup) 162 { 163 } 164 165 OpaqueTypeIndexingTestInstance::~OpaqueTypeIndexingTestInstance (void) 166 { 167 } 168 169 void OpaqueTypeIndexingTestInstance::checkSupported (const VkDescriptorType descriptorType) 170 { 171 const VkPhysicalDeviceFeatures& deviceFeatures = m_context.getDeviceFeatures(); 172 173 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION) 174 { 175 switch (descriptorType) 176 { 177 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 178 if (!deviceFeatures.shaderSampledImageArrayDynamicIndexing) 179 TCU_THROW(NotSupportedError, "Dynamic indexing of sampler arrays is not supported"); 180 break; 181 182 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 183 if (!deviceFeatures.shaderUniformBufferArrayDynamicIndexing) 184 TCU_THROW(NotSupportedError, "Dynamic indexing of uniform buffer arrays is not supported"); 185 break; 186 187 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 188 if (!deviceFeatures.shaderStorageBufferArrayDynamicIndexing) 189 TCU_THROW(NotSupportedError, "Dynamic indexing of storage buffer arrays is not supported"); 190 break; 191 192 default: 193 break; 194 } 195 } 196 } 197 198 static deUint32 getFirstFreeBindingLocation (const glu::ShaderType shaderType) 199 { 200 deUint32 location; 201 202 switch (shaderType) 203 { 204 case glu::SHADERTYPE_TESSELLATION_CONTROL: 205 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 206 case glu::SHADERTYPE_COMPUTE: 207 // 0 - input buffer 208 // 1 - output buffer 209 location = 2u; 210 break; 211 212 default: 213 location = 0u; 214 break; 215 } 216 217 return location; 218 } 219 220 static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars, deUint32& bindingLocation) 221 { 222 for (int varNdx = 0; varNdx < numVars; varNdx++) 223 str << "layout(set = 0, binding = " << bindingLocation++ << ") uniform buf" << varNdx << " { highp int " << varPrefix << varNdx << "; }" << ";\n"; 224 } 225 226 static void uploadUniformIndices (UniformSetup* uniformSetup, int numIndices, const int* indices, deUint32& bindingLocation) 227 { 228 for (int varNdx = 0; varNdx < numIndices; varNdx++) 229 uniformSetup->addData(new UniformData<int>(bindingLocation++, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, indices[varNdx])); 230 } 231 232 static TextureType getTextureType (glu::DataType samplerType) 233 { 234 switch (samplerType) 235 { 236 case glu::TYPE_SAMPLER_1D: 237 case glu::TYPE_INT_SAMPLER_1D: 238 case glu::TYPE_UINT_SAMPLER_1D: 239 case glu::TYPE_SAMPLER_1D_SHADOW: 240 return TEXTURE_TYPE_1D; 241 242 case glu::TYPE_SAMPLER_2D: 243 case glu::TYPE_INT_SAMPLER_2D: 244 case glu::TYPE_UINT_SAMPLER_2D: 245 case glu::TYPE_SAMPLER_2D_SHADOW: 246 return TEXTURE_TYPE_2D; 247 248 case glu::TYPE_SAMPLER_CUBE: 249 case glu::TYPE_INT_SAMPLER_CUBE: 250 case glu::TYPE_UINT_SAMPLER_CUBE: 251 case glu::TYPE_SAMPLER_CUBE_SHADOW: 252 return TEXTURE_TYPE_CUBE; 253 254 case glu::TYPE_SAMPLER_2D_ARRAY: 255 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 256 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 257 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 258 return TEXTURE_TYPE_2D_ARRAY; 259 260 case glu::TYPE_SAMPLER_3D: 261 case glu::TYPE_INT_SAMPLER_3D: 262 case glu::TYPE_UINT_SAMPLER_3D: 263 return TEXTURE_TYPE_3D; 264 265 default: 266 throw tcu::InternalError("Invalid sampler type"); 267 } 268 } 269 270 static bool isShadowSampler (glu::DataType samplerType) 271 { 272 return samplerType == glu::TYPE_SAMPLER_1D_SHADOW || 273 samplerType == glu::TYPE_SAMPLER_2D_SHADOW || 274 samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW || 275 samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW; 276 } 277 278 static glu::DataType getSamplerOutputType (glu::DataType samplerType) 279 { 280 switch (samplerType) 281 { 282 case glu::TYPE_SAMPLER_1D: 283 case glu::TYPE_SAMPLER_2D: 284 case glu::TYPE_SAMPLER_CUBE: 285 case glu::TYPE_SAMPLER_2D_ARRAY: 286 case glu::TYPE_SAMPLER_3D: 287 return glu::TYPE_FLOAT_VEC4; 288 289 case glu::TYPE_SAMPLER_1D_SHADOW: 290 case glu::TYPE_SAMPLER_2D_SHADOW: 291 case glu::TYPE_SAMPLER_CUBE_SHADOW: 292 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW: 293 return glu::TYPE_FLOAT; 294 295 case glu::TYPE_INT_SAMPLER_1D: 296 case glu::TYPE_INT_SAMPLER_2D: 297 case glu::TYPE_INT_SAMPLER_CUBE: 298 case glu::TYPE_INT_SAMPLER_2D_ARRAY: 299 case glu::TYPE_INT_SAMPLER_3D: 300 return glu::TYPE_INT_VEC4; 301 302 case glu::TYPE_UINT_SAMPLER_1D: 303 case glu::TYPE_UINT_SAMPLER_2D: 304 case glu::TYPE_UINT_SAMPLER_CUBE: 305 case glu::TYPE_UINT_SAMPLER_2D_ARRAY: 306 case glu::TYPE_UINT_SAMPLER_3D: 307 return glu::TYPE_UINT_VEC4; 308 309 default: 310 throw tcu::InternalError("Invalid sampler type"); 311 } 312 } 313 314 static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType) 315 { 316 const glu::DataType outType = getSamplerOutputType(samplerType); 317 const glu::DataType outScalarType = glu::getDataTypeScalarType(outType); 318 319 switch (outScalarType) 320 { 321 case glu::TYPE_FLOAT: 322 if (isShadowSampler(samplerType)) 323 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); 324 else 325 return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); 326 327 case glu::TYPE_INT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8); 328 case glu::TYPE_UINT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8); 329 330 default: 331 throw tcu::InternalError("Invalid sampler type"); 332 } 333 } 334 335 static glu::DataType getSamplerCoordType (glu::DataType samplerType) 336 { 337 const TextureType texType = getTextureType(samplerType); 338 int numCoords = 0; 339 340 switch (texType) 341 { 342 case TEXTURE_TYPE_1D: numCoords = 1; break; 343 case TEXTURE_TYPE_2D: numCoords = 2; break; 344 case TEXTURE_TYPE_2D_ARRAY: numCoords = 3; break; 345 case TEXTURE_TYPE_CUBE: numCoords = 3; break; 346 case TEXTURE_TYPE_3D: numCoords = 3; break; 347 default: 348 DE_ASSERT(false); 349 } 350 351 if (isShadowSampler(samplerType)) 352 numCoords += 1; 353 354 DE_ASSERT(de::inRange(numCoords, 1, 4)); 355 356 return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords); 357 } 358 359 static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd) 360 { 361 DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1); 362 363 if (access.getFormat().order == tcu::TextureFormat::D) 364 { 365 // \note Texture uses odd values, lookup even values to avoid precision issues. 366 const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f }; 367 368 for (int ndx = 0; ndx < access.getWidth(); ndx++) 369 access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0); 370 } 371 else 372 { 373 TCU_CHECK_INTERNAL(access.getFormat().order == tcu::TextureFormat::RGBA && access.getFormat().getPixelSize() == 4); 374 375 for (int ndx = 0; ndx < access.getWidth(); ndx++) 376 *((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32(); 377 } 378 } 379 380 static vk::VkImageType getVkImageType (TextureType texType) 381 { 382 switch (texType) 383 { 384 case TEXTURE_TYPE_1D: return vk::VK_IMAGE_TYPE_1D; 385 case TEXTURE_TYPE_2D: 386 case TEXTURE_TYPE_2D_ARRAY: return vk::VK_IMAGE_TYPE_2D; 387 case TEXTURE_TYPE_CUBE: return vk::VK_IMAGE_TYPE_2D; 388 case TEXTURE_TYPE_3D: return vk::VK_IMAGE_TYPE_3D; 389 default: 390 DE_FATAL("Impossible"); 391 return (vk::VkImageType)0; 392 } 393 } 394 395 static vk::VkImageViewType getVkImageViewType (TextureType texType) 396 { 397 switch (texType) 398 { 399 case TEXTURE_TYPE_1D: return vk::VK_IMAGE_VIEW_TYPE_1D; 400 case TEXTURE_TYPE_2D: return vk::VK_IMAGE_VIEW_TYPE_2D; 401 case TEXTURE_TYPE_2D_ARRAY: return vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY; 402 case TEXTURE_TYPE_CUBE: return vk::VK_IMAGE_VIEW_TYPE_CUBE; 403 case TEXTURE_TYPE_3D: return vk::VK_IMAGE_VIEW_TYPE_3D; 404 default: 405 DE_FATAL("Impossible"); 406 return (vk::VkImageViewType)0; 407 } 408 } 409 410 // SamplerIndexingCaseInstance 411 412 class SamplerIndexingCaseInstance : public OpaqueTypeIndexingTestInstance 413 { 414 public: 415 enum 416 { 417 NUM_INVOCATIONS = 64, 418 NUM_SAMPLERS = 8, 419 NUM_LOOKUPS = 4 420 }; 421 422 SamplerIndexingCaseInstance (Context& context, 423 const glu::ShaderType shaderType, 424 const ShaderSpec& shaderSpec, 425 ShaderExecutor& executor, 426 const char* name, 427 glu::DataType samplerType, 428 const IndexExprType indexExprType, 429 UniformSetup* uniformSetup, 430 const std::vector<int>& lookupIndices); 431 virtual ~SamplerIndexingCaseInstance (void); 432 433 virtual tcu::TestStatus iterate (void); 434 435 protected: 436 const glu::DataType m_samplerType; 437 const std::vector<int>& m_lookupIndices; 438 }; 439 440 SamplerIndexingCaseInstance::SamplerIndexingCaseInstance (Context& context, 441 const glu::ShaderType shaderType, 442 const ShaderSpec& shaderSpec, 443 ShaderExecutor& executor, 444 const char* name, 445 glu::DataType samplerType, 446 const IndexExprType indexExprType, 447 UniformSetup* uniformSetup, 448 const std::vector<int>& lookupIndices) 449 : OpaqueTypeIndexingTestInstance (context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType) 450 , m_samplerType (samplerType) 451 , m_lookupIndices (lookupIndices) 452 { 453 } 454 455 SamplerIndexingCaseInstance::~SamplerIndexingCaseInstance (void) 456 { 457 } 458 459 bool isIntegerFormat (const tcu::TextureFormat& format) 460 { 461 const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(format.type); 462 463 return chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER || 464 chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER; 465 } 466 467 tcu::TestStatus SamplerIndexingCaseInstance::iterate (void) 468 { 469 const int numInvocations = SamplerIndexingCaseInstance::NUM_INVOCATIONS; 470 const int numSamplers = SamplerIndexingCaseInstance::NUM_SAMPLERS; 471 const int numLookups = SamplerIndexingCaseInstance::NUM_LOOKUPS; 472 const glu::DataType coordType = getSamplerCoordType(m_samplerType); 473 const glu::DataType outputType = getSamplerOutputType(m_samplerType); 474 const tcu::TextureFormat texFormat = getSamplerTextureFormat(m_samplerType); 475 const int outLookupStride = numInvocations*getDataTypeScalarSize(outputType); 476 std::vector<float> coords; 477 std::vector<deUint32> outData; 478 std::vector<deUint8> texData (numSamplers * texFormat.getPixelSize()); 479 const tcu::PixelBufferAccess refTexAccess (texFormat, numSamplers, 1, 1, &texData[0]); 480 de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 481 const TextureType texType = getTextureType(m_samplerType); 482 const vk::VkImageType imageType = getVkImageType(texType); 483 const vk::VkImageViewType imageViewType = getVkImageViewType(texType); 484 const tcu::Sampler::FilterMode filterMode = (isShadowSampler(m_samplerType) || isIntegerFormat(texFormat)) ? tcu::Sampler::NEAREST : tcu::Sampler::LINEAR; 485 const tcu::Sampler refSampler = isShadowSampler(m_samplerType) 486 ? tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 487 filterMode, filterMode, 0.0f, false /* non-normalized */, 488 tcu::Sampler::COMPAREMODE_LESS) 489 : tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 490 filterMode, filterMode); 491 492 checkSupported(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); 493 494 coords.resize(numInvocations * getDataTypeScalarSize(coordType)); 495 496 if (texType == TEXTURE_TYPE_CUBE) 497 { 498 if (isShadowSampler(m_samplerType)) 499 { 500 for (size_t i = 0; i < coords.size() / 4; i++) 501 { 502 coords[4 * i] = 1.0f; 503 coords[4 * i + 1] = coords[4 * i + 2] = coords[4 * i + 3] = 0.0f; 504 } 505 } 506 else 507 { 508 for (size_t i = 0; i < coords.size() / 3; i++) 509 { 510 coords[3 * i] = 1.0f; 511 coords[3 * i + 1] = coords[3 * i + 2] = 0.0f; 512 } 513 } 514 } 515 516 if (isShadowSampler(m_samplerType)) 517 { 518 // Use different comparison value per invocation. 519 // \note Texture uses odd values, comparison even values. 520 const int numCoordComps = getDataTypeScalarSize(coordType); 521 const float cmpValues[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }; 522 523 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 524 coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues)); 525 } 526 527 fillTextureData(refTexAccess, rnd); 528 529 outData.resize(numLookups*outLookupStride); 530 531 { 532 std::vector<void*> inputs; 533 std::vector<void*> outputs; 534 std::vector<int> expandedIndices; 535 deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType); 536 537 inputs.push_back(&coords[0]); 538 539 m_uniformSetup->addData(new SamplerUniformData(bindingLocation++, (deUint32)numSamplers, refSampler, texFormat, tcu::IVec3(1, 1, 1), imageType, imageViewType, &texData[0])); 540 541 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 542 { 543 expandedIndices.resize(numInvocations * m_lookupIndices.size()); 544 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 545 { 546 for (int invNdx = 0; invNdx < numInvocations; invNdx++) 547 expandedIndices[lookupNdx*numInvocations + invNdx] = m_lookupIndices[lookupNdx]; 548 } 549 550 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 551 inputs.push_back(&expandedIndices[lookupNdx*numInvocations]); 552 } 553 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 554 uploadUniformIndices(m_uniformSetup, numLookups, &m_lookupIndices[0], bindingLocation); 555 556 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 557 outputs.push_back(&outData[outLookupStride*lookupNdx]); 558 559 m_executor.setUniforms(m_uniformSetup); 560 561 m_executor.execute(m_context, numInvocations, &inputs[0], &outputs[0]); 562 } 563 564 { 565 tcu::TestLog& log = m_context.getTestContext().getLog(); 566 tcu::TestStatus testResult = tcu::TestStatus::pass("Pass"); 567 568 if (isShadowSampler(m_samplerType)) 569 { 570 const int numCoordComps = getDataTypeScalarSize(coordType); 571 572 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1); 573 574 // Each invocation may have different results. 575 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 576 { 577 const float coord = coords[invocationNdx*numCoordComps + (numCoordComps-1)]; 578 579 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 580 { 581 const int texNdx = m_lookupIndices[lookupNdx]; 582 const float result = *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]); 583 const float reference = refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0)); 584 585 if (de::abs(result-reference) > 0.005f) 586 { 587 log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected " 588 << reference << ", got " << result 589 << tcu::TestLog::EndMessage; 590 591 if (testResult.getCode() == QP_TEST_RESULT_PASS) 592 testResult = tcu::TestStatus::fail("Got invalid lookup result"); 593 } 594 } 595 } 596 } 597 else 598 { 599 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4); 600 601 // Validate results from first invocation 602 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 603 { 604 const int texNdx = m_lookupIndices[lookupNdx]; 605 const deUint8* resPtr = (const deUint8*)&outData[lookupNdx*outLookupStride]; 606 bool isOk; 607 608 if (outputType == glu::TYPE_FLOAT_VEC4) 609 { 610 const float threshold = 1.0f / 256.0f; 611 const tcu::Vec4 reference = refTexAccess.getPixel(texNdx, 0); 612 const float* floatPtr = (const float*)resPtr; 613 const tcu::Vec4 result (floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]); 614 615 isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold))); 616 617 if (!isOk) 618 { 619 log << tcu::TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected " 620 << reference << ", got " << result 621 << tcu::TestLog::EndMessage; 622 } 623 } 624 else 625 { 626 const tcu::UVec4 reference = refTexAccess.getPixelUint(texNdx, 0); 627 const deUint32* uintPtr = (const deUint32*)resPtr; 628 const tcu::UVec4 result (uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]); 629 630 isOk = boolAll(equal(reference, result)); 631 632 if (!isOk) 633 { 634 log << tcu::TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected " 635 << reference << ", got " << result 636 << tcu::TestLog::EndMessage; 637 } 638 } 639 640 if (!isOk && testResult.getCode() == QP_TEST_RESULT_PASS) 641 testResult = tcu::TestStatus::fail("Got invalid lookup result"); 642 } 643 644 // Check results of other invocations against first one 645 for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++) 646 { 647 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++) 648 { 649 const deUint32* refPtr = &outData[lookupNdx*outLookupStride]; 650 const deUint32* resPtr = refPtr + invocationNdx*4; 651 bool isOk = true; 652 653 for (int ndx = 0; ndx < 4; ndx++) 654 isOk = isOk && (refPtr[ndx] == resPtr[ndx]); 655 656 if (!isOk) 657 { 658 log << tcu::TestLog::Message << "ERROR: invocation " << invocationNdx << " result " 659 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4)) 660 << " for lookup " << lookupNdx << " doesn't match result from first invocation " 661 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4)) 662 << tcu::TestLog::EndMessage; 663 664 if (testResult.getCode() == QP_TEST_RESULT_PASS) 665 testResult = tcu::TestStatus::fail("Inconsistent lookup results"); 666 } 667 } 668 } 669 } 670 671 return testResult; 672 } 673 } 674 675 class SamplerIndexingCase : public OpaqueTypeIndexingCase 676 { 677 public: 678 SamplerIndexingCase (tcu::TestContext& testCtx, 679 const char* name, 680 const char* description, 681 const glu::ShaderType shaderType, 682 glu::DataType samplerType, 683 IndexExprType indexExprType); 684 virtual ~SamplerIndexingCase (void); 685 686 virtual TestInstance* createInstance (Context& ctx) const; 687 688 private: 689 SamplerIndexingCase (const SamplerIndexingCase&); 690 SamplerIndexingCase& operator= (const SamplerIndexingCase&); 691 692 void createShaderSpec (void); 693 694 const glu::DataType m_samplerType; 695 const int m_numSamplers; 696 const int m_numLookups; 697 std::vector<int> m_lookupIndices; 698 }; 699 700 SamplerIndexingCase::SamplerIndexingCase (tcu::TestContext& testCtx, 701 const char* name, 702 const char* description, 703 const glu::ShaderType shaderType, 704 glu::DataType samplerType, 705 IndexExprType indexExprType) 706 : OpaqueTypeIndexingCase (testCtx, name, description, shaderType, indexExprType) 707 , m_samplerType (samplerType) 708 , m_numSamplers (SamplerIndexingCaseInstance::NUM_SAMPLERS) 709 , m_numLookups (SamplerIndexingCaseInstance::NUM_LOOKUPS) 710 , m_lookupIndices (m_numLookups) 711 { 712 createShaderSpec(); 713 init(); 714 } 715 716 SamplerIndexingCase::~SamplerIndexingCase (void) 717 { 718 } 719 720 TestInstance* SamplerIndexingCase::createInstance (Context& ctx) const 721 { 722 return new SamplerIndexingCaseInstance(ctx, 723 m_shaderType, 724 m_shaderSpec, 725 *m_executor, 726 m_name, 727 m_samplerType, 728 m_indexExprType, 729 m_uniformSetup, 730 m_lookupIndices); 731 } 732 733 void SamplerIndexingCase::createShaderSpec (void) 734 { 735 de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 736 deUint32 binding = getFirstFreeBindingLocation(m_shaderType); 737 const char* samplersName = "texSampler"; 738 const char* coordsName = "coords"; 739 const char* indicesPrefix = "index"; 740 const char* resultPrefix = "result"; 741 const glu::DataType coordType = getSamplerCoordType(m_samplerType); 742 const glu::DataType outType = getSamplerOutputType(m_samplerType); 743 std::ostringstream global, code; 744 745 for (int ndx = 0; ndx < m_numLookups; ndx++) 746 m_lookupIndices[ndx] = rnd.getInt(0, m_numSamplers-1); 747 748 m_shaderSpec.inputs.push_back(Symbol(coordsName, glu::VarType(coordType, glu::PRECISION_HIGHP))); 749 750 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL) 751 global << "#extension GL_EXT_gpu_shader5 : require\n"; 752 753 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 754 global << "const highp int indexBase = 1;\n"; 755 756 global << 757 "layout(set = 0, binding = " << binding++ << ") uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << m_numSamplers << "];\n"; 758 759 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 760 { 761 for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++) 762 { 763 const std::string varName = indicesPrefix + de::toString(lookupNdx); 764 m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP))); 765 } 766 } 767 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 768 declareUniformIndexVars(global, indicesPrefix, m_numLookups, binding); 769 770 for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++) 771 { 772 const std::string varName = resultPrefix + de::toString(lookupNdx); 773 m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(outType, glu::PRECISION_HIGHP))); 774 } 775 776 for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++) 777 { 778 code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "["; 779 780 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 781 code << m_lookupIndices[lookupNdx]; 782 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 783 code << "indexBase + " << (m_lookupIndices[lookupNdx]-1); 784 else 785 code << indicesPrefix << lookupNdx; 786 787 code << "], " << coordsName << ");\n"; 788 } 789 790 m_shaderSpec.globalDeclarations = global.str(); 791 m_shaderSpec.source = code.str(); 792 } 793 794 enum BlockType 795 { 796 BLOCKTYPE_UNIFORM = 0, 797 BLOCKTYPE_BUFFER, 798 799 BLOCKTYPE_LAST 800 }; 801 802 class BlockArrayIndexingCaseInstance : public OpaqueTypeIndexingTestInstance 803 { 804 public: 805 enum 806 { 807 NUM_INVOCATIONS = 32, 808 NUM_INSTANCES = 4, 809 NUM_READS = 4 810 }; 811 812 BlockArrayIndexingCaseInstance (Context& context, 813 const glu::ShaderType shaderType, 814 const ShaderSpec& shaderSpec, 815 ShaderExecutor& executor, 816 const char* name, 817 BlockType blockType, 818 const IndexExprType indexExprType, 819 UniformSetup* uniformSetup, 820 const std::vector<int>& readIndices, 821 const std::vector<deUint32>& inValues); 822 virtual ~BlockArrayIndexingCaseInstance (void); 823 824 virtual tcu::TestStatus iterate (void); 825 826 private: 827 const BlockType m_blockType; 828 const std::vector<int>& m_readIndices; 829 const std::vector<deUint32>& m_inValues; 830 }; 831 832 BlockArrayIndexingCaseInstance::BlockArrayIndexingCaseInstance (Context& context, 833 const glu::ShaderType shaderType, 834 const ShaderSpec& shaderSpec, 835 ShaderExecutor& executor, 836 const char* name, 837 BlockType blockType, 838 const IndexExprType indexExprType, 839 UniformSetup* uniformSetup, 840 const std::vector<int>& readIndices, 841 const std::vector<deUint32>& inValues) 842 : OpaqueTypeIndexingTestInstance (context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType) 843 , m_blockType (blockType) 844 , m_readIndices (readIndices) 845 , m_inValues (inValues) 846 { 847 } 848 849 BlockArrayIndexingCaseInstance::~BlockArrayIndexingCaseInstance (void) 850 { 851 } 852 853 tcu::TestStatus BlockArrayIndexingCaseInstance::iterate (void) 854 { 855 const int numInvocations = NUM_INVOCATIONS; 856 const int numReads = NUM_READS; 857 std::vector<deUint32> outValues (numInvocations*numReads); 858 859 { 860 tcu::TestLog& log = m_context.getTestContext().getLog(); 861 tcu::TestStatus testResult = tcu::TestStatus::pass("Pass"); 862 std::vector<int> expandedIndices; 863 std::vector<void*> inputs; 864 std::vector<void*> outputs; 865 deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType); 866 VkDescriptorType descriptorType = m_blockType == BLOCKTYPE_UNIFORM ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 867 868 checkSupported(descriptorType); 869 870 m_uniformSetup->addData(new UniformArrayData<deUint32>(bindingLocation++, descriptorType, m_inValues)); 871 872 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 873 { 874 expandedIndices.resize(numInvocations * m_readIndices.size()); 875 876 for (int readNdx = 0; readNdx < numReads; readNdx++) 877 { 878 int* dst = &expandedIndices[numInvocations*readNdx]; 879 std::fill(dst, dst+numInvocations, m_readIndices[readNdx]); 880 } 881 882 for (int readNdx = 0; readNdx < numReads; readNdx++) 883 inputs.push_back(&expandedIndices[readNdx*numInvocations]); 884 } 885 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 886 uploadUniformIndices(m_uniformSetup, numReads, &m_readIndices[0], bindingLocation); 887 888 for (int readNdx = 0; readNdx < numReads; readNdx++) 889 outputs.push_back(&outValues[readNdx*numInvocations]); 890 891 m_executor.setUniforms(m_uniformSetup); 892 893 m_executor.execute(m_context, numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]); 894 895 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 896 { 897 for (int readNdx = 0; readNdx < numReads; readNdx++) 898 { 899 const deUint32 refValue = m_inValues[m_readIndices[readNdx]]; 900 const deUint32 resValue = outValues[readNdx*numInvocations + invocationNdx]; 901 902 if (refValue != resValue) 903 { 904 log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx 905 << ", read " << readNdx << ": expected " 906 << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue) 907 << tcu::TestLog::EndMessage; 908 909 if (testResult.getCode() == QP_TEST_RESULT_PASS) 910 testResult = tcu::TestStatus::fail("Invalid result value"); 911 } 912 } 913 } 914 915 return testResult; 916 } 917 } 918 919 class BlockArrayIndexingCase : public OpaqueTypeIndexingCase 920 { 921 public: 922 BlockArrayIndexingCase (tcu::TestContext& testCtx, 923 const char* name, 924 const char* description, 925 BlockType blockType, 926 IndexExprType indexExprType, 927 const glu::ShaderType shaderType); 928 virtual ~BlockArrayIndexingCase (void); 929 930 virtual TestInstance* createInstance (Context& ctx) const; 931 932 private: 933 BlockArrayIndexingCase (const BlockArrayIndexingCase&); 934 BlockArrayIndexingCase& operator= (const BlockArrayIndexingCase&); 935 936 void createShaderSpec (void); 937 938 const BlockType m_blockType; 939 std::vector<int> m_readIndices; 940 std::vector<deUint32> m_inValues; 941 }; 942 943 BlockArrayIndexingCase::BlockArrayIndexingCase (tcu::TestContext& testCtx, 944 const char* name, 945 const char* description, 946 BlockType blockType, 947 IndexExprType indexExprType, 948 const glu::ShaderType shaderType) 949 : OpaqueTypeIndexingCase (testCtx, name, description, shaderType, indexExprType) 950 , m_blockType (blockType) 951 , m_readIndices (BlockArrayIndexingCaseInstance::NUM_READS) 952 , m_inValues (BlockArrayIndexingCaseInstance::NUM_INSTANCES) 953 { 954 createShaderSpec(); 955 init(); 956 } 957 958 BlockArrayIndexingCase::~BlockArrayIndexingCase (void) 959 { 960 } 961 962 TestInstance* BlockArrayIndexingCase::createInstance (Context& ctx) const 963 { 964 return new BlockArrayIndexingCaseInstance(ctx, 965 m_shaderType, 966 m_shaderSpec, 967 *m_executor, 968 m_name, 969 m_blockType, 970 m_indexExprType, 971 m_uniformSetup, 972 m_readIndices, 973 m_inValues); 974 } 975 976 void BlockArrayIndexingCase::createShaderSpec (void) 977 { 978 const int numInstances = BlockArrayIndexingCaseInstance::NUM_INSTANCES; 979 const int numReads = BlockArrayIndexingCaseInstance::NUM_READS; 980 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType)); 981 deUint32 binding = getFirstFreeBindingLocation(m_shaderType); 982 const char* blockName = "Block"; 983 const char* instanceName = "block"; 984 const char* indicesPrefix = "index"; 985 const char* resultPrefix = "result"; 986 const char* interfaceName = m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer"; 987 std::ostringstream global, code; 988 989 for (int readNdx = 0; readNdx < numReads; readNdx++) 990 m_readIndices[readNdx] = rnd.getInt(0, numInstances-1); 991 992 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 993 m_inValues[instanceNdx] = rnd.getUint32(); 994 995 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL) 996 global << "#extension GL_EXT_gpu_shader5 : require\n"; 997 998 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 999 global << "const highp int indexBase = 1;\n"; 1000 1001 global << 1002 "layout(set = 0, binding = " << binding++ << ") " << interfaceName << " " << blockName << "\n" 1003 "{\n" 1004 " highp uint value;\n" 1005 "} " << instanceName << "[" << numInstances << "];\n"; 1006 1007 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 1008 { 1009 for (int readNdx = 0; readNdx < numReads; readNdx++) 1010 { 1011 const std::string varName = indicesPrefix + de::toString(readNdx); 1012 m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP))); 1013 } 1014 } 1015 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 1016 declareUniformIndexVars(global, indicesPrefix, numReads, binding); 1017 1018 for (int readNdx = 0; readNdx < numReads; readNdx++) 1019 { 1020 const std::string varName = resultPrefix + de::toString(readNdx); 1021 m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 1022 } 1023 1024 for (int readNdx = 0; readNdx < numReads; readNdx++) 1025 { 1026 code << resultPrefix << readNdx << " = " << instanceName << "["; 1027 1028 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 1029 code << m_readIndices[readNdx]; 1030 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1031 code << "indexBase + " << (m_readIndices[readNdx]-1); 1032 else 1033 code << indicesPrefix << readNdx; 1034 1035 code << "].value;\n"; 1036 } 1037 1038 m_shaderSpec.globalDeclarations = global.str(); 1039 m_shaderSpec.source = code.str(); 1040 } 1041 1042 class AtomicCounterIndexingCaseInstance : public OpaqueTypeIndexingTestInstance 1043 { 1044 public: 1045 enum 1046 { 1047 NUM_INVOCATIONS = 32, 1048 NUM_COUNTERS = 4, 1049 NUM_OPS = 4 1050 }; 1051 1052 AtomicCounterIndexingCaseInstance (Context& context, 1053 const glu::ShaderType shaderType, 1054 const ShaderSpec& shaderSpec, 1055 ShaderExecutor& executor, 1056 const char* name, 1057 UniformSetup* uniformSetup, 1058 const std::vector<int>& opIndices, 1059 const IndexExprType indexExprType); 1060 virtual ~AtomicCounterIndexingCaseInstance (void); 1061 1062 virtual tcu::TestStatus iterate (void); 1063 1064 private: 1065 const std::vector<int>& m_opIndices; 1066 }; 1067 1068 AtomicCounterIndexingCaseInstance::AtomicCounterIndexingCaseInstance (Context& context, 1069 const glu::ShaderType shaderType, 1070 const ShaderSpec& shaderSpec, 1071 ShaderExecutor& executor, 1072 const char* name, 1073 UniformSetup* uniformSetup, 1074 const std::vector<int>& opIndices, 1075 const IndexExprType indexExprType) 1076 : OpaqueTypeIndexingTestInstance (context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType) 1077 , m_opIndices (opIndices) 1078 { 1079 } 1080 1081 AtomicCounterIndexingCaseInstance::~AtomicCounterIndexingCaseInstance (void) 1082 { 1083 } 1084 1085 tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void) 1086 { 1087 // \todo [2015-12-02 elecro] Add vertexPipelineStoresAndAtomics feature check. 1088 const int numInvocations = NUM_INVOCATIONS; 1089 const int numCounters = NUM_COUNTERS; 1090 const int numOps = NUM_OPS; 1091 std::vector<int> expandedIndices; 1092 std::vector<void*> inputs; 1093 std::vector<void*> outputs; 1094 std::vector<deUint32> outValues (numInvocations*numOps); 1095 deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType); 1096 1097 const deUint32 atomicCounterLocation = bindingLocation++; 1098 1099 checkSupported(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); 1100 1101 { 1102 DE_ASSERT(numCounters <= 4); 1103 // Add the atomic counters' base value, all zero. 1104 m_uniformSetup->addData(new UniformData<tcu::Mat4>(atomicCounterLocation, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, tcu::Mat4(0.0))); 1105 1106 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 1107 { 1108 expandedIndices.resize(numInvocations * m_opIndices.size()); 1109 1110 for (int opNdx = 0; opNdx < numOps; opNdx++) 1111 { 1112 int* dst = &expandedIndices[numInvocations*opNdx]; 1113 std::fill(dst, dst+numInvocations, m_opIndices[opNdx]); 1114 } 1115 1116 for (int opNdx = 0; opNdx < numOps; opNdx++) 1117 inputs.push_back(&expandedIndices[opNdx*numInvocations]); 1118 } 1119 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 1120 uploadUniformIndices(m_uniformSetup, numOps, &m_opIndices[0], bindingLocation); 1121 1122 for (int opNdx = 0; opNdx < numOps; opNdx++) 1123 outputs.push_back(&outValues[opNdx*numInvocations]); 1124 1125 m_executor.setUniforms(m_uniformSetup); 1126 1127 m_executor.execute(m_context, numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]); 1128 } 1129 1130 { 1131 tcu::TestLog& log = m_context.getTestContext().getLog(); 1132 tcu::TestStatus testResult = tcu::TestStatus::pass("Pass"); 1133 std::vector<int> numHits (numCounters, 0); // Number of hits per counter. 1134 std::vector<deUint32> counterValues (numCounters); 1135 std::vector<std::vector<bool> > counterMasks (numCounters); 1136 1137 for (int opNdx = 0; opNdx < numOps; opNdx++) 1138 numHits[m_opIndices[opNdx]] += 1; 1139 1140 // Read counter values 1141 { 1142 const void* mapPtr = m_executor.getBufferPtr(atomicCounterLocation); 1143 DE_ASSERT(mapPtr != DE_NULL); 1144 std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]); 1145 } 1146 1147 // Verify counter values 1148 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1149 { 1150 const deUint32 refCount = (deUint32)(numHits[counterNdx]*numInvocations); 1151 const deUint32 resCount = counterValues[counterNdx]; 1152 1153 if (refCount != resCount) 1154 { 1155 log << tcu::TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount 1156 << ", expected " << refCount 1157 << tcu::TestLog::EndMessage; 1158 1159 if (testResult.getCode() == QP_TEST_RESULT_PASS) 1160 testResult = tcu::TestStatus::fail("Invalid atomic counter value"); 1161 } 1162 } 1163 1164 // Allocate bitmasks - one bit per each valid result value 1165 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1166 { 1167 const int counterValue = numHits[counterNdx]*numInvocations; 1168 counterMasks[counterNdx].resize(counterValue, false); 1169 } 1170 1171 // Verify result values from shaders 1172 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++) 1173 { 1174 for (int opNdx = 0; opNdx < numOps; opNdx++) 1175 { 1176 const int counterNdx = m_opIndices[opNdx]; 1177 const deUint32 resValue = outValues[opNdx*numInvocations + invocationNdx]; 1178 const bool rangeOk = de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size()); 1179 const bool notSeen = rangeOk && !counterMasks[counterNdx][resValue]; 1180 const bool isOk = rangeOk && notSeen; 1181 1182 if (!isOk) 1183 { 1184 log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx 1185 << ", op " << opNdx << ": got invalid result value " 1186 << resValue 1187 << tcu::TestLog::EndMessage; 1188 1189 if (testResult.getCode() == QP_TEST_RESULT_PASS) 1190 testResult = tcu::TestStatus::fail("Invalid result value"); 1191 } 1192 else 1193 { 1194 // Mark as used - no other invocation should see this value from same counter. 1195 counterMasks[counterNdx][resValue] = true; 1196 } 1197 } 1198 } 1199 1200 if (testResult.getCode() == QP_TEST_RESULT_PASS) 1201 { 1202 // Consistency check - all masks should be 1 now 1203 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++) 1204 { 1205 for (std::vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++) 1206 TCU_CHECK_INTERNAL(*i); 1207 } 1208 } 1209 1210 return testResult; 1211 } 1212 } 1213 1214 class AtomicCounterIndexingCase : public OpaqueTypeIndexingCase 1215 { 1216 public: 1217 AtomicCounterIndexingCase (tcu::TestContext& testCtx, 1218 const char* name, 1219 const char* description, 1220 IndexExprType indexExprType, 1221 const glu::ShaderType shaderType); 1222 virtual ~AtomicCounterIndexingCase (void); 1223 1224 virtual TestInstance* createInstance (Context& ctx) const; 1225 1226 private: 1227 AtomicCounterIndexingCase (const BlockArrayIndexingCase&); 1228 AtomicCounterIndexingCase& operator= (const BlockArrayIndexingCase&); 1229 1230 void createShaderSpec (void); 1231 1232 std::vector<int> m_opIndices; 1233 }; 1234 1235 AtomicCounterIndexingCase::AtomicCounterIndexingCase (tcu::TestContext& testCtx, 1236 const char* name, 1237 const char* description, 1238 IndexExprType indexExprType, 1239 const glu::ShaderType shaderType) 1240 : OpaqueTypeIndexingCase (testCtx, name, description, shaderType, indexExprType) 1241 , m_opIndices (AtomicCounterIndexingCaseInstance::NUM_OPS) 1242 { 1243 createShaderSpec(); 1244 init(); 1245 } 1246 1247 AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void) 1248 { 1249 } 1250 1251 TestInstance* AtomicCounterIndexingCase::createInstance (Context& ctx) const 1252 { 1253 return new AtomicCounterIndexingCaseInstance(ctx, 1254 m_shaderType, 1255 m_shaderSpec, 1256 *m_executor, 1257 m_name, 1258 m_uniformSetup, 1259 m_opIndices, 1260 m_indexExprType); 1261 } 1262 1263 void AtomicCounterIndexingCase::createShaderSpec (void) 1264 { 1265 const int numCounters = AtomicCounterIndexingCaseInstance::NUM_COUNTERS; 1266 const int numOps = AtomicCounterIndexingCaseInstance::NUM_OPS; 1267 deUint32 binding = getFirstFreeBindingLocation(m_shaderType); 1268 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType)); 1269 1270 for (int opNdx = 0; opNdx < numOps; opNdx++) 1271 m_opIndices[opNdx] = rnd.getInt(0, numOps-1); 1272 1273 { 1274 const char* indicesPrefix = "index"; 1275 const char* resultPrefix = "result"; 1276 std::ostringstream global, code; 1277 1278 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL) 1279 global << "#extension GL_EXT_gpu_shader5 : require\n"; 1280 1281 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1282 global << "const highp int indexBase = 1;\n"; 1283 1284 global << 1285 "layout(set = 0, binding = " << binding++ << ") buffer AtomicBuffer { highp uint counter[" << numCounters << "]; };\n"; 1286 1287 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM) 1288 { 1289 for (int opNdx = 0; opNdx < numOps; opNdx++) 1290 { 1291 const std::string varName = indicesPrefix + de::toString(opNdx); 1292 m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP))); 1293 } 1294 } 1295 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM) 1296 declareUniformIndexVars(global, indicesPrefix, numOps, binding); 1297 1298 for (int opNdx = 0; opNdx < numOps; opNdx++) 1299 { 1300 const std::string varName = resultPrefix + de::toString(opNdx); 1301 m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 1302 } 1303 1304 for (int opNdx = 0; opNdx < numOps; opNdx++) 1305 { 1306 code << resultPrefix << opNdx << " = atomicAdd(counter["; 1307 1308 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL) 1309 code << m_opIndices[opNdx]; 1310 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1311 code << "indexBase + " << (m_opIndices[opNdx]-1); 1312 else 1313 code << indicesPrefix << opNdx; 1314 1315 code << "], uint(1));\n"; 1316 } 1317 1318 m_shaderSpec.globalDeclarations = global.str(); 1319 m_shaderSpec.source = code.str(); 1320 } 1321 } 1322 1323 class OpaqueTypeIndexingTests : public tcu::TestCaseGroup 1324 { 1325 public: 1326 OpaqueTypeIndexingTests (tcu::TestContext& testCtx); 1327 virtual ~OpaqueTypeIndexingTests (void); 1328 1329 virtual void init (void); 1330 1331 private: 1332 OpaqueTypeIndexingTests (const OpaqueTypeIndexingTests&); 1333 OpaqueTypeIndexingTests& operator= (const OpaqueTypeIndexingTests&); 1334 }; 1335 1336 OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (tcu::TestContext& testCtx) 1337 : tcu::TestCaseGroup(testCtx, "opaque_type_indexing", "Opaque Type Indexing Tests") 1338 { 1339 } 1340 1341 OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void) 1342 { 1343 } 1344 1345 void OpaqueTypeIndexingTests::init (void) 1346 { 1347 static const struct 1348 { 1349 IndexExprType type; 1350 const char* name; 1351 const char* description; 1352 } indexingTypes[] = 1353 { 1354 { INDEX_EXPR_TYPE_CONST_LITERAL, "const_literal", "Indexing by constant literal" }, 1355 { INDEX_EXPR_TYPE_CONST_EXPRESSION, "const_expression", "Indexing by constant expression" }, 1356 { INDEX_EXPR_TYPE_UNIFORM, "uniform", "Indexing by uniform value" }, 1357 { INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, "dynamically_uniform", "Indexing by dynamically uniform expression" } 1358 }; 1359 1360 static const struct 1361 { 1362 glu::ShaderType type; 1363 const char* name; 1364 } shaderTypes[] = 1365 { 1366 { glu::SHADERTYPE_VERTEX, "vertex" }, 1367 { glu::SHADERTYPE_FRAGMENT, "fragment" }, 1368 { glu::SHADERTYPE_COMPUTE, "compute" } 1369 }; 1370 1371 // .sampler 1372 { 1373 static const glu::DataType samplerTypes[] = 1374 { 1375 // \note 1D images will be added by a later extension. 1376 // glu::TYPE_SAMPLER_1D, 1377 glu::TYPE_SAMPLER_2D, 1378 glu::TYPE_SAMPLER_CUBE, 1379 glu::TYPE_SAMPLER_2D_ARRAY, 1380 glu::TYPE_SAMPLER_3D, 1381 // glu::TYPE_SAMPLER_1D_SHADOW, 1382 glu::TYPE_SAMPLER_2D_SHADOW, 1383 glu::TYPE_SAMPLER_CUBE_SHADOW, 1384 glu::TYPE_SAMPLER_2D_ARRAY_SHADOW, 1385 // glu::TYPE_INT_SAMPLER_1D, 1386 glu::TYPE_INT_SAMPLER_2D, 1387 glu::TYPE_INT_SAMPLER_CUBE, 1388 glu::TYPE_INT_SAMPLER_2D_ARRAY, 1389 glu::TYPE_INT_SAMPLER_3D, 1390 // glu::TYPE_UINT_SAMPLER_1D, 1391 glu::TYPE_UINT_SAMPLER_2D, 1392 glu::TYPE_UINT_SAMPLER_CUBE, 1393 glu::TYPE_UINT_SAMPLER_2D_ARRAY, 1394 glu::TYPE_UINT_SAMPLER_3D, 1395 }; 1396 1397 tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests"); 1398 addChild(samplerGroup); 1399 1400 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++) 1401 { 1402 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type; 1403 tcu::TestCaseGroup* const indexGroup = new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description); 1404 samplerGroup->addChild(indexGroup); 1405 1406 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 1407 { 1408 const glu::ShaderType shaderType = shaderTypes[shaderTypeNdx].type; 1409 tcu::TestCaseGroup* const shaderGroup = new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, ""); 1410 indexGroup->addChild(shaderGroup); 1411 1412 for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++) 1413 { 1414 const glu::DataType samplerType = samplerTypes[samplerTypeNdx]; 1415 const char* samplerName = getDataTypeName(samplerType); 1416 const std::string caseName = de::toLower(samplerName); 1417 1418 shaderGroup->addChild(new SamplerIndexingCase(m_testCtx, caseName.c_str(), "", shaderType, samplerType, indexExprType)); 1419 } 1420 } 1421 } 1422 } 1423 1424 // .ubo / .ssbo / .atomic_counter 1425 { 1426 tcu::TestCaseGroup* const uboGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Uniform Block Instance Array Indexing Tests"); 1427 tcu::TestCaseGroup* const ssboGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Buffer Block Instance Array Indexing Tests"); 1428 tcu::TestCaseGroup* const acGroup = new tcu::TestCaseGroup(m_testCtx, "atomic_counter", "Atomic Counter Array Indexing Tests"); 1429 addChild(uboGroup); 1430 addChild(ssboGroup); 1431 addChild(acGroup); 1432 1433 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++) 1434 { 1435 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type; 1436 const char* indexExprName = indexingTypes[indexTypeNdx].name; 1437 const char* indexExprDesc = indexingTypes[indexTypeNdx].description; 1438 1439 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 1440 { 1441 const glu::ShaderType shaderType = shaderTypes[shaderTypeNdx].type; 1442 const std::string name = std::string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name; 1443 1444 uboGroup->addChild (new BlockArrayIndexingCase (m_testCtx, name.c_str(), indexExprDesc, BLOCKTYPE_UNIFORM, indexExprType, shaderType)); 1445 acGroup->addChild (new AtomicCounterIndexingCase (m_testCtx, name.c_str(), indexExprDesc, indexExprType, shaderType)); 1446 1447 if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION) 1448 ssboGroup->addChild (new BlockArrayIndexingCase (m_testCtx, name.c_str(), indexExprDesc, BLOCKTYPE_BUFFER, indexExprType, shaderType)); 1449 } 1450 } 1451 } 1452 } 1453 1454 } // anonymous 1455 1456 tcu::TestCaseGroup* createOpaqueTypeIndexingTests (tcu::TestContext& testCtx) 1457 { 1458 return new OpaqueTypeIndexingTests(testCtx); 1459 } 1460 1461 } // shaderexecutor 1462 } // vkt 1463