1 /*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 Google Inc. 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 Texture filtering tests with explicit LOD instructions 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktTextureFilteringExplicitLodTests.hpp" 25 26 #include "vkDefs.hpp" 27 28 #include "vktSampleVerifier.hpp" 29 #include "vktShaderExecutor.hpp" 30 #include "vktTestCaseUtil.hpp" 31 32 #include "vkDeviceUtil.hpp" 33 #include "vkImageUtil.hpp" 34 #include "vkPlatform.hpp" 35 #include "vkRef.hpp" 36 #include "vkRefUtil.hpp" 37 #include "vkStrUtil.hpp" 38 #include "vkTypeUtil.hpp" 39 #include "vkQueryUtil.hpp" 40 #include "vkMemUtil.hpp" 41 42 #include "tcuTexLookupVerifier.hpp" 43 #include "tcuTestLog.hpp" 44 #include "tcuTexture.hpp" 45 #include "tcuTextureUtil.hpp" 46 #include "tcuVector.hpp" 47 48 #include "deClock.h" 49 #include "deMath.h" 50 #include "deStringUtil.hpp" 51 #include "deUniquePtr.hpp" 52 53 #include <sstream> 54 #include <string> 55 #include <vector> 56 57 namespace vkt 58 { 59 namespace texture 60 { 61 62 using namespace tcu; 63 using namespace vk; 64 using std::string; 65 66 namespace 67 { 68 69 tcu::FloatFormat getConversionPrecision (VkFormat format) 70 { 71 const tcu::FloatFormat reallyLow (0, 0, 8, false, tcu::YES); 72 const tcu::FloatFormat fp16 (-14, 15, 10, false); 73 const tcu::FloatFormat fp32 (-126, 127, 23, true); 74 75 switch (format) 76 { 77 case VK_FORMAT_B4G4R4A4_UNORM_PACK16: 78 case VK_FORMAT_R5G6B5_UNORM_PACK16: 79 case VK_FORMAT_A1R5G5B5_UNORM_PACK16: 80 return reallyLow; 81 82 case VK_FORMAT_R8_UNORM: 83 case VK_FORMAT_R8_SNORM: 84 case VK_FORMAT_R8G8_UNORM: 85 case VK_FORMAT_R8G8_SNORM: 86 case VK_FORMAT_R8G8B8A8_UNORM: 87 case VK_FORMAT_R8G8B8A8_SNORM: 88 case VK_FORMAT_B8G8R8A8_UNORM: 89 case VK_FORMAT_A8B8G8R8_UNORM_PACK32: 90 case VK_FORMAT_A8B8G8R8_SNORM_PACK32: 91 case VK_FORMAT_A2B10G10R10_UNORM_PACK32: 92 return fp16; 93 94 case VK_FORMAT_R16_SFLOAT: 95 case VK_FORMAT_R16G16_SFLOAT: 96 case VK_FORMAT_R16G16B16A16_SFLOAT: 97 return fp16; 98 99 case VK_FORMAT_R32_SFLOAT: 100 case VK_FORMAT_R32G32_SFLOAT: 101 case VK_FORMAT_R32G32B32A32_SFLOAT: 102 return fp32; 103 104 default: 105 DE_FATAL("Precision not defined for format"); 106 return fp32; 107 } 108 } 109 110 tcu::FloatFormat getFilteringPrecision (VkFormat format) 111 { 112 const tcu::FloatFormat reallyLow (0, 0, 6, false, tcu::YES); 113 const tcu::FloatFormat low (0, 0, 7, false, tcu::YES); 114 const tcu::FloatFormat fp16 (-14, 15, 10, false); 115 const tcu::FloatFormat fp32 (-126, 127, 23, true); 116 117 switch (format) 118 { 119 case VK_FORMAT_B4G4R4A4_UNORM_PACK16: 120 case VK_FORMAT_R5G6B5_UNORM_PACK16: 121 case VK_FORMAT_A1R5G5B5_UNORM_PACK16: 122 return reallyLow; 123 124 case VK_FORMAT_R8_UNORM: 125 case VK_FORMAT_R8_SNORM: 126 case VK_FORMAT_R8G8_UNORM: 127 case VK_FORMAT_R8G8_SNORM: 128 case VK_FORMAT_R8G8B8A8_UNORM: 129 case VK_FORMAT_R8G8B8A8_SNORM: 130 case VK_FORMAT_B8G8R8A8_UNORM: 131 case VK_FORMAT_A8B8G8R8_UNORM_PACK32: 132 case VK_FORMAT_A8B8G8R8_SNORM_PACK32: 133 case VK_FORMAT_A2B10G10R10_UNORM_PACK32: 134 return low; 135 136 case VK_FORMAT_R16_SFLOAT: 137 case VK_FORMAT_R16G16_SFLOAT: 138 case VK_FORMAT_R16G16B16A16_SFLOAT: 139 return fp16; 140 141 case VK_FORMAT_R32_SFLOAT: 142 case VK_FORMAT_R32G32_SFLOAT: 143 case VK_FORMAT_R32G32B32A32_SFLOAT: 144 return fp32; 145 146 default: 147 DE_FATAL("Precision not defined for format"); 148 return fp32; 149 } 150 } 151 152 using namespace shaderexecutor; 153 154 string genSamplerDeclaration(const ImageViewParameters& imParams, 155 const SamplerParameters& samplerParams) 156 { 157 string result = "sampler"; 158 159 switch (imParams.dim) 160 { 161 case IMG_DIM_1D: 162 result += "1D"; 163 break; 164 165 case IMG_DIM_2D: 166 result += "2D"; 167 break; 168 169 case IMG_DIM_3D: 170 result += "3D"; 171 break; 172 173 case IMG_DIM_CUBE: 174 result += "Cube"; 175 break; 176 177 default: 178 break; 179 } 180 181 if (imParams.isArrayed) 182 { 183 result += "Array"; 184 } 185 186 if (samplerParams.isCompare) 187 { 188 result += "Shadow"; 189 } 190 191 return result; 192 } 193 194 string genLookupCode(const ImageViewParameters& imParams, 195 const SamplerParameters& samplerParams, 196 const SampleLookupSettings& lookupSettings) 197 { 198 int dim = -1; 199 200 switch (imParams.dim) 201 { 202 case IMG_DIM_1D: 203 dim = 1; 204 break; 205 206 case IMG_DIM_2D: 207 dim = 2; 208 break; 209 210 case IMG_DIM_3D: 211 dim = 3; 212 break; 213 214 case IMG_DIM_CUBE: 215 dim = 3; 216 break; 217 218 default: 219 dim = 0; 220 break; 221 } 222 223 DE_ASSERT(dim >= 1 && dim <= 3); 224 225 int numCoordComp = dim; 226 227 if (lookupSettings.isProjective) 228 { 229 ++numCoordComp; 230 } 231 232 int numArgComp = numCoordComp; 233 bool hasSeparateCompare = false; 234 235 if (imParams.isArrayed) 236 { 237 DE_ASSERT(!lookupSettings.isProjective && "Can't do a projective lookup on an arrayed image!"); 238 239 ++numArgComp; 240 } 241 242 if (samplerParams.isCompare && numCoordComp == 4) 243 { 244 hasSeparateCompare = true; 245 } 246 else if (samplerParams.isCompare) 247 { 248 ++numArgComp; 249 } 250 251 // Build coordinate input to texture*() function 252 253 string arg = "vec"; 254 arg += (char) (numArgComp + '0'); 255 arg += "(vec"; 256 arg += (char) (numCoordComp + '0'); 257 arg += "(coord)"; 258 259 int numZero = numArgComp - numCoordComp; 260 261 if (imParams.isArrayed) 262 { 263 arg += ", layer"; 264 --numZero; 265 } 266 267 if (samplerParams.isCompare && !hasSeparateCompare) 268 { 269 arg += ", dRef"; 270 --numZero; 271 } 272 273 for (int ndx = 0; ndx < numZero; ++ndx) 274 { 275 arg += ", 0.0"; 276 } 277 278 arg += ")"; 279 280 // Build call to texture*() function 281 282 string code; 283 284 code += "result = texture"; 285 286 if (lookupSettings.isProjective) 287 { 288 code += "Proj"; 289 } 290 291 if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES) 292 { 293 code += "Grad"; 294 } 295 else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD) 296 { 297 code += "Lod"; 298 } 299 300 code += "(testSampler, "; 301 code += arg; 302 303 if (samplerParams.isCompare && hasSeparateCompare) 304 { 305 code += ", dRef"; 306 } 307 308 if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES) 309 { 310 code += ", vec"; 311 code += (char) (numCoordComp + '0'); 312 code += "(dPdx), "; 313 code += "vec"; 314 code += (char) (numCoordComp + '0'); 315 code += "(dPdy)"; 316 } 317 else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD) 318 { 319 code += ", lod"; 320 } 321 322 code += ");"; 323 324 return code; 325 } 326 327 void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba, ImageViewParameters imParams) 328 { 329 const DeviceInterface& vkd = ctx.getDeviceInterface(); 330 const VkDevice dev = ctx.getDevice(); 331 const deUint32 uqfi = ctx.getUniversalQueueFamilyIndex(); 332 333 const VkDeviceSize bufSize = 334 getPixelSize(mapVkFormat(imParams.format)) 335 * imParams.arrayLayers 336 * imParams.size[0] 337 * imParams.size[1] 338 * imParams.size[2] 339 * 2; 340 341 const VkBufferCreateInfo bufCreateInfo = 342 { 343 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType 344 DE_NULL, // pNext 345 0, // flags 346 bufSize, // size 347 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // usage 348 VK_SHARING_MODE_EXCLUSIVE, // sharingMode 349 1, // queueFamilyIndexCount 350 &uqfi // pQueueFamilyIndices 351 }; 352 353 Unique<VkBuffer> buf(createBuffer(vkd, dev, &bufCreateInfo)); 354 355 VkMemoryRequirements bufMemReq; 356 vkd.getBufferMemoryRequirements(dev, buf.get(), &bufMemReq); 357 358 de::UniquePtr<Allocation> bufMem(ctx.getDefaultAllocator().allocate(bufMemReq, MemoryRequirement::HostVisible)); 359 VK_CHECK(vkd.bindBufferMemory(dev, buf.get(), bufMem->getMemory(), bufMem->getOffset())); 360 361 Unique<VkCommandPool> copyPool(createCommandPool(vkd, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, uqfi)); 362 363 Unique<VkCommandBuffer> copyBuffer(allocateCommandBuffer(vkd, dev, *copyPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 364 365 std::vector<VkBufferImageCopy> copyRegions; 366 367 deUint8* const bufMapPtr = reinterpret_cast<deUint8*>(bufMem->getHostPtr()); 368 deUint8* bufCurPtr = bufMapPtr; 369 370 for (int level = 0; level < imParams.levels; ++level) 371 { 372 const IVec3 curLevelSize = pba[level].getSize(); 373 374 const std::size_t copySize = 375 getPixelSize(mapVkFormat(imParams.format)) 376 * curLevelSize[0] * curLevelSize[1] * curLevelSize[2] 377 * imParams.arrayLayers; 378 379 deMemcpy(bufCurPtr, pba[level].getDataPtr(), copySize); 380 381 flushMappedMemoryRange(vkd, dev, bufMem->getMemory(), bufMem->getOffset() + (bufCurPtr - bufMapPtr), copySize); 382 383 const VkImageSubresourceLayers curSubresource = 384 { 385 VK_IMAGE_ASPECT_COLOR_BIT, 386 (deUint32)level, 387 0, 388 (deUint32)imParams.arrayLayers 389 }; 390 391 const VkBufferImageCopy curRegion = 392 { 393 (VkDeviceSize) (bufCurPtr - bufMapPtr), 394 0, 395 0, 396 curSubresource, 397 {0U, 0U, 0U}, 398 {(deUint32)curLevelSize[0], (deUint32)curLevelSize[1], (deUint32)curLevelSize[2]} 399 }; 400 401 copyRegions.push_back(curRegion); 402 403 bufCurPtr += copySize; 404 } 405 406 const VkCommandBufferBeginInfo beginInfo = 407 { 408 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 409 DE_NULL, 410 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 411 DE_NULL 412 }; 413 414 VK_CHECK(vkd.beginCommandBuffer(copyBuffer.get(), &beginInfo)); 415 416 const VkImageSubresourceRange imMemBarSubRange = 417 { 418 VK_IMAGE_ASPECT_COLOR_BIT, 419 0, 420 (deUint32)imParams.levels, 421 0, 422 (deUint32)imParams.arrayLayers 423 }; 424 425 VkImageMemoryBarrier imMemBar = 426 { 427 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 428 DE_NULL, 429 0, 430 VK_ACCESS_TRANSFER_WRITE_BIT, 431 VK_IMAGE_LAYOUT_UNDEFINED, 432 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 433 VK_QUEUE_FAMILY_IGNORED, 434 VK_QUEUE_FAMILY_IGNORED, 435 im, 436 imMemBarSubRange 437 }; 438 439 VkBufferMemoryBarrier bufMemBar = 440 { 441 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 442 DE_NULL, 443 VK_ACCESS_HOST_WRITE_BIT, 444 VK_ACCESS_TRANSFER_READ_BIT, 445 VK_QUEUE_FAMILY_IGNORED, 446 VK_QUEUE_FAMILY_IGNORED, 447 buf.get(), 448 0, 449 bufSize 450 }; 451 452 vkd.cmdPipelineBarrier(copyBuffer.get(), 453 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 454 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 455 0, 456 0, 457 DE_NULL, 458 1, 459 &bufMemBar, 460 1, 461 &imMemBar); 462 463 vkd.cmdCopyBufferToImage(copyBuffer.get(), 464 buf.get(), 465 im, 466 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 467 (deUint32)copyRegions.size(), 468 ©Regions[0]); 469 470 imMemBar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 471 imMemBar.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 472 imMemBar.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; 473 imMemBar.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 474 475 vkd.cmdPipelineBarrier(copyBuffer.get(), 476 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 477 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 478 0, 479 0, 480 DE_NULL, 481 0, 482 DE_NULL, 483 1, 484 &imMemBar); 485 486 VK_CHECK(vkd.endCommandBuffer(copyBuffer.get())); 487 488 const VkSubmitInfo copySubmitInfo = 489 { 490 VK_STRUCTURE_TYPE_SUBMIT_INFO, 491 DE_NULL, 492 0, 493 DE_NULL, 494 DE_NULL, 495 1, 496 &(copyBuffer.get()), 497 0, 498 DE_NULL 499 }; 500 501 VK_CHECK(vkd.queueSubmit(ctx.getUniversalQueue(), 1, ©SubmitInfo, 0)); 502 VK_CHECK(vkd.queueWaitIdle(ctx.getUniversalQueue())); 503 } 504 505 struct TestCaseData 506 { 507 std::vector<ConstPixelBufferAccess> pba; 508 ImageViewParameters imParams; 509 SamplerParameters samplerParams; 510 SampleLookupSettings sampleLookupSettings; 511 glu::ShaderType shaderType; 512 }; 513 514 VkSamplerCreateInfo mapSamplerCreateInfo (const SamplerParameters& samplerParams) 515 { 516 VkSamplerCreateInfo samplerCreateInfo = 517 { 518 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // sType 519 DE_NULL, // pNext 520 0U, // flags 521 samplerParams.magFilter, // magFilter 522 samplerParams.minFilter, // minFilter 523 samplerParams.mipmapFilter, // mipmapMode 524 samplerParams.wrappingModeU, // addressModeU 525 samplerParams.wrappingModeV, // addressModeV 526 samplerParams.wrappingModeW, // addressMoveW 527 samplerParams.lodBias, // mipLodBias 528 VK_FALSE, // anisotropyEnable 529 1.0f, // maxAnisotropy 530 VK_FALSE, // compareEnable 531 VK_COMPARE_OP_NEVER, // compareOp 532 samplerParams.minLod, // minLod 533 samplerParams.maxLod, // maxLod 534 samplerParams.borderColor, // borderColor 535 samplerParams.isUnnormalized ? VK_TRUE : VK_FALSE, // unnormalizedCoordinates 536 }; 537 538 if (samplerParams.isCompare) 539 { 540 samplerCreateInfo.compareEnable = VK_TRUE; 541 542 DE_FATAL("Not implemented"); 543 } 544 545 return samplerCreateInfo; 546 } 547 548 VkImageType mapImageType (ImgDim dim) 549 { 550 VkImageType imType; 551 552 switch (dim) 553 { 554 case IMG_DIM_1D: 555 imType = VK_IMAGE_TYPE_1D; 556 break; 557 558 case IMG_DIM_2D: 559 case IMG_DIM_CUBE: 560 imType = VK_IMAGE_TYPE_2D; 561 break; 562 563 case IMG_DIM_3D: 564 imType = VK_IMAGE_TYPE_3D; 565 break; 566 567 default: 568 imType = VK_IMAGE_TYPE_LAST; 569 break; 570 } 571 572 return imType; 573 } 574 575 VkImageViewType mapImageViewType (const ImageViewParameters& imParams) 576 { 577 VkImageViewType imViewType; 578 579 if (imParams.isArrayed) 580 { 581 switch (imParams.dim) 582 { 583 case IMG_DIM_1D: 584 imViewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY; 585 break; 586 587 case IMG_DIM_2D: 588 imViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; 589 break; 590 591 case IMG_DIM_CUBE: 592 imViewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; 593 break; 594 595 default: 596 imViewType = VK_IMAGE_VIEW_TYPE_LAST; 597 break; 598 } 599 } 600 else 601 { 602 switch (imParams.dim) 603 { 604 case IMG_DIM_1D: 605 imViewType = VK_IMAGE_VIEW_TYPE_1D; 606 break; 607 608 case IMG_DIM_2D: 609 imViewType = VK_IMAGE_VIEW_TYPE_2D; 610 break; 611 612 case IMG_DIM_3D: 613 imViewType = VK_IMAGE_VIEW_TYPE_3D; 614 break; 615 616 case IMG_DIM_CUBE: 617 imViewType = VK_IMAGE_VIEW_TYPE_CUBE; 618 break; 619 620 default: 621 imViewType = VK_IMAGE_VIEW_TYPE_LAST; 622 break; 623 } 624 } 625 626 return imViewType; 627 } 628 629 class DataGenerator 630 { 631 public: 632 virtual ~DataGenerator (void) {} 633 634 virtual bool generate (void) = 0; 635 636 virtual std::vector<ConstPixelBufferAccess> getPba (void) const = 0; 637 virtual std::vector<SampleArguments> getSampleArgs (void) const = 0; 638 639 protected: 640 DataGenerator (void) {} 641 }; 642 643 class TextureFilteringTestInstance : public TestInstance 644 { 645 public: 646 TextureFilteringTestInstance (Context& ctx, 647 const TestCaseData& testCaseData, 648 const ShaderSpec& shaderSpec, 649 de::MovePtr<DataGenerator> gen); 650 651 virtual TestStatus iterate (void) { return runTest(); } 652 653 protected: 654 TestStatus runTest (void); 655 bool isSupported (void); 656 void createResources (void); 657 void execute (void); 658 bool verify (void); 659 660 tcu::Sampler mapTcuSampler (void) const; 661 662 const glu::ShaderType m_shaderType; 663 const ShaderSpec m_shaderSpec; 664 const ImageViewParameters m_imParams; 665 const SamplerParameters m_samplerParams; 666 const SampleLookupSettings m_sampleLookupSettings; 667 668 std::vector<SampleArguments> m_sampleArguments; 669 deUint32 m_numSamples; 670 671 de::MovePtr<Allocation> m_imAllocation; 672 Move<VkImage> m_im; 673 Move<VkImageView> m_imView; 674 Move<VkSampler> m_sampler; 675 676 Move<VkDescriptorSetLayout> m_extraResourcesLayout; 677 Move<VkDescriptorPool> m_extraResourcesPool; 678 Move<VkDescriptorSet> m_extraResourcesSet; 679 680 de::MovePtr<ShaderExecutor> m_executor; 681 682 std::vector<ConstPixelBufferAccess> m_levels; 683 de::MovePtr<DataGenerator> m_gen; 684 685 std::vector<Vec4> m_resultSamples; 686 std::vector<Vec4> m_resultCoords; 687 }; 688 689 TextureFilteringTestInstance::TextureFilteringTestInstance (Context& ctx, 690 const TestCaseData& testCaseData, 691 const ShaderSpec& shaderSpec, 692 de::MovePtr<DataGenerator> gen) 693 : TestInstance (ctx) 694 , m_shaderType (testCaseData.shaderType) 695 , m_shaderSpec (shaderSpec) 696 , m_imParams (testCaseData.imParams) 697 , m_samplerParams (testCaseData.samplerParams) 698 , m_sampleLookupSettings (testCaseData.sampleLookupSettings) 699 , m_levels (testCaseData.pba) 700 , m_gen (gen.release()) 701 { 702 for (deUint8 compNdx = 0; compNdx < 3; ++compNdx) 703 DE_ASSERT(m_imParams.size[compNdx] > 0); 704 } 705 706 TestStatus TextureFilteringTestInstance::runTest (void) 707 { 708 if (!isSupported()) 709 TCU_THROW(NotSupportedError, "Unsupported combination of filtering and image format"); 710 711 TCU_CHECK(m_gen->generate()); 712 m_levels = m_gen->getPba(); 713 714 m_sampleArguments = m_gen->getSampleArgs(); 715 m_numSamples = (deUint32)m_sampleArguments.size(); 716 717 createResources(); 718 initializeImage(m_context, m_im.get(), &m_levels[0], m_imParams); 719 720 deUint64 startTime, endTime; 721 722 startTime = deGetMicroseconds(); 723 execute(); 724 endTime = deGetMicroseconds(); 725 726 m_context.getTestContext().getLog() << TestLog::Message 727 << "Execution time: " 728 << endTime - startTime 729 << "us" 730 << TestLog::EndMessage; 731 732 startTime = deGetMicroseconds(); 733 bool result = verify(); 734 endTime = deGetMicroseconds(); 735 736 m_context.getTestContext().getLog() << TestLog::Message 737 << "Verification time: " 738 << endTime - startTime 739 << "us" 740 << TestLog::EndMessage; 741 742 if (result) 743 { 744 return TestStatus::pass("Success"); 745 } 746 else 747 { 748 // \todo [2016-06-24 collinbaker] Print report if verification fails 749 return TestStatus::fail("Verification failed"); 750 } 751 } 752 753 bool TextureFilteringTestInstance::verify (void) 754 { 755 // \todo [2016-06-24 collinbaker] Handle cubemaps 756 757 const int coordBits = (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits; 758 const int mipmapBits = (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits; 759 const int maxPrintedFailures = 5; 760 int failCount = 0; 761 762 const SampleVerifier verifier (m_imParams, 763 m_samplerParams, 764 m_sampleLookupSettings, 765 coordBits, 766 mipmapBits, 767 getConversionPrecision(m_imParams.format), 768 getFilteringPrecision(m_imParams.format), 769 m_levels); 770 771 772 for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx) 773 { 774 if (!verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx])) 775 { 776 if (failCount++ < maxPrintedFailures) 777 { 778 // Re-run with report logging 779 std::string report; 780 verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report); 781 782 m_context.getTestContext().getLog() 783 << TestLog::Section("Failed sample", "Failed sample") 784 << TestLog::Message 785 << "Sample " << sampleNdx << ".\n" 786 << "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n" 787 << "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n" 788 << "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n" 789 << "Failure report:\n" << report << "\n" 790 << TestLog::EndMessage 791 << TestLog::EndSection; 792 } 793 } 794 } 795 796 m_context.getTestContext().getLog() 797 << TestLog::Message 798 << "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "." 799 << TestLog::EndMessage; 800 801 return failCount == 0; 802 } 803 804 void TextureFilteringTestInstance::execute (void) 805 { 806 std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods; 807 808 for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx) 809 { 810 const SampleArguments& sampleArgs = m_sampleArguments[ndx]; 811 812 for (deUint8 compNdx = 0; compNdx < 4; ++compNdx) 813 { 814 coords.push_back(sampleArgs.coord[compNdx]); 815 dPdxs .push_back(sampleArgs.dPdx[compNdx]); 816 dPdys .push_back(sampleArgs.dPdy[compNdx]); 817 } 818 819 layers.push_back(sampleArgs.layer); 820 dRefs .push_back(sampleArgs.dRef); 821 lods .push_back(sampleArgs.lod); 822 } 823 824 const void* inputs[6] = 825 { 826 reinterpret_cast<const void*>(&coords[0]), 827 reinterpret_cast<const void*>(&layers[0]), 828 reinterpret_cast<const void*>(&dRefs[0]), 829 reinterpret_cast<const void*>(&dPdxs[0]), 830 reinterpret_cast<const void*>(&dPdys[0]), 831 reinterpret_cast<const void*>(&lods[0]) 832 }; 833 834 // Staging buffers; data will be copied into vectors of Vec4 835 // \todo [2016-06-24 collinbaker] Figure out if I actually need to 836 // use staging buffers 837 std::vector<float> resultSamplesTemp(m_numSamples * 4); 838 std::vector<float> resultCoordsTemp (m_numSamples * 4); 839 840 void* outputs[2] = 841 { 842 reinterpret_cast<void*>(&resultSamplesTemp[0]), 843 reinterpret_cast<void*>(&resultCoordsTemp[0]) 844 }; 845 846 m_executor->execute(m_numSamples, inputs, outputs, *m_extraResourcesSet); 847 848 m_resultSamples.resize(m_numSamples); 849 m_resultCoords .resize(m_numSamples); 850 851 for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx) 852 { 853 m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0], 854 resultSamplesTemp[4 * ndx + 1], 855 resultSamplesTemp[4 * ndx + 2], 856 resultSamplesTemp[4 * ndx + 3]); 857 858 m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0], 859 resultCoordsTemp [4 * ndx + 1], 860 resultCoordsTemp [4 * ndx + 2], 861 resultCoordsTemp [4 * ndx + 3]); 862 } 863 } 864 865 void TextureFilteringTestInstance::createResources (void) 866 { 867 // Create VkImage 868 869 const DeviceInterface& vkd = m_context.getDeviceInterface(); 870 const VkDevice device = m_context.getDevice(); 871 872 const deUint32 queueFamily = m_context.getUniversalQueueFamilyIndex(); 873 const VkImageCreateFlags imCreateFlags =(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; 874 875 const VkImageCreateInfo imCreateInfo = 876 { 877 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 878 DE_NULL, 879 imCreateFlags, 880 mapImageType(m_imParams.dim), 881 m_imParams.format, 882 makeExtent3D(m_imParams.size[0], m_imParams.size[1], m_imParams.size[2]), 883 (deUint32)m_imParams.levels, 884 (deUint32)m_imParams.arrayLayers, 885 VK_SAMPLE_COUNT_1_BIT, 886 VK_IMAGE_TILING_OPTIMAL, 887 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 888 VK_SHARING_MODE_EXCLUSIVE, 889 1, 890 &queueFamily, 891 VK_IMAGE_LAYOUT_UNDEFINED 892 }; 893 894 m_im = createImage(vkd, device, &imCreateInfo); 895 896 // Allocate memory for image 897 898 VkMemoryRequirements imMemReq; 899 vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq); 900 901 m_imAllocation = m_context.getDefaultAllocator().allocate(imMemReq, MemoryRequirement::Any); 902 VK_CHECK(vkd.bindImageMemory(device, m_im.get(), m_imAllocation->getMemory(), m_imAllocation->getOffset())); 903 904 // Create VkImageView 905 906 // \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images) 907 DE_ASSERT(m_imParams.dim != IMG_DIM_CUBE); // \todo Support cube maps 908 const VkImageSubresourceRange imViewSubresourceRange = 909 { 910 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 911 0, // baseMipLevel 912 (deUint32)m_imParams.levels, // levelCount 913 0, // baseArrayLayer 914 (deUint32)m_imParams.arrayLayers // layerCount 915 }; 916 917 const VkComponentMapping imViewCompMap = 918 { 919 VK_COMPONENT_SWIZZLE_R, 920 VK_COMPONENT_SWIZZLE_G, 921 VK_COMPONENT_SWIZZLE_B, 922 VK_COMPONENT_SWIZZLE_A 923 }; 924 925 const VkImageViewCreateInfo imViewCreateInfo = 926 { 927 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType 928 DE_NULL, // pNext 929 0, // flags 930 m_im.get(), // image 931 mapImageViewType(m_imParams), // viewType 932 m_imParams.format, // format 933 imViewCompMap, // components 934 imViewSubresourceRange // subresourceRange 935 }; 936 937 m_imView = createImageView(vkd, device, &imViewCreateInfo); 938 939 // Create VkSampler 940 941 const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams); 942 m_sampler = createSampler(vkd, device, &samplerCreateInfo); 943 944 // Create additional descriptors 945 946 { 947 const VkDescriptorSetLayoutBinding bindings[] = 948 { 949 { 0u, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u, VK_SHADER_STAGE_ALL, DE_NULL }, 950 }; 951 const VkDescriptorSetLayoutCreateInfo layoutInfo = 952 { 953 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 954 DE_NULL, 955 (VkDescriptorSetLayoutCreateFlags)0u, 956 DE_LENGTH_OF_ARRAY(bindings), 957 bindings, 958 }; 959 960 m_extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo); 961 } 962 963 { 964 const VkDescriptorPoolSize poolSizes[] = 965 { 966 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u }, 967 }; 968 const VkDescriptorPoolCreateInfo poolInfo = 969 { 970 VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 971 DE_NULL, 972 (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 973 1u, // maxSets 974 DE_LENGTH_OF_ARRAY(poolSizes), 975 poolSizes, 976 }; 977 978 m_extraResourcesPool = createDescriptorPool(vkd, device, &poolInfo); 979 } 980 981 { 982 const VkDescriptorSetAllocateInfo allocInfo = 983 { 984 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 985 DE_NULL, 986 *m_extraResourcesPool, 987 1u, 988 &m_extraResourcesLayout.get(), 989 }; 990 991 m_extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo); 992 } 993 994 { 995 const VkDescriptorImageInfo imageInfo = 996 { 997 *m_sampler, 998 *m_imView, 999 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL 1000 }; 1001 const VkWriteDescriptorSet descriptorWrite = 1002 { 1003 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 1004 DE_NULL, 1005 *m_extraResourcesSet, 1006 0u, // dstBinding 1007 0u, // dstArrayElement 1008 1u, 1009 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1010 &imageInfo, 1011 (const VkDescriptorBufferInfo*)DE_NULL, 1012 (const VkBufferView*)DE_NULL, 1013 }; 1014 1015 vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL); 1016 } 1017 1018 m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_context, m_shaderType, m_shaderSpec, *m_extraResourcesLayout)); 1019 } 1020 1021 VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams) 1022 { 1023 VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; 1024 1025 if (samplerParams.minFilter == VK_FILTER_LINEAR || 1026 samplerParams.magFilter == VK_FILTER_LINEAR || 1027 samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR) 1028 { 1029 features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; 1030 } 1031 1032 return features; 1033 } 1034 1035 bool TextureFilteringTestInstance::isSupported (void) 1036 { 1037 const VkImageCreateFlags imCreateFlags = (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; 1038 const VkFormatFeatureFlags reqImFeatures = getRequiredFormatFeatures(m_samplerParams); 1039 1040 const VkImageFormatProperties imFormatProperties = getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(), 1041 m_context.getPhysicalDevice(), 1042 m_imParams.format, 1043 mapImageType(m_imParams.dim), 1044 VK_IMAGE_TILING_OPTIMAL, 1045 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1046 imCreateFlags); 1047 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(), 1048 m_context.getPhysicalDevice(), 1049 m_imParams.format); 1050 1051 // \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties 1052 DE_UNREF(imFormatProperties); 1053 1054 return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures; 1055 } 1056 1057 class TextureFilteringTestCase : public TestCase 1058 { 1059 public: 1060 TextureFilteringTestCase (tcu::TestContext& testCtx, 1061 const char* name, 1062 const char* description) 1063 : TestCase(testCtx, name, description) 1064 { 1065 } 1066 1067 void initSpec (void); 1068 1069 virtual void initPrograms (vk::SourceCollections& programCollection) const 1070 { 1071 generateSources(m_testCaseData.shaderType, m_shaderSpec, programCollection); 1072 } 1073 1074 virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0; 1075 1076 virtual TestInstance* createInstance (Context& ctx) const 1077 { 1078 return new TextureFilteringTestInstance(ctx, m_testCaseData, m_shaderSpec, createGenerator()); 1079 } 1080 1081 protected: 1082 de::MovePtr<ShaderExecutor> m_executor; 1083 TestCaseData m_testCaseData; 1084 ShaderSpec m_shaderSpec; 1085 }; 1086 1087 void TextureFilteringTestCase::initSpec (void) 1088 { 1089 m_shaderSpec.source = genLookupCode(m_testCaseData.imParams, 1090 m_testCaseData.samplerParams, 1091 m_testCaseData.sampleLookupSettings); 1092 m_shaderSpec.source += "\nsampledCoord = coord;"; 1093 1094 m_shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 1095 m_shaderSpec.outputs.push_back(Symbol("sampledCoord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 1096 m_shaderSpec.inputs .push_back(Symbol("coord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 1097 m_shaderSpec.inputs .push_back(Symbol("layer", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP))); 1098 m_shaderSpec.inputs .push_back(Symbol("dRef", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP))); 1099 m_shaderSpec.inputs .push_back(Symbol("dPdx", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 1100 m_shaderSpec.inputs .push_back(Symbol("dPdy", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 1101 m_shaderSpec.inputs .push_back(Symbol("lod", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP))); 1102 1103 m_shaderSpec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp "; 1104 m_shaderSpec.globalDeclarations += genSamplerDeclaration(m_testCaseData.imParams, 1105 m_testCaseData.samplerParams); 1106 m_shaderSpec.globalDeclarations += " testSampler;"; 1107 } 1108 1109 class Texture2DGradientTestCase : public TextureFilteringTestCase 1110 { 1111 public: 1112 Texture2DGradientTestCase (TestContext& testCtx, 1113 const char* name, 1114 const char* desc, 1115 TextureFormat format, 1116 IVec3 dimensions, 1117 VkFilter magFilter, 1118 VkFilter minFilter, 1119 VkSamplerMipmapMode mipmapFilter, 1120 VkSamplerAddressMode wrappingMode, 1121 bool useDerivatives) 1122 1123 : TextureFilteringTestCase (testCtx, name, desc) 1124 , m_format (format) 1125 , m_dimensions (dimensions) 1126 , m_magFilter (magFilter) 1127 , m_minFilter (minFilter) 1128 , m_mipmapFilter (mipmapFilter) 1129 , m_wrappingMode (wrappingMode) 1130 , m_useDerivatives (useDerivatives) 1131 { 1132 m_testCaseData = genTestCaseData(); 1133 initSpec(); 1134 } 1135 1136 protected: 1137 class Generator; 1138 1139 virtual de::MovePtr<DataGenerator> createGenerator (void) const; 1140 1141 TestCaseData genTestCaseData() 1142 { 1143 // Generate grid 1144 1145 const SampleLookupSettings sampleLookupSettings = 1146 { 1147 m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode 1148 false, // hasLodBias 1149 false, // isProjective 1150 }; 1151 1152 const SamplerParameters samplerParameters = 1153 { 1154 m_magFilter, 1155 m_minFilter, 1156 m_mipmapFilter, 1157 m_wrappingMode, 1158 m_wrappingMode, 1159 m_wrappingMode, 1160 VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 1161 0.0f, 1162 -1.0f, 1163 50.0f, 1164 false, 1165 false 1166 }; 1167 1168 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0], 1169 m_dimensions[1]))); 1170 1171 const ImageViewParameters imParameters = 1172 { 1173 IMG_DIM_2D, 1174 mapTextureFormat(m_format), 1175 m_dimensions, 1176 numLevels, 1177 false, 1178 1, 1179 }; 1180 1181 const TestCaseData data = 1182 { 1183 std::vector<ConstPixelBufferAccess>(), 1184 imParameters, 1185 samplerParameters, 1186 sampleLookupSettings, 1187 glu::SHADERTYPE_FRAGMENT 1188 }; 1189 1190 return data; 1191 } 1192 1193 private: 1194 const TextureFormat m_format; 1195 const IVec3 m_dimensions; 1196 const VkFilter m_magFilter; 1197 const VkFilter m_minFilter; 1198 const VkSamplerMipmapMode m_mipmapFilter; 1199 const VkSamplerAddressMode m_wrappingMode; 1200 const bool m_useDerivatives; 1201 }; 1202 1203 class Texture2DGradientTestCase::Generator : public DataGenerator 1204 { 1205 public: 1206 Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {} 1207 1208 virtual ~Generator (void) 1209 { 1210 delete m_tex.release(); 1211 } 1212 1213 virtual bool generate (void) 1214 { 1215 m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format, 1216 m_testCase->m_dimensions[0], 1217 m_testCase->m_dimensions[1])); 1218 1219 const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0], 1220 m_testCase->m_dimensions[1]))); 1221 1222 const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format); 1223 1224 const Vec4 cBias = fmtInfo.valueMin; 1225 const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin; 1226 1227 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx) 1228 { 1229 const Vec4 gMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias; 1230 const Vec4 gMax = Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias; 1231 1232 m_tex->allocLevel(levelNdx); 1233 fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax); 1234 } 1235 1236 return true; 1237 } 1238 1239 virtual std::vector<ConstPixelBufferAccess> getPba (void) const 1240 { 1241 std::vector<ConstPixelBufferAccess> pba; 1242 1243 const deUint8 numLevels = (deUint8) m_tex->getNumLevels(); 1244 1245 for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx) 1246 { 1247 pba.push_back(m_tex->getLevel(levelNdx)); 1248 } 1249 1250 return pba; 1251 } 1252 1253 virtual std::vector<SampleArguments> getSampleArgs (void) const 1254 { 1255 std::vector<SampleArguments> args; 1256 1257 if (m_testCase->m_useDerivatives) 1258 { 1259 struct 1260 { 1261 Vec4 dPdx; 1262 Vec4 dPdy; 1263 } 1264 derivativePairs[] = 1265 { 1266 {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)}, 1267 {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, 1268 {Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)}, 1269 {Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)}, 1270 {Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)} 1271 }; 1272 1273 for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i) 1274 { 1275 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j) 1276 { 1277 for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx) 1278 { 1279 SampleArguments cur = SampleArguments(); 1280 cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]), 1281 (float)j / (float)(2 * m_testCase->m_dimensions[1]), 1282 0.0f, 0.0f); 1283 cur.dPdx = derivativePairs[derivNdx].dPdx; 1284 cur.dPdy = derivativePairs[derivNdx].dPdy; 1285 1286 args.push_back(cur); 1287 } 1288 } 1289 } 1290 } 1291 else 1292 { 1293 const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0}; 1294 1295 for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i) 1296 { 1297 for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j) 1298 { 1299 for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx) 1300 { 1301 SampleArguments cur = SampleArguments(); 1302 cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]), 1303 (float)j / (float)(2 * m_testCase->m_dimensions[1]), 1304 0.0f, 0.0f); 1305 cur.lod = lodList[lodNdx]; 1306 1307 args.push_back(cur); 1308 } 1309 } 1310 } 1311 } 1312 1313 return args; 1314 } 1315 1316 private: 1317 const Texture2DGradientTestCase* m_testCase; 1318 de::MovePtr<Texture2D> m_tex; 1319 }; 1320 1321 de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const 1322 { 1323 return de::MovePtr<DataGenerator>(new Generator(this)); 1324 } 1325 1326 TestCaseGroup* create2DFormatTests (TestContext& testCtx) 1327 { 1328 de::MovePtr<TestCaseGroup> tests( 1329 new TestCaseGroup(testCtx, "formats", "Various image formats")); 1330 1331 const VkFormat formats[] = 1332 { 1333 VK_FORMAT_B4G4R4A4_UNORM_PACK16, 1334 VK_FORMAT_R5G6B5_UNORM_PACK16, 1335 VK_FORMAT_A1R5G5B5_UNORM_PACK16, 1336 VK_FORMAT_R8_UNORM, 1337 VK_FORMAT_R8_SNORM, 1338 VK_FORMAT_R8G8_UNORM, 1339 VK_FORMAT_R8G8_SNORM, 1340 VK_FORMAT_R8G8B8A8_UNORM, 1341 VK_FORMAT_R8G8B8A8_SNORM, 1342 // VK_FORMAT_R8G8B8A8_SRGB, 1343 VK_FORMAT_B8G8R8A8_UNORM, 1344 // VK_FORMAT_B8G8R8A8_SRGB, 1345 VK_FORMAT_A8B8G8R8_UNORM_PACK32, 1346 VK_FORMAT_A8B8G8R8_SNORM_PACK32, 1347 // VK_FORMAT_A8B8G8R8_SRGB_PACK32, 1348 VK_FORMAT_A2B10G10R10_UNORM_PACK32, 1349 VK_FORMAT_R16_SFLOAT, 1350 VK_FORMAT_R16G16_SFLOAT, 1351 VK_FORMAT_R16G16B16A16_SFLOAT, 1352 VK_FORMAT_R32_SFLOAT, 1353 VK_FORMAT_R32G32_SFLOAT, 1354 VK_FORMAT_R32G32B32A32_SFLOAT, 1355 // VK_FORMAT_B10G11R11_UFLOAT_PACK32, 1356 // VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 1357 }; 1358 1359 const IVec3 size(32, 32, 1); 1360 1361 for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx) 1362 { 1363 const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10)); 1364 1365 Texture2DGradientTestCase* testCaseNearest = 1366 new Texture2DGradientTestCase( 1367 testCtx, 1368 (prefix + "_nearest").c_str(), 1369 "...", 1370 mapVkFormat(formats[formatNdx]), 1371 size, 1372 VK_FILTER_NEAREST, 1373 VK_FILTER_NEAREST, 1374 VK_SAMPLER_MIPMAP_MODE_NEAREST, 1375 VK_SAMPLER_ADDRESS_MODE_REPEAT, 1376 false); 1377 1378 tests->addChild(testCaseNearest); 1379 1380 Texture2DGradientTestCase* testCaseLinear = 1381 new Texture2DGradientTestCase( 1382 testCtx, 1383 (prefix + "_linear").c_str(), 1384 "...", 1385 mapVkFormat(formats[formatNdx]), 1386 size, 1387 VK_FILTER_LINEAR, 1388 VK_FILTER_LINEAR, 1389 VK_SAMPLER_MIPMAP_MODE_LINEAR, 1390 VK_SAMPLER_ADDRESS_MODE_REPEAT, 1391 false); 1392 1393 tests->addChild(testCaseLinear); 1394 } 1395 1396 return tests.release(); 1397 } 1398 1399 TestCaseGroup* create2DDerivTests (TestContext& testCtx) 1400 { 1401 de::MovePtr<TestCaseGroup> tests( 1402 new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests")); 1403 1404 const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; 1405 const VkSamplerAddressMode wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 1406 const IVec3 size = IVec3(16, 16, 1); 1407 1408 const VkFilter filters[2] = 1409 { 1410 VK_FILTER_NEAREST, 1411 VK_FILTER_LINEAR 1412 }; 1413 1414 const VkSamplerMipmapMode mipmapFilters[2] = 1415 { 1416 VK_SAMPLER_MIPMAP_MODE_NEAREST, 1417 VK_SAMPLER_MIPMAP_MODE_LINEAR, 1418 }; 1419 1420 for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx) 1421 { 1422 for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx) 1423 { 1424 for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx) 1425 { 1426 std::ostringstream caseName; 1427 1428 switch (filters[magFilterNdx]) 1429 { 1430 case VK_FILTER_NEAREST: 1431 caseName << "nearest"; 1432 break; 1433 1434 case VK_FILTER_LINEAR: 1435 caseName << "linear"; 1436 break; 1437 1438 default: 1439 break; 1440 } 1441 1442 switch (filters[minFilterNdx]) 1443 { 1444 case VK_FILTER_NEAREST: 1445 caseName << "_nearest"; 1446 break; 1447 1448 case VK_FILTER_LINEAR: 1449 caseName << "_linear"; 1450 break; 1451 1452 default: 1453 break; 1454 } 1455 1456 caseName << "_mipmap"; 1457 1458 switch (mipmapFilters[mipmapFilterNdx]) 1459 { 1460 case VK_SAMPLER_MIPMAP_MODE_NEAREST: 1461 caseName << "_nearest"; 1462 break; 1463 1464 case VK_SAMPLER_MIPMAP_MODE_LINEAR: 1465 caseName << "_linear"; 1466 break; 1467 1468 default: 1469 break; 1470 } 1471 1472 Texture2DGradientTestCase* testCase = 1473 new Texture2DGradientTestCase( 1474 testCtx, 1475 caseName.str().c_str(), 1476 "...", 1477 mapVkFormat(format), 1478 size, 1479 filters[magFilterNdx], 1480 filters[minFilterNdx], 1481 mipmapFilters[mipmapFilterNdx], 1482 wrappingMode, 1483 true); 1484 1485 tests->addChild(testCase); 1486 } 1487 } 1488 } 1489 1490 return tests.release(); 1491 } 1492 1493 TestCaseGroup* create2DSizeTests (TestContext& testCtx) 1494 { 1495 de::MovePtr<TestCaseGroup> tests( 1496 new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations")); 1497 1498 const VkFilter filters[2] = 1499 { 1500 VK_FILTER_NEAREST, 1501 VK_FILTER_LINEAR 1502 }; 1503 1504 const VkSamplerMipmapMode mipmapFilters[2] = 1505 { 1506 VK_SAMPLER_MIPMAP_MODE_NEAREST, 1507 VK_SAMPLER_MIPMAP_MODE_LINEAR 1508 }; 1509 1510 const VkSamplerAddressMode wrappingModes[2] = 1511 { 1512 VK_SAMPLER_ADDRESS_MODE_REPEAT, 1513 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE 1514 }; 1515 1516 const IVec3 sizes[] = 1517 { 1518 IVec3(2, 2, 1), 1519 IVec3(2, 3, 1), 1520 IVec3(3, 7, 1), 1521 IVec3(4, 8, 1), 1522 IVec3(31, 55, 1), 1523 IVec3(32, 32, 1), 1524 IVec3(32, 64, 1), 1525 IVec3(57, 35, 1), 1526 IVec3(128, 128, 1) 1527 }; 1528 1529 1530 for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx) 1531 { 1532 for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx) 1533 { 1534 for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx) 1535 { 1536 for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx) 1537 { 1538 for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx) 1539 { 1540 std::ostringstream caseName; 1541 1542 caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1]; 1543 1544 switch (filters[magFilterNdx]) 1545 { 1546 case VK_FILTER_NEAREST: 1547 caseName << "_nearest"; 1548 break; 1549 1550 case VK_FILTER_LINEAR: 1551 caseName << "_linear"; 1552 break; 1553 1554 default: 1555 break; 1556 } 1557 1558 switch (filters[minFilterNdx]) 1559 { 1560 case VK_FILTER_NEAREST: 1561 caseName << "_nearest"; 1562 break; 1563 1564 case VK_FILTER_LINEAR: 1565 caseName << "_linear"; 1566 break; 1567 1568 default: 1569 break; 1570 } 1571 1572 switch (mipmapFilters[mipmapFilterNdx]) 1573 { 1574 case VK_SAMPLER_MIPMAP_MODE_NEAREST: 1575 caseName << "_mipmap_nearest"; 1576 break; 1577 1578 case VK_SAMPLER_MIPMAP_MODE_LINEAR: 1579 caseName << "_mipmap_linear"; 1580 break; 1581 1582 default: 1583 break; 1584 } 1585 1586 switch (wrappingModes[wrappingModeNdx]) 1587 { 1588 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: 1589 caseName << "_clamp"; 1590 break; 1591 1592 case VK_SAMPLER_ADDRESS_MODE_REPEAT: 1593 caseName << "_repeat"; 1594 break; 1595 1596 default: 1597 break; 1598 } 1599 1600 Texture2DGradientTestCase* testCase = 1601 new Texture2DGradientTestCase( 1602 testCtx, 1603 caseName.str().c_str(), 1604 "...", 1605 mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), 1606 sizes[sizeNdx], 1607 filters[magFilterNdx], 1608 filters[minFilterNdx], 1609 mipmapFilters[mipmapFilterNdx], 1610 wrappingModes[wrappingModeNdx], 1611 false); 1612 1613 tests->addChild(testCase); 1614 } 1615 } 1616 } 1617 } 1618 } 1619 1620 return tests.release(); 1621 } 1622 1623 TestCaseGroup* create2DTests (TestContext& testCtx) 1624 { 1625 de::MovePtr<TestCaseGroup> tests( 1626 new TestCaseGroup(testCtx, "2d", "2D Image filtering tests")); 1627 1628 tests->addChild(create2DSizeTests(testCtx)); 1629 tests->addChild(create2DFormatTests(testCtx)); 1630 tests->addChild(create2DDerivTests(testCtx)); 1631 1632 return tests.release(); 1633 } 1634 1635 } // anonymous 1636 1637 TestCaseGroup* createExplicitLodTests (TestContext& testCtx) 1638 { 1639 de::MovePtr<TestCaseGroup> tests( 1640 new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD")); 1641 1642 tests->addChild(create2DTests(testCtx)); 1643 1644 return tests.release(); 1645 } 1646 1647 } // texture 1648 } // vkt 1649