1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2022 The Khronos Group Inc. 6 * Copyright (c) 2022 Valve Corporation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 *//*! 21 * \file 22 * \brief 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktPipelineImageSlicedViewOf3DTests.hpp" 26#include "vktTestCase.hpp" 27 28#include "vkImageUtil.hpp" 29#include "vkTypeUtil.hpp" 30#include "vkObjUtil.hpp" 31#include "vkCmdUtil.hpp" 32#include "vkBuilderUtil.hpp" 33#include "vkImageWithMemory.hpp" 34#include "vkBufferWithMemory.hpp" 35#include "vkBarrierUtil.hpp" 36 37#include "tcuTexture.hpp" 38#include "tcuImageCompare.hpp" 39#include "tcuTextureUtil.hpp" 40 41#include "deRandom.hpp" 42 43#include <sstream> 44#include <vector> 45#include <tuple> 46#include <set> 47#include <limits> 48#include <string> 49#include <algorithm> 50 51namespace vkt 52{ 53namespace pipeline 54{ 55 56using namespace vk; 57 58namespace 59{ 60 61constexpr uint32_t kWidth = 8u; 62constexpr uint32_t kHeight = 8u; 63constexpr VkFormat kFormat = VK_FORMAT_R8G8B8A8_UINT; 64constexpr uint32_t kVertexCount = 3u; 65constexpr auto kUsageLayout = VK_IMAGE_LAYOUT_GENERAL; 66 67enum class TestType 68{ 69 LOAD = 0, 70 STORE, 71}; 72 73struct TestParams 74{ 75 TestType testType; 76 VkShaderStageFlagBits stage; 77 uint32_t width; 78 uint32_t height; 79 uint32_t depth; 80 uint32_t offset; 81 82private: 83 // We want to test both normal ranges and VK_REMAINING_3D_SLICES_EXT, but in the latter case we cannot blindly use the range 84 // value for some operations. See getActualRange() and getSlicedViewRange(). 85 uint32_t range; 86 87public: 88 tcu::Maybe<uint32_t> mipLevel; 89 bool sampleImg; 90 91 TestParams (TestType testType_, VkShaderStageFlagBits stage_, uint32_t width_, uint32_t height_, uint32_t depth_, uint32_t offset_, uint32_t range_, 92 const tcu::Maybe<uint32_t>& mipLevel_, bool sampleImg_) 93 : testType (testType_) 94 , stage (stage_) 95 , width (width_) 96 , height (height_) 97 , depth (depth_) 98 , offset (offset_) 99 , range (range_) 100 , mipLevel (mipLevel_) 101 , sampleImg (sampleImg_) 102 { 103 DE_ASSERT(stage == VK_SHADER_STAGE_COMPUTE_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT); 104 DE_ASSERT(range > 0u); 105 106 const auto selectedLevel = getSelectedLevel(); 107 108 if (useMipMaps()) 109 { 110 // To simplify things. 111 DE_ASSERT(width == height && width == depth); 112 113 const auto maxMipLevelCount = getMaxMipLevelCount(); 114 DE_ASSERT(selectedLevel < maxMipLevelCount); 115 DE_UNREF(maxMipLevelCount); // For release builds. 116 } 117 118 const uint32_t selectedLevelDepth = (depth >> selectedLevel); 119 DE_UNREF(selectedLevelDepth); // For release builds. 120 121 if (!useRemainingSlices()) 122 DE_ASSERT(offset + range <= selectedLevelDepth); 123 else 124 DE_ASSERT(offset < selectedLevelDepth); 125 } 126 127 uint32_t getSelectedLevel (void) const 128 { 129 return (useMipMaps() ? mipLevel.get() : 0u); 130 } 131 132 uint32_t getFullImageLevels (void) const 133 { 134 return (useMipMaps() ? getMaxMipLevelCount() : 1u); 135 } 136 137 uint32_t getActualRange (void) const 138 { 139 const auto levelDepth = (depth >> getSelectedLevel()); 140 DE_ASSERT(levelDepth > 0u); 141 142 return (useRemainingSlices() ? (levelDepth - offset) : range); 143 } 144 145 uint32_t getSlicedViewRange (void) const 146 { 147 return range; 148 } 149 150 VkExtent3D getSliceExtent (void) const 151 { 152 const auto selectedLevel = getSelectedLevel(); 153 const auto extent = makeExtent3D((width >> selectedLevel), 154 (height >> selectedLevel), 155 getActualRange()); 156 157 DE_ASSERT(extent.width > 0u); 158 DE_ASSERT(extent.height > 0u); 159 DE_ASSERT(extent.depth > 0u); 160 return extent; 161 } 162 163 VkExtent3D getFullLevelExtent (void) const 164 { 165 const auto selectedLevel = getSelectedLevel(); 166 const auto extent = makeExtent3D((width >> selectedLevel), 167 (height >> selectedLevel), 168 (depth >> selectedLevel)); 169 170 DE_ASSERT(extent.width > 0u); 171 DE_ASSERT(extent.height > 0u); 172 DE_ASSERT(extent.depth > 0u); 173 return extent; 174 } 175 176 static uint32_t getMaxMipLevelCountForSize (uint32_t size) 177 { 178 DE_ASSERT(size <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max())); 179 return static_cast<uint32_t>(deLog2Floor32(static_cast<int32_t>(size)) + 1); 180 } 181 182private: 183 uint32_t getMaxMipLevelCount (void) const 184 { 185 return getMaxMipLevelCountForSize(depth); 186 } 187 188 bool useMipMaps (void) const 189 { 190 return static_cast<bool>(mipLevel); 191 } 192 193 bool useRemainingSlices (void) const 194 { 195 return (range == VK_REMAINING_3D_SLICES_EXT); 196 } 197}; 198 199class SlicedViewTestCase : public vkt::TestCase 200{ 201public: 202 SlicedViewTestCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params) 203 : vkt::TestCase(testCtx, name), m_params(params) {} 204 virtual ~SlicedViewTestCase (void) {} 205 206 void initPrograms (vk::SourceCollections& programCollection) const override; 207 TestInstance* createInstance (Context& context) const override; 208 void checkSupport (Context& context) const override; 209 210protected: 211 const TestParams m_params; 212}; 213 214class SlicedViewTestInstance : public vkt::TestInstance 215{ 216public: 217 SlicedViewTestInstance (Context& context, const TestParams& params) 218 : vkt::TestInstance(context), m_params (params) 219 {} 220 virtual ~SlicedViewTestInstance (void) {} 221 222protected: 223 virtual void runPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer, const VkImageView slicedImage, const VkImageView auxiliarImage); 224 virtual void runGraphicsPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer); 225 virtual void runComputePipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer); 226 bool runSamplingPipeline (const VkImage fullImage, const VkImageView slicedView, const VkExtent3D& levelExtent); 227 228 const TestParams m_params; 229 230 Move<VkDescriptorSetLayout> m_setLayout; 231 Move<VkDescriptorPool> m_descriptorPool; 232 Move<VkDescriptorSet> m_descriptorSet; 233 Move<VkPipelineLayout> m_pipelineLayout; 234 235 // Only for graphics pipelines. 236 Move<VkRenderPass> m_renderPass; 237 Move<VkFramebuffer> m_framebuffer; 238 239 Move<VkPipeline> m_pipeline; 240}; 241 242class SlicedViewLoadTestInstance : public SlicedViewTestInstance 243{ 244public: 245 SlicedViewLoadTestInstance (Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {} 246 virtual ~SlicedViewLoadTestInstance (void) {} 247 248 tcu::TestStatus iterate (void); 249}; 250 251class SlicedViewStoreTestInstance : public SlicedViewTestInstance 252{ 253public: 254 SlicedViewStoreTestInstance (Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {} 255 virtual ~SlicedViewStoreTestInstance (void) {} 256 257 tcu::TestStatus iterate (void); 258}; 259 260void SlicedViewTestCase::checkSupport (Context &context) const 261{ 262 context.requireDeviceFunctionality(VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME); 263 264 if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT) 265 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS); 266} 267 268void SlicedViewTestCase::initPrograms(vk::SourceCollections &programCollection) const 269{ 270 const std::string bindings = 271 "layout (rgba8ui, set=0, binding=0) uniform uimage3D slicedImage;\n" 272 "layout (rgba8ui, set=0, binding=1) uniform uimage3D auxiliarImage;\n" 273 ; 274 275 std::string loadFrom; 276 std::string storeTo; 277 278 // We may need to load stuff from the sliced image into an auxiliary image if we're testing load, or we may need to store stuff 279 // to the sliced image, read from the auxiliary image if we're testing stores. 280 if (m_params.testType == TestType::LOAD) 281 { 282 loadFrom = "slicedImage"; 283 storeTo = "auxiliarImage"; 284 } 285 else if (m_params.testType == TestType::STORE) 286 { 287 loadFrom = "auxiliarImage"; 288 storeTo = "slicedImage"; 289 } 290 else 291 DE_ASSERT(false); 292 293 std::ostringstream mainOperation; 294 295 // Note: "coords" will vary depending on the shader stage. 296 mainOperation 297 << " const ivec3 size = imageSize(slicedImage);\n" 298 << " const uvec4 badColor = uvec4(0, 0, 0, 0);\n" 299 << " const uvec4 goodColor = imageLoad(" << loadFrom << ", coords);\n" 300 << " const uvec4 storedColor = ((size.z == " << m_params.getActualRange() << ") ? goodColor : badColor);\n" 301 << " imageStore(" << storeTo << ", coords, storedColor);\n" 302 ; 303 304 if (m_params.stage == VK_SHADER_STAGE_COMPUTE_BIT) 305 { 306 // For compute, we'll launch as many workgroups as slices, and each invocation will handle one pixel. 307 const auto sliceExtent = m_params.getSliceExtent(); 308 std::ostringstream comp; 309 comp 310 << "#version 460\n" 311 << "layout (local_size_x=" << sliceExtent.width << ", local_size_y=" << sliceExtent.height << ", local_size_z=1) in;\n" 312 << bindings 313 << "void main (void) {\n" 314 << " const ivec3 coords = ivec3(ivec2(gl_LocalInvocationID.xy), int(gl_WorkGroupID.x));\n" 315 << mainOperation.str() 316 << "}\n" 317 ; 318 programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str()); 319 } 320 else if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT) 321 { 322 // For fragment, we'll draw as many instances as slices, and each draw will use a full-screen triangle to generate as many 323 // fragment shader invocations as pixels in the image (the framebuffer needs to have the same size as the storage images). 324 std::ostringstream frag; 325 frag 326 << "#version 460\n" 327 << "layout (location=0) in flat int zCoord;\n" 328 << bindings 329 << "void main (void) {\n" 330 << " const ivec3 coords = ivec3(ivec2(gl_FragCoord.xy), zCoord);\n" 331 << mainOperation.str() 332 << "}\n" 333 ; 334 335 std::ostringstream vert; 336 vert 337 << "#version 460\n" 338 << "layout (location=0) out flat int zCoord;\n" 339 << "vec2 positions[3] = vec2[](\n" 340 << " vec2(-1.0, -1.0),\n" 341 << " vec2( 3.0, -1.0),\n" 342 << " vec2(-1.0, 3.0)\n" 343 << ");\n" 344 << "void main() {\n" 345 << " gl_Position = vec4(positions[gl_VertexIndex % 3], 0.0, 1.0);\n" 346 << " zCoord = int(gl_InstanceIndex);\n" 347 << "}\n" 348 ; 349 350 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()); 351 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); 352 } 353 else 354 { 355 DE_ASSERT(false); 356 } 357 358 if (m_params.sampleImg) 359 { 360 // Prepare a compute shader that will sample the whole level to verify it's available. 361 const auto levelExtent = m_params.getFullLevelExtent(); 362 363 std::ostringstream comp; 364 comp 365 << "#version 460\n" 366 << "layout (local_size_x=" << levelExtent.width << ", local_size_y=" << levelExtent.height << ", local_size_z=" << levelExtent.depth << ") in;\n" 367 << "layout (set=0, binding=0) uniform usampler3D combinedSampler;\n" // The image being tested. 368 << "layout (set=0, binding=1, rgba8ui) uniform uimage3D auxiliarImage;\n" // Verification storage image. 369 << "void main() {\n" 370 << " const vec3 levelExtent = vec3(" << levelExtent.width << ", " << levelExtent.height << ", " << levelExtent.depth << ");\n" 371 << " const vec3 sampleCoords = vec3(\n" 372 << " (float(gl_LocalInvocationID.x) + 0.5) / levelExtent.x,\n" 373 << " (float(gl_LocalInvocationID.y) + 0.5) / levelExtent.y,\n" 374 << " (float(gl_LocalInvocationID.z) + 0.5) / levelExtent.z);\n" 375 << " const ivec3 storeCoords = ivec3(int(gl_LocalInvocationID.x), int(gl_LocalInvocationID.y), int(gl_LocalInvocationID.z));\n" 376 << " const uvec4 sampledColor = texture(combinedSampler, sampleCoords);\n" 377 << " imageStore(auxiliarImage, storeCoords, sampledColor);\n" 378 << "}\n" 379 ; 380 programCollection.glslSources.add("compSample") << glu::ComputeSource(comp.str()); 381 } 382} 383 384TestInstance* SlicedViewTestCase::createInstance (Context& context) const 385{ 386 if (m_params.testType == TestType::LOAD) 387 return new SlicedViewLoadTestInstance(context, m_params); 388 if (m_params.testType == TestType::STORE) 389 return new SlicedViewStoreTestInstance(context, m_params); 390 391 DE_ASSERT(false); 392 return nullptr; 393} 394 395tcu::IVec3 makeIVec3 (uint32_t width, uint32_t height, uint32_t depth) 396{ 397 return tcu::IVec3(static_cast<int>(width), static_cast<int>(height), static_cast<int>(depth)); 398} 399 400de::MovePtr<tcu::PixelBufferAccess> makePixelBufferAccess (const BufferWithMemory& buffer, const tcu::IVec3& size, const tcu::TextureFormat& format) 401{ 402 de::MovePtr<tcu::PixelBufferAccess> bufferImage (new tcu::PixelBufferAccess(format, size, buffer.getAllocation().getHostPtr())); 403 return bufferImage; 404} 405 406de::MovePtr<BufferWithMemory> makeTransferBuffer (const VkExtent3D& extent, const tcu::TextureFormat& format, 407 const DeviceInterface& vkd, const VkDevice device, Allocator& alloc) 408{ 409 DE_ASSERT(extent.width > 0u); 410 DE_ASSERT(extent.height > 0u); 411 DE_ASSERT(extent.depth > 0u); 412 413 const auto pixelSizeBytes = tcu::getPixelSize(format); 414 const auto pixelCount = extent.width * extent.height * extent.depth; 415 const auto bufferSize = static_cast<VkDeviceSize>(pixelCount) * static_cast<VkDeviceSize>(pixelSizeBytes); 416 const auto bufferUsage = (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); 417 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, bufferUsage); 418 419 de::MovePtr<BufferWithMemory> buffer (new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)); 420 return buffer; 421} 422 423de::MovePtr<BufferWithMemory> makeAndFillTransferBuffer (const VkExtent3D& extent, const tcu::TextureFormat& format, 424 const DeviceInterface& vkd, const VkDevice device, Allocator& alloc) 425{ 426 DE_ASSERT(tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER); 427 428 auto buffer = makeTransferBuffer(extent, format, vkd, device, alloc); 429 const auto size = makeIVec3(extent.width, extent.height, extent.depth); 430 auto bufferImg = makePixelBufferAccess(*buffer, size, format); 431 432 // Fill image with predefined pattern. 433 for (int z = 0; z < size.z(); ++z) 434 for (int y = 0; y < size.y(); ++y) 435 for (int x = 0; x < size.x(); ++x) 436 { 437 const tcu::UVec4 color ( 438 static_cast<uint32_t>(0x80 | x), 439 static_cast<uint32_t>(0x80 | y), 440 static_cast<uint32_t>(0x80 | z), 441 1u 442 ); 443 bufferImg->setPixel(color, x, y, z); 444 } 445 446 return buffer; 447} 448 449de::MovePtr<ImageWithMemory> make3DImage (const DeviceInterface &vkd, const VkDevice device, Allocator& alloc, const VkFormat format, const VkExtent3D& extent, uint32_t mipLevels, const bool sampling) 450{ 451 const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT 452 | (sampling ? VK_IMAGE_USAGE_SAMPLED_BIT : static_cast<VkImageUsageFlagBits>(0))); 453 454 const VkImageCreateInfo imageCreateInfo = 455 { 456 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 457 nullptr, // const void* pNext; 458 0u, // VkImageCreateFlags flags; 459 VK_IMAGE_TYPE_3D, // VkImageType imageType; 460 format, // VkFormat format; 461 extent, // VkExtent3D extent; 462 mipLevels, // uint32_t mipLevels; 463 1u, // uint32_t arrayLayers; 464 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 465 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 466 imageUsage, // VkImageUsageFlags usage; 467 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 468 0u, // uint32_t queueFamilyIndexCount; 469 nullptr, // const uint32_t* pQueueFamilyIndices; 470 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 471 }; 472 473 de::MovePtr<ImageWithMemory> image (new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any)); 474 return image; 475} 476 477VkImageSubresourceRange makeCommonImageSubresourceRange (uint32_t baseLevel, uint32_t levelCount) 478{ 479 return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, baseLevel, levelCount, 0u, 1u); 480} 481 482VkImageSubresourceLayers makeCommonImageSubresourceLayers (uint32_t mipLevel) 483{ 484 return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0u, 1u); 485} 486 487Move<VkImageView> make3DImageView (const DeviceInterface &vkd, const VkDevice device, const VkImage image, const VkFormat format, 488 const tcu::Maybe<tcu::UVec2>& slices/*x=offset, y=range)*/, uint32_t mipLevel, uint32_t levelCount) 489{ 490 const bool subSlice = static_cast<bool>(slices); 491 492 VkImageViewSlicedCreateInfoEXT sliceCreateInfo = initVulkanStructure(); 493 494 if (subSlice) 495 { 496 sliceCreateInfo.sliceOffset = slices->x(); 497 sliceCreateInfo.sliceCount = slices->y(); 498 } 499 500 const VkImageViewCreateInfo viewCreateInfo = 501 { 502 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; 503 (subSlice ? &sliceCreateInfo : nullptr), // const void* pNext; 504 0u, // VkImageViewCreateFlags flags; 505 image, // VkImage image; 506 VK_IMAGE_VIEW_TYPE_3D, // VkImageViewType viewType; 507 format, // VkFormat format; 508 makeComponentMappingRGBA(), // VkComponentMapping components; 509 makeCommonImageSubresourceRange(mipLevel, levelCount), // VkImageSubresourceRange subresourceRange; 510 }; 511 512 return createImageView(vkd, device, &viewCreateInfo); 513} 514 515VkPipelineStageFlagBits makePipelineStage (VkShaderStageFlagBits shaderStage) 516{ 517 if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT) 518 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 519 if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT) 520 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 521 522 DE_ASSERT(false); 523 return VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM; 524} 525 526void SlicedViewTestInstance::runPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer, const VkImageView slicedImage, const VkImageView auxiliarImage) 527{ 528 // The layouts created and used here must match the shaders. 529 const auto descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 530 531 DescriptorSetLayoutBuilder layoutBuilder; 532 layoutBuilder.addSingleBinding(descriptorType, m_params.stage); 533 layoutBuilder.addSingleBinding(descriptorType, m_params.stage); 534 m_setLayout = layoutBuilder.build(vkd, device); 535 536 DescriptorPoolBuilder poolBuilder; 537 poolBuilder.addType(descriptorType, 2u); 538 m_descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 539 540 m_descriptorSet = makeDescriptorSet(vkd, device, m_descriptorPool.get(), m_setLayout.get()); 541 m_pipelineLayout = makePipelineLayout(vkd, device, m_setLayout.get()); 542 543 DescriptorSetUpdateBuilder updateBuilder; 544 const auto slicedImageDescInfo = makeDescriptorImageInfo(DE_NULL, slicedImage, kUsageLayout); 545 const auto auxiliarImageDescInfo = makeDescriptorImageInfo(DE_NULL, auxiliarImage, kUsageLayout); 546 updateBuilder.writeSingle(m_descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &slicedImageDescInfo); 547 updateBuilder.writeSingle(m_descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &auxiliarImageDescInfo); 548 updateBuilder.update(vkd, device); 549 550 if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT) 551 runGraphicsPipeline(vkd, device, cmdBuffer); 552 else if (m_params.stage == VK_SHADER_STAGE_COMPUTE_BIT) 553 runComputePipeline(vkd, device, cmdBuffer); 554 else 555 DE_ASSERT(false); 556} 557 558void SlicedViewTestInstance::runGraphicsPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer) 559{ 560 const auto sliceExtent = m_params.getSliceExtent(); 561 const auto& binaries = m_context.getBinaryCollection(); 562 const auto vertShader = createShaderModule(vkd, device, binaries.get("vert")); 563 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag")); 564 const auto extent = makeExtent3D(sliceExtent.width, sliceExtent.height, 1u); 565 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 566 567 m_renderPass = makeRenderPass(vkd, device); 568 m_framebuffer = makeFramebuffer(vkd, device, m_renderPass.get(), 0u, nullptr, sliceExtent.width, sliceExtent.height); 569 570 const std::vector<VkViewport> viewports (1u, makeViewport(extent)); 571 const std::vector<VkRect2D> scissors (1u, makeRect2D(extent)); 572 573 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure(); 574 575 m_pipeline = makeGraphicsPipeline(vkd, device, m_pipelineLayout.get(), 576 vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(), 577 m_renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, 578 &vertexInputStateCreateInfo); 579 580 beginRenderPass(vkd, cmdBuffer, m_renderPass.get(), m_framebuffer.get(), scissors.at(0u)); 581 vkd.cmdBindPipeline(cmdBuffer, bindPoint, m_pipeline.get()); 582 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr); 583 vkd.cmdDraw(cmdBuffer, kVertexCount, sliceExtent.depth, 0u, 0u); 584 endRenderPass(vkd, cmdBuffer); 585} 586 587void SlicedViewTestInstance::runComputePipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer) 588{ 589 const auto bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; 590 const auto compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp")); 591 592 m_pipeline = makeComputePipeline(vkd, device, m_pipelineLayout.get(), compShader.get()); 593 594 vkd.cmdBindPipeline(cmdBuffer, bindPoint, m_pipeline.get()); 595 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr); 596 vkd.cmdDispatch(cmdBuffer, m_params.getActualRange(), 1u, 1u); 597} 598 599bool SlicedViewTestInstance::runSamplingPipeline (const VkImage fullImage, const VkImageView slicedView, const VkExtent3D& levelExtent) 600{ 601 const auto& vkd = m_context.getDeviceInterface(); 602 const auto device = m_context.getDevice(); 603 const auto qfIndex = m_context.getUniversalQueueFamilyIndex(); 604 const auto queue = m_context.getUniversalQueue(); 605 auto& alloc = m_context.getDefaultAllocator(); 606 607 const auto bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; 608 const auto shaderStage = VK_SHADER_STAGE_COMPUTE_BIT; 609 const auto pipelineStage = makePipelineStage(shaderStage); 610 611 // Command pool and buffer. 612 const auto cmdPool = makeCommandPool(vkd, device, qfIndex); 613 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); 614 const auto cmdBuffer = cmdBufferPtr.get(); 615 616 // Descriptor set layout and pipeline layout. 617 DescriptorSetLayoutBuilder setLayoutBuilder; 618 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage); 619 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage); 620 const auto setLayout = setLayoutBuilder.build(vkd, device); 621 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get()); 622 623 // Pipeline. 624 const auto compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("compSample")); 625 const auto pipeline = makeComputePipeline(vkd, device, pipelineLayout.get(), compShader.get()); 626 627 // Descriptor pool and set. 628 DescriptorPoolBuilder poolBuilder; 629 poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); 630 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); 631 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 632 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get()); 633 634 // Update descriptor set. 635 const VkSamplerCreateInfo samplerCreateInfo = 636 { 637 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType; 638 nullptr, // const void* pNext; 639 0u, // VkSamplerCreateFlags flags; 640 VK_FILTER_NEAREST, // VkFilter magFilter; 641 VK_FILTER_NEAREST, // VkFilter minFilter; 642 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode; 643 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeU; 644 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeV; 645 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeW; 646 0.0f, // float mipLodBias; 647 VK_FALSE, // VkBool32 anisotropyEnable; 648 1.0f, // float maxAnisotropy; 649 VK_FALSE, // VkBool32 compareEnable; 650 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; 651 0.0f, // float minLod; 652 0.0f, // float maxLod; 653 VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, // VkBorderColor borderColor; 654 VK_FALSE, // VkBool32 unnormalizedCoordinates; 655 }; 656 const auto sampler = createSampler(vkd, device, &samplerCreateInfo); 657 658 // This will be used as a storage image to verify the sampling results. 659 // It has the same size as the full level extent, but only a single level and not sliced. 660 const auto auxiliarImage = make3DImage(vkd, device, alloc, kFormat, levelExtent, 1u, false/*sampling*/); 661 const auto auxiliarView = make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u); 662 663 DescriptorSetUpdateBuilder updateBuilder; 664 const auto sampledImageInfo = makeDescriptorImageInfo(sampler.get(), slicedView, kUsageLayout); 665 const auto storageImageInfo = makeDescriptorImageInfo(DE_NULL, auxiliarView.get(), kUsageLayout); 666 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &sampledImageInfo); 667 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImageInfo); 668 updateBuilder.update(vkd, device); 669 670 const auto tcuFormat = mapVkFormat(kFormat); 671 const auto verifBuffer = makeTransferBuffer(levelExtent, tcuFormat, vkd, device, alloc); 672 const auto refBuffer = makeTransferBuffer(levelExtent, tcuFormat, vkd, device, alloc); 673 674 beginCommandBuffer(vkd, cmdBuffer); 675 676 // Move auxiliar image to the proper layout. 677 const auto shaderAccess = (VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT); 678 const auto colorSRR = makeCommonImageSubresourceRange(0u, 1u); 679 const auto preDispatchBarrier = makeImageMemoryBarrier(0u, shaderAccess, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, auxiliarImage->get(), colorSRR); 680 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, pipelineStage, &preDispatchBarrier); 681 682 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get()); 683 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr); 684 vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u); 685 686 // Sync shader writes before copying to verification buffer. 687 const auto preCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); 688 cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier); 689 690 // Copy storage image to verification buffer. 691 const auto colorSRL = makeCommonImageSubresourceLayers(0u); 692 const auto copyRegion = makeBufferImageCopy(levelExtent, colorSRL); 693 vkd.cmdCopyImageToBuffer(cmdBuffer, auxiliarImage->get(), kUsageLayout, verifBuffer->get(), 1u, ©Region); 694 695 // Copy full level from the original full image to the reference buffer to compare them. 696 const auto refSRL = makeCommonImageSubresourceLayers(m_params.getSelectedLevel()); 697 const auto refCopy = makeBufferImageCopy(levelExtent, refSRL); 698 vkd.cmdCopyImageToBuffer(cmdBuffer, fullImage, kUsageLayout, refBuffer->get(), 1u, &refCopy); 699 700 // Sync copies to host. 701 const auto postCopyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); 702 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyBarrier); 703 704 endCommandBuffer(vkd, cmdBuffer); 705 submitCommandsAndWait(vkd, device, queue, cmdBuffer); 706 707 // Compare both buffers. 708 auto& verifBufferAlloc = verifBuffer->getAllocation(); 709 auto& refBufferAlloc = refBuffer->getAllocation(); 710 invalidateAlloc(vkd, device, verifBufferAlloc); 711 invalidateAlloc(vkd, device, refBufferAlloc); 712 713 const auto iExtent = makeIVec3(levelExtent.width, levelExtent.height, levelExtent.depth); 714 const tcu::ConstPixelBufferAccess verifAcces (tcuFormat, iExtent, verifBufferAlloc.getHostPtr()); 715 const tcu::ConstPixelBufferAccess refAccess (tcuFormat, iExtent, refBufferAlloc.getHostPtr()); 716 717 auto& log = m_context.getTestContext().getLog(); 718 const tcu::UVec4 threshold (0u, 0u, 0u, 0u); 719 return tcu::intThresholdCompare(log, "SamplingResult", "", refAccess, verifAcces, threshold, tcu::COMPARE_LOG_ON_ERROR); 720} 721 722tcu::TestStatus SlicedViewLoadTestInstance::iterate (void) 723{ 724 const auto& vkd = m_context.getDeviceInterface(); 725 const auto device = m_context.getDevice(); 726 auto& alloc = m_context.getDefaultAllocator(); 727 const auto qfIndex = m_context.getUniversalQueueFamilyIndex(); 728 const auto queue = m_context.getUniversalQueue(); 729 730 const auto mipLevel = m_params.getSelectedLevel(); 731 const auto fullExtent = makeExtent3D(m_params.width, m_params.height, m_params.depth); 732 const auto sliceExtent = m_params.getSliceExtent(); 733 const auto tcuFormat = mapVkFormat(kFormat); 734 const auto auxiliarBuffer = makeAndFillTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc); 735 const auto verifBuffer = makeTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc); 736 const auto fullImage = make3DImage(vkd, device, alloc, kFormat, fullExtent, m_params.getFullImageLevels(), m_params.sampleImg); 737 const auto fullSRR = makeCommonImageSubresourceRange(0u, VK_REMAINING_MIP_LEVELS); 738 const auto singleSRR = makeCommonImageSubresourceRange(0u, 1u); 739 const auto targetLevelSRL = makeCommonImageSubresourceLayers(mipLevel); 740 const auto baseLevelSRL = makeCommonImageSubresourceLayers(0u); 741 const auto clearColor = makeClearValueColorU32(0u, 0u, 0u, 0u); 742 const auto pipelineStage = makePipelineStage(m_params.stage); 743 744 const auto cmdPool = makeCommandPool(vkd, device, qfIndex); 745 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); 746 const auto cmdBuffer = cmdBufferPtr.get(); 747 748 beginCommandBuffer(vkd, cmdBuffer); 749 750 // Zero-out full image. 751 const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, 752 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 753 fullImage->get(), fullSRR); 754 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier); 755 vkd.cmdClearColorImage(cmdBuffer, fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &fullSRR); 756 757 // Copy reference buffer to full image at the right offset. 758 const auto preCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 759 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 760 fullImage->get(), fullSRR); 761 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier); 762 763 const VkBufferImageCopy sliceCopy = 764 { 765 0ull, // VkDeviceSize bufferOffset; 766 0u, // deUint32 bufferRowLength; 767 0u, // deUint32 bufferImageHeight; 768 targetLevelSRL, // VkImageSubresourceLayers imageSubresource; 769 makeOffset3D(0, 0, static_cast<int32_t>(m_params.offset)), // VkOffset3D imageOffset; 770 sliceExtent, // VkExtent3D imageExtent; 771 }; 772 vkd.cmdCopyBufferToImage(cmdBuffer, auxiliarBuffer->get(), fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &sliceCopy); 773 774 // Move full image to the general layout to be able to read from or write to it from the shader. 775 // Note: read-only optimal is not a valid layout for this. 776 const auto postCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, 777 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, 778 fullImage->get(), fullSRR); 779 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &postCopyBarrier); 780 781 // Create sliced view of the full image. 782 const auto slicedView = make3DImageView(vkd, device, fullImage->get(), kFormat, tcu::just(tcu::UVec2(m_params.offset, m_params.getSlicedViewRange())), mipLevel, 1u); 783 784 // Create storage image and view with reduced size (this will be the destination image in the shader). 785 const auto auxiliarImage = make3DImage(vkd, device, alloc, kFormat, sliceExtent, 1u, false/*sampling*/); 786 const auto auxiliarView = make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u); 787 788 // Move the auxiliar image to the general layout for writing. 789 const auto preWriteBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, kUsageLayout, auxiliarImage->get(), singleSRR); 790 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, pipelineStage, &preWriteBarrier); 791 792 // Run load operation. 793 runPipeline(vkd, device, cmdBuffer, slicedView.get(), auxiliarView.get()); 794 795 // Copy auxiliar image (result) to verification buffer. 796 const auto preVerifCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); 797 cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preVerifCopyBarrier); 798 const auto verifCopyRegion = makeBufferImageCopy(sliceExtent, baseLevelSRL); 799 vkd.cmdCopyImageToBuffer(cmdBuffer, auxiliarImage->get(), kUsageLayout, verifBuffer->get(), 1u, &verifCopyRegion); 800 801 // Sync verification buffer with host reads. 802 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); 803 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier); 804 805 endCommandBuffer(vkd, cmdBuffer); 806 submitCommandsAndWait(vkd, device, queue, cmdBuffer); 807 808 const auto sliceExtentIV3 = makeIVec3(sliceExtent.width, sliceExtent.height, sliceExtent.depth); 809 auto& auxiliarBufferAlloc = auxiliarBuffer->getAllocation(); 810 auto& verifBufferAlloc = verifBuffer->getAllocation(); 811 812 // Invalidate verification buffer allocation. 813 invalidateAlloc(vkd, device, verifBufferAlloc); 814 815 // Compare auxiliar buffer and verification buffer. 816 const tcu::ConstPixelBufferAccess initialImage (tcuFormat, sliceExtentIV3, auxiliarBufferAlloc.getHostPtr()); 817 const tcu::ConstPixelBufferAccess finalImage (tcuFormat, sliceExtentIV3, verifBufferAlloc.getHostPtr()); 818 819 auto& log = m_context.getTestContext().getLog(); 820 const tcu::UVec4 threshold(0u, 0u, 0u, 0u); 821 822 if (!tcu::intThresholdCompare(log, "Comparison", "Comparison of reference and result", initialImage, finalImage, threshold, tcu::COMPARE_LOG_ON_ERROR)) 823 return tcu::TestStatus::fail("Image comparison failed; check log for details"); 824 825 if (m_params.sampleImg && !runSamplingPipeline(fullImage->get(), slicedView.get(), m_params.getFullLevelExtent())) 826 return tcu::TestStatus::fail("Sampling full level failed; check log for details"); 827 828 return tcu::TestStatus::pass("Pass"); 829} 830 831tcu::TestStatus SlicedViewStoreTestInstance::iterate (void) 832{ 833 const auto& vkd = m_context.getDeviceInterface(); 834 const auto device = m_context.getDevice(); 835 auto& alloc = m_context.getDefaultAllocator(); 836 const auto qfIndex = m_context.getUniversalQueueFamilyIndex(); 837 const auto queue = m_context.getUniversalQueue(); 838 839 const auto mipLevel = m_params.getSelectedLevel(); 840 const auto fullExtent = makeExtent3D(m_params.width, m_params.height, m_params.depth); 841 const auto sliceExtent = m_params.getSliceExtent(); 842 const auto tcuFormat = mapVkFormat(kFormat); 843 const auto auxiliarBuffer = makeAndFillTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc); 844 const auto verifBuffer = makeTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc); 845 const auto fullImage = make3DImage(vkd, device, alloc, kFormat, fullExtent, m_params.getFullImageLevels(), m_params.sampleImg); 846 const auto fullSRR = makeCommonImageSubresourceRange(0u, VK_REMAINING_MIP_LEVELS); 847 const auto singleSRR = makeCommonImageSubresourceRange(0u, 1u); 848 const auto targetLevelSRL = makeCommonImageSubresourceLayers(mipLevel); 849 const auto baseLevelSRL = makeCommonImageSubresourceLayers(0u); 850 const auto clearColor = makeClearValueColorU32(0u, 0u, 0u, 0u); 851 const auto pipelineStage = makePipelineStage(m_params.stage); 852 853 const auto cmdPool = makeCommandPool(vkd, device, qfIndex); 854 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); 855 const auto cmdBuffer = cmdBufferPtr.get(); 856 857 beginCommandBuffer(vkd, cmdBuffer); 858 859 // Zero-out full image. 860 const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, fullImage->get(), fullSRR); 861 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier); 862 vkd.cmdClearColorImage(cmdBuffer, fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &fullSRR); 863 864 // Create sliced view of the full image. 865 const auto slicedView = make3DImageView(vkd, device, fullImage->get(), kFormat, tcu::just(tcu::UVec2(m_params.offset, m_params.getSlicedViewRange())), mipLevel, 1u); 866 867 // Create storage image and view with reduced size (this will be the source image in the shader). 868 const auto auxiliarImage = make3DImage(vkd, device, alloc, kFormat, sliceExtent, 1u, false/*sampling*/); 869 const auto auxiliarView = make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u); 870 871 // Copy reference buffer into auxiliar image. 872 const auto preCopyBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, auxiliarImage->get(), singleSRR); 873 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier); 874 const auto sliceCopy = makeBufferImageCopy(sliceExtent, baseLevelSRL); 875 vkd.cmdCopyBufferToImage(cmdBuffer, auxiliarBuffer->get(), auxiliarImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &sliceCopy); 876 877 // Move both images to the general layout for reading and writing. 878 // Note: read-only optimal is not a valid layout for the read image. 879 const auto preShaderBarrierAux = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, auxiliarImage->get(), singleSRR); 880 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &preShaderBarrierAux); 881 const auto preShaderBarrierFull = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, fullImage->get(), fullSRR); 882 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &preShaderBarrierFull); 883 884 // Run store operation. 885 runPipeline(vkd, device, cmdBuffer, slicedView.get(), auxiliarView.get()); 886 887 // Copy the right section of the full image (result) to verification buffer. 888 const auto preVerifCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); 889 cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preVerifCopyBarrier); 890 891 const VkBufferImageCopy verifCopy = 892 { 893 0ull, // VkDeviceSize bufferOffset; 894 0u, // deUint32 bufferRowLength; 895 0u, // deUint32 bufferImageHeight; 896 targetLevelSRL, // VkImageSubresourceLayers imageSubresource; 897 makeOffset3D(0, 0, static_cast<int32_t>(m_params.offset)), // VkOffset3D imageOffset; 898 sliceExtent, // VkExtent3D imageExtent; 899 }; 900 vkd.cmdCopyImageToBuffer(cmdBuffer, fullImage->get(), kUsageLayout, verifBuffer->get(), 1u, &verifCopy); 901 902 // Sync verification buffer with host reads. 903 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT); 904 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier); 905 906 endCommandBuffer(vkd, cmdBuffer); 907 submitCommandsAndWait(vkd, device, queue, cmdBuffer); 908 909 const auto sliceExtentIV3 = makeIVec3(sliceExtent.width, sliceExtent.height, sliceExtent.depth); 910 auto& auxiliarBufferAlloc = auxiliarBuffer->getAllocation(); 911 auto& verifBufferAlloc = verifBuffer->getAllocation(); 912 913 // Invalidate verification buffer allocation. 914 invalidateAlloc(vkd, device, verifBufferAlloc); 915 916 // Compare auxiliar buffer and verification buffer. 917 const tcu::ConstPixelBufferAccess initialImage (tcuFormat, sliceExtentIV3, auxiliarBufferAlloc.getHostPtr()); 918 const tcu::ConstPixelBufferAccess finalImage (tcuFormat, sliceExtentIV3, verifBufferAlloc.getHostPtr()); 919 920 auto& log = m_context.getTestContext().getLog(); 921 const tcu::UVec4 threshold(0u, 0u, 0u, 0u); 922 923 if (!tcu::intThresholdCompare(log, "Comparison", "Comparison of reference and result", initialImage, finalImage, threshold, tcu::COMPARE_LOG_ON_ERROR)) 924 return tcu::TestStatus::fail("Image comparison failed; check log for details"); 925 926 if (m_params.sampleImg && !runSamplingPipeline(fullImage->get(), slicedView.get(), m_params.getFullLevelExtent())) 927 return tcu::TestStatus::fail("Sampling full level failed; check log for details"); 928 929 return tcu::TestStatus::pass("Pass"); 930} 931 932using TestCaseGroupPtr = de::MovePtr<tcu::TestCaseGroup>; 933 934} // anonymous 935 936tcu::TestCaseGroup* createImageSlicedViewOf3DTests (tcu::TestContext& testCtx) 937{ 938 TestCaseGroupPtr imageTests (new tcu::TestCaseGroup(testCtx, "sliced_view_of_3d_image")); 939 940 const struct 941 { 942 VkShaderStageFlagBits stage; 943 const char* name; 944 } stageCases[] = 945 { 946 { VK_SHADER_STAGE_COMPUTE_BIT, "comp" }, 947 { VK_SHADER_STAGE_FRAGMENT_BIT, "frag" }, 948 }; 949 950 const struct 951 { 952 TestType testType; 953 const char* name; 954 } testTypeCases[] = 955 { 956 { TestType::LOAD, "load" }, 957 { TestType::STORE, "store" }, 958 }; 959 960 const struct 961 { 962 bool sampleImg; 963 const char* suffix; 964 } samplingCases[] = 965 { 966 { false, "" }, 967 { true, "_with_sampling" }, 968 }; 969 970 const uint32_t seed = 1667817299u; 971 de::Random rnd (seed); 972 973 // Basic tests with 2 slices and a view of the first or second slice. 974 { 975 const uint32_t basicDepth = 2u; 976 const uint32_t basicRange = 1u; 977 978 TestCaseGroupPtr basicTests (new tcu::TestCaseGroup(testCtx, "basic")); 979 980 for (const auto& testTypeCase : testTypeCases) 981 { 982 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name)); 983 984 for (const auto& stageCase : stageCases) 985 { 986 TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name)); 987 988 for (uint32_t offset = 0u; offset < basicDepth; ++offset) 989 { 990 for (const auto& samplingCase : samplingCases) 991 { 992 const auto testName = "offset_" + std::to_string(offset) + samplingCase.suffix; 993 TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, basicDepth, offset, basicRange, tcu::Nothing, samplingCase.sampleImg); 994 995 stageGroup->addChild(new SlicedViewTestCase(testCtx, testName, params)); 996 } 997 } 998 999 testTypeGroup->addChild(stageGroup.release()); 1000 } 1001 1002 basicTests->addChild(testTypeGroup.release()); 1003 } 1004 1005 imageTests->addChild(basicTests.release()); 1006 } 1007 1008 // Full slice tests. 1009 { 1010 const uint32_t fullDepth = 4u; 1011 1012 TestCaseGroupPtr fullSliceTests (new tcu::TestCaseGroup(testCtx, "full_slice")); 1013 1014 for (const auto& testTypeCase : testTypeCases) 1015 { 1016 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name)); 1017 1018 for (const auto& stageCase : stageCases) 1019 { 1020 for (const auto& samplingCase : samplingCases) 1021 { 1022 const auto testName = std::string(stageCase.name) + samplingCase.suffix; 1023 TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, fullDepth, 0u, fullDepth, tcu::Nothing, samplingCase.sampleImg); 1024 testTypeGroup->addChild(new SlicedViewTestCase(testCtx, testName, params)); 1025 } 1026 } 1027 1028 fullSliceTests->addChild(testTypeGroup.release()); 1029 } 1030 1031 imageTests->addChild(fullSliceTests.release()); 1032 } 1033 1034 // Pseudorandom test cases. 1035 { 1036 using CaseId = std::tuple<uint32_t, uint32_t, uint32_t>; // depth, offset, range 1037 using CaseIdSet = std::set<CaseId>; 1038 1039 const uint32_t depthCases = 5u; 1040 const uint32_t rangeCases = 5u; 1041 const int minDepth = 10u; 1042 const int maxDepth = 32u; 1043 1044 TestCaseGroupPtr randomTests (new tcu::TestCaseGroup(testCtx, "random")); 1045 1046 for (const auto& testTypeCase : testTypeCases) 1047 { 1048 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name)); 1049 1050 for (const auto& stageCase : stageCases) 1051 { 1052 TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name)); 1053 1054 CaseIdSet generatedCases; 1055 1056 for (uint32_t i = 0u; i < depthCases; ++i) 1057 { 1058 const uint32_t depth = static_cast<uint32_t>(rnd.getInt(minDepth, maxDepth)); 1059 1060 for (uint32_t j = 0u; j < rangeCases; ++j) 1061 { 1062 uint32_t offset = 0u; 1063 uint32_t range = 0u; 1064 1065 for (;;) 1066 { 1067 DE_ASSERT(depth > 0u); 1068 offset = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(depth - 1u))); 1069 1070 DE_ASSERT(offset < depth); 1071 range = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(depth - offset))); 1072 1073 // 0 is interpreted as VK_REMAINING_3D_SLICES_EXT. 1074 if (range == 0u) 1075 range = VK_REMAINING_3D_SLICES_EXT; 1076 1077 // The current seed may generate duplicate cases with non-unique names, so we filter those out. 1078 const CaseId currentCase (depth, offset, range); 1079 if (de::contains(begin(generatedCases), end(generatedCases), currentCase)) 1080 continue; 1081 1082 generatedCases.insert(currentCase); 1083 break; 1084 } 1085 1086 const auto rangeStr = ((range == VK_REMAINING_3D_SLICES_EXT) ? "remaining_3d_slices" : std::to_string(range)); 1087 const auto testName = "depth_" + std::to_string(depth) + "_offset_" + std::to_string(offset) + "_range_" + rangeStr; 1088 TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, depth, offset, range, tcu::Nothing, false); 1089 1090 stageGroup->addChild(new SlicedViewTestCase(testCtx, testName, params)); 1091 } 1092 } 1093 1094 testTypeGroup->addChild(stageGroup.release()); 1095 } 1096 1097 randomTests->addChild(testTypeGroup.release()); 1098 } 1099 1100 imageTests->addChild(randomTests.release()); 1101 } 1102 1103 // Mip level test cases. 1104 { 1105 using CaseId = std::tuple<uint32_t, uint32_t>; // depth, offset, range 1106 using CaseIdSet = std::set<CaseId>; 1107 1108 const uint32_t casesPerLevel = 2u; 1109 const uint32_t width = kWidth; 1110 const uint32_t height = kWidth; 1111 const uint32_t depth = kWidth; 1112 const uint32_t maxLevels = TestParams::getMaxMipLevelCountForSize(kWidth); 1113 1114 TestCaseGroupPtr mipLevelTests (new tcu::TestCaseGroup(testCtx, "mip_level")); 1115 1116 for (const auto& testTypeCase : testTypeCases) 1117 { 1118 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name)); 1119 1120 for (const auto& stageCase : stageCases) 1121 { 1122 TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name)); 1123 1124 for (uint32_t level = 0u; level < maxLevels; ++level) 1125 { 1126 const auto levelSize = (depth >> level); 1127 const auto groupName = "level_" + std::to_string(level); 1128 CaseIdSet generatedCases; 1129 1130 DE_ASSERT(levelSize > 0u); 1131 1132 TestCaseGroupPtr levelGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str())); 1133 1134 // Generate a few pseudorandom cases per mip level. 1135 for (uint32_t i = 0u; i < casesPerLevel; ++i) 1136 { 1137 uint32_t offset = 0u; 1138 uint32_t range = 0u; 1139 1140 for (;;) 1141 { 1142 offset = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(levelSize - 1u))); 1143 DE_ASSERT(offset < levelSize); 1144 1145 range = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(levelSize - offset))); 1146 1147 // 0 is interpreted as VK_REMAINING_3D_SLICES_EXT. 1148 if (range == 0u) 1149 range = VK_REMAINING_3D_SLICES_EXT; 1150 1151 const CaseId currentCase (offset, range); 1152 if (de::contains(begin(generatedCases), end(generatedCases), currentCase)) 1153 continue; 1154 1155 generatedCases.insert(currentCase); 1156 break; 1157 } 1158 1159 const auto rangeStr = ((range == VK_REMAINING_3D_SLICES_EXT) ? "remaining_3d_slices" : std::to_string(range)); 1160 const auto testName = "offset_" + std::to_string(offset) + "_range_" + rangeStr; 1161 TestParams params (testTypeCase.testType, stageCase.stage, width, height, depth, offset, range, tcu::just(level), false); 1162 1163 levelGroup->addChild(new SlicedViewTestCase(testCtx, testName, params)); 1164 } 1165 1166 stageGroup->addChild(levelGroup.release()); 1167 } 1168 1169 testTypeGroup->addChild(stageGroup.release()); 1170 } 1171 1172 mipLevelTests->addChild(testTypeGroup.release()); 1173 } 1174 1175 imageTests->addChild(mipLevelTests.release()); 1176 } 1177 1178 return imageTests.release(); 1179} 1180 1181} // pipeline 1182} // vkt 1183