1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group 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 Sparse buffer tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktSparseResourcesBufferTests.hpp" 25 #include "vktTestCaseUtil.hpp" 26 #include "vktTestGroupUtil.hpp" 27 #include "vktSparseResourcesTestsUtil.hpp" 28 #include "vktSparseResourcesBase.hpp" 29 #include "vktSparseResourcesBufferSparseBinding.hpp" 30 #include "vktSparseResourcesBufferSparseResidency.hpp" 31 #include "vktSparseResourcesBufferMemoryAliasing.hpp" 32 33 #include "vkRef.hpp" 34 #include "vkRefUtil.hpp" 35 #include "vkPlatform.hpp" 36 #include "vkPrograms.hpp" 37 #include "vkMemUtil.hpp" 38 #include "vkBuilderUtil.hpp" 39 #include "vkQueryUtil.hpp" 40 #include "vkTypeUtil.hpp" 41 42 #include "tcuTestLog.hpp" 43 44 #include "deUniquePtr.hpp" 45 #include "deSharedPtr.hpp" 46 #include "deMath.h" 47 48 #include <string> 49 #include <vector> 50 #include <map> 51 52 using namespace vk; 53 using de::MovePtr; 54 using de::UniquePtr; 55 using de::SharedPtr; 56 using tcu::Vec4; 57 using tcu::IVec2; 58 using tcu::IVec4; 59 60 namespace vkt 61 { 62 namespace sparse 63 { 64 namespace 65 { 66 67 typedef SharedPtr<UniquePtr<Allocation> > AllocationSp; 68 69 enum 70 { 71 RENDER_SIZE = 128, //!< framebuffer size in pixels 72 GRID_SIZE = RENDER_SIZE / 8, //!< number of grid tiles in a row 73 }; 74 75 enum TestFlagBits 76 { 77 // sparseBinding is implied 78 TEST_FLAG_ALIASED = 1u << 0, //!< sparseResidencyAliased 79 TEST_FLAG_RESIDENCY = 1u << 1, //!< sparseResidencyBuffer 80 TEST_FLAG_NON_RESIDENT_STRICT = 1u << 2, //!< residencyNonResidentStrict 81 TEST_FLAG_ENABLE_DEVICE_GROUPS = 1u << 3, //!< device groups are enabled 82 }; 83 typedef deUint32 TestFlags; 84 85 //! SparseAllocationBuilder output. Owns the allocated memory. 86 struct SparseAllocation 87 { 88 deUint32 numResourceChunks; 89 VkDeviceSize resourceSize; //!< buffer size in bytes 90 std::vector<AllocationSp> allocations; //!< actual allocated memory 91 std::vector<VkSparseMemoryBind> memoryBinds; //!< memory binds backing the resource 92 }; 93 94 //! Utility to lay out memory allocations for a sparse buffer, including holes and aliased regions. 95 //! Will allocate memory upon building. 96 class SparseAllocationBuilder 97 { 98 public: 99 SparseAllocationBuilder (void); 100 101 // \note "chunk" is the smallest (due to alignment) bindable amount of memory 102 103 SparseAllocationBuilder& addMemoryHole (const deUint32 numChunks = 1u); 104 SparseAllocationBuilder& addResourceHole (const deUint32 numChunks = 1u); 105 SparseAllocationBuilder& addMemoryBind (const deUint32 numChunks = 1u); 106 SparseAllocationBuilder& addAliasedMemoryBind (const deUint32 allocationNdx, const deUint32 chunkOffset, const deUint32 numChunks = 1u); 107 SparseAllocationBuilder& addMemoryAllocation (void); 108 109 MovePtr<SparseAllocation> build (const DeviceInterface& vk, 110 const VkDevice device, 111 Allocator& allocator, 112 VkBufferCreateInfo referenceCreateInfo, //!< buffer size is ignored in this info 113 const VkDeviceSize minChunkSize = 0ull) const; //!< make sure chunks are at least this big 114 115 private: 116 struct MemoryBind 117 { 118 deUint32 allocationNdx; 119 deUint32 resourceChunkNdx; 120 deUint32 memoryChunkNdx; 121 deUint32 numChunks; 122 }; 123 124 deUint32 m_allocationNdx; 125 deUint32 m_resourceChunkNdx; 126 deUint32 m_memoryChunkNdx; 127 std::vector<MemoryBind> m_memoryBinds; 128 std::vector<deUint32> m_chunksPerAllocation; 129 130 }; 131 132 SparseAllocationBuilder::SparseAllocationBuilder (void) 133 : m_allocationNdx (0) 134 , m_resourceChunkNdx (0) 135 , m_memoryChunkNdx (0) 136 { 137 m_chunksPerAllocation.push_back(0); 138 } 139 140 SparseAllocationBuilder& SparseAllocationBuilder::addMemoryHole (const deUint32 numChunks) 141 { 142 m_memoryChunkNdx += numChunks; 143 m_chunksPerAllocation[m_allocationNdx] += numChunks; 144 145 return *this; 146 } 147 148 SparseAllocationBuilder& SparseAllocationBuilder::addResourceHole (const deUint32 numChunks) 149 { 150 m_resourceChunkNdx += numChunks; 151 152 return *this; 153 } 154 155 SparseAllocationBuilder& SparseAllocationBuilder::addMemoryAllocation (void) 156 { 157 DE_ASSERT(m_memoryChunkNdx != 0); // doesn't make sense to have an empty allocation 158 159 m_allocationNdx += 1; 160 m_memoryChunkNdx = 0; 161 m_chunksPerAllocation.push_back(0); 162 163 return *this; 164 } 165 166 SparseAllocationBuilder& SparseAllocationBuilder::addMemoryBind (const deUint32 numChunks) 167 { 168 const MemoryBind memoryBind = 169 { 170 m_allocationNdx, 171 m_resourceChunkNdx, 172 m_memoryChunkNdx, 173 numChunks 174 }; 175 m_memoryBinds.push_back(memoryBind); 176 177 m_resourceChunkNdx += numChunks; 178 m_memoryChunkNdx += numChunks; 179 m_chunksPerAllocation[m_allocationNdx] += numChunks; 180 181 return *this; 182 } 183 184 SparseAllocationBuilder& SparseAllocationBuilder::addAliasedMemoryBind (const deUint32 allocationNdx, const deUint32 chunkOffset, const deUint32 numChunks) 185 { 186 DE_ASSERT(allocationNdx <= m_allocationNdx); 187 188 const MemoryBind memoryBind = 189 { 190 allocationNdx, 191 m_resourceChunkNdx, 192 chunkOffset, 193 numChunks 194 }; 195 m_memoryBinds.push_back(memoryBind); 196 197 m_resourceChunkNdx += numChunks; 198 199 return *this; 200 } 201 202 inline VkMemoryRequirements requirementsWithSize (VkMemoryRequirements requirements, const VkDeviceSize size) 203 { 204 requirements.size = size; 205 return requirements; 206 } 207 208 MovePtr<SparseAllocation> SparseAllocationBuilder::build (const DeviceInterface& vk, 209 const VkDevice device, 210 Allocator& allocator, 211 VkBufferCreateInfo referenceCreateInfo, 212 const VkDeviceSize minChunkSize) const 213 { 214 215 MovePtr<SparseAllocation> sparseAllocation (new SparseAllocation()); 216 217 referenceCreateInfo.size = sizeof(deUint32); 218 const Unique<VkBuffer> refBuffer (createBuffer(vk, device, &referenceCreateInfo)); 219 const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vk, device, *refBuffer); 220 const VkDeviceSize chunkSize = std::max(memoryRequirements.alignment, static_cast<VkDeviceSize>(deAlign64(minChunkSize, memoryRequirements.alignment))); 221 222 for (std::vector<deUint32>::const_iterator numChunksIter = m_chunksPerAllocation.begin(); numChunksIter != m_chunksPerAllocation.end(); ++numChunksIter) 223 { 224 sparseAllocation->allocations.push_back(makeDeSharedPtr( 225 allocator.allocate(requirementsWithSize(memoryRequirements, *numChunksIter * chunkSize), MemoryRequirement::Any))); 226 } 227 228 for (std::vector<MemoryBind>::const_iterator memBindIter = m_memoryBinds.begin(); memBindIter != m_memoryBinds.end(); ++memBindIter) 229 { 230 const Allocation& alloc = **sparseAllocation->allocations[memBindIter->allocationNdx]; 231 const VkSparseMemoryBind bind = 232 { 233 memBindIter->resourceChunkNdx * chunkSize, // VkDeviceSize resourceOffset; 234 memBindIter->numChunks * chunkSize, // VkDeviceSize size; 235 alloc.getMemory(), // VkDeviceMemory memory; 236 alloc.getOffset() + memBindIter->memoryChunkNdx * chunkSize, // VkDeviceSize memoryOffset; 237 (VkSparseMemoryBindFlags)0, // VkSparseMemoryBindFlags flags; 238 }; 239 sparseAllocation->memoryBinds.push_back(bind); 240 referenceCreateInfo.size = std::max(referenceCreateInfo.size, bind.resourceOffset + bind.size); 241 } 242 243 sparseAllocation->resourceSize = referenceCreateInfo.size; 244 sparseAllocation->numResourceChunks = m_resourceChunkNdx; 245 246 return sparseAllocation; 247 } 248 249 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, const VkImageUsageFlags usage) 250 { 251 const VkImageCreateInfo imageParams = 252 { 253 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 254 DE_NULL, // const void* pNext; 255 (VkImageCreateFlags)0, // VkImageCreateFlags flags; 256 VK_IMAGE_TYPE_2D, // VkImageType imageType; 257 format, // VkFormat format; 258 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent; 259 1u, // deUint32 mipLevels; 260 1u, // deUint32 arrayLayers; 261 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 262 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 263 usage, // VkImageUsageFlags usage; 264 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 265 0u, // deUint32 queueFamilyIndexCount; 266 DE_NULL, // const deUint32* pQueueFamilyIndices; 267 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 268 }; 269 return imageParams; 270 } 271 272 Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk, 273 const VkDevice device, 274 const VkFormat colorFormat) 275 { 276 const VkAttachmentDescription colorAttachmentDescription = 277 { 278 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; 279 colorFormat, // VkFormat format; 280 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 281 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; 282 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; 283 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; 284 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; 285 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 286 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; 287 }; 288 289 const VkAttachmentReference colorAttachmentRef = 290 { 291 0u, // deUint32 attachment; 292 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; 293 }; 294 295 const VkSubpassDescription subpassDescription = 296 { 297 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; 298 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 299 0u, // deUint32 inputAttachmentCount; 300 DE_NULL, // const VkAttachmentReference* pInputAttachments; 301 1u, // deUint32 colorAttachmentCount; 302 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments; 303 DE_NULL, // const VkAttachmentReference* pResolveAttachments; 304 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; 305 0u, // deUint32 preserveAttachmentCount; 306 DE_NULL // const deUint32* pPreserveAttachments; 307 }; 308 309 const VkRenderPassCreateInfo renderPassInfo = 310 { 311 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; 312 DE_NULL, // const void* pNext; 313 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; 314 1u, // deUint32 attachmentCount; 315 &colorAttachmentDescription, // const VkAttachmentDescription* pAttachments; 316 1u, // deUint32 subpassCount; 317 &subpassDescription, // const VkSubpassDescription* pSubpasses; 318 0u, // deUint32 dependencyCount; 319 DE_NULL // const VkSubpassDependency* pDependencies; 320 }; 321 322 return createRenderPass(vk, device, &renderPassInfo); 323 } 324 325 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk, 326 const VkDevice device, 327 const VkPipelineLayout pipelineLayout, 328 const VkRenderPass renderPass, 329 const IVec2 renderSize, 330 const VkPrimitiveTopology topology, 331 const deUint32 stageCount, 332 const VkPipelineShaderStageCreateInfo* pStages) 333 { 334 const VkVertexInputBindingDescription vertexInputBindingDescription = 335 { 336 0u, // uint32_t binding; 337 sizeof(Vec4), // uint32_t stride; 338 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; 339 }; 340 341 const VkVertexInputAttributeDescription vertexInputAttributeDescription = 342 { 343 0u, // uint32_t location; 344 0u, // uint32_t binding; 345 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; 346 0u, // uint32_t offset; 347 }; 348 349 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = 350 { 351 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; 352 DE_NULL, // const void* pNext; 353 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; 354 1u, // uint32_t vertexBindingDescriptionCount; 355 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; 356 1u, // uint32_t vertexAttributeDescriptionCount; 357 &vertexInputAttributeDescription, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; 358 }; 359 360 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = 361 { 362 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; 363 DE_NULL, // const void* pNext; 364 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; 365 topology, // VkPrimitiveTopology topology; 366 VK_FALSE, // VkBool32 primitiveRestartEnable; 367 }; 368 369 const VkViewport viewport = makeViewport( 370 0.0f, 0.0f, 371 static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), 372 0.0f, 1.0f); 373 374 const VkRect2D scissor = { 375 makeOffset2D(0, 0), 376 makeExtent2D(static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y())), 377 }; 378 379 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = 380 { 381 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; 382 DE_NULL, // const void* pNext; 383 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags; 384 1u, // uint32_t viewportCount; 385 &viewport, // const VkViewport* pViewports; 386 1u, // uint32_t scissorCount; 387 &scissor, // const VkRect2D* pScissors; 388 }; 389 390 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = 391 { 392 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; 393 DE_NULL, // const void* pNext; 394 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags; 395 VK_FALSE, // VkBool32 depthClampEnable; 396 VK_FALSE, // VkBool32 rasterizerDiscardEnable; 397 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; 398 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; 399 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; 400 VK_FALSE, // VkBool32 depthBiasEnable; 401 0.0f, // float depthBiasConstantFactor; 402 0.0f, // float depthBiasClamp; 403 0.0f, // float depthBiasSlopeFactor; 404 1.0f, // float lineWidth; 405 }; 406 407 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = 408 { 409 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; 410 DE_NULL, // const void* pNext; 411 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; 412 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; 413 VK_FALSE, // VkBool32 sampleShadingEnable; 414 0.0f, // float minSampleShading; 415 DE_NULL, // const VkSampleMask* pSampleMask; 416 VK_FALSE, // VkBool32 alphaToCoverageEnable; 417 VK_FALSE // VkBool32 alphaToOneEnable; 418 }; 419 420 const VkStencilOpState stencilOpState = makeStencilOpState( 421 VK_STENCIL_OP_KEEP, // stencil fail 422 VK_STENCIL_OP_KEEP, // depth & stencil pass 423 VK_STENCIL_OP_KEEP, // depth only fail 424 VK_COMPARE_OP_ALWAYS, // compare op 425 0u, // compare mask 426 0u, // write mask 427 0u); // reference 428 429 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = 430 { 431 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; 432 DE_NULL, // const void* pNext; 433 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags; 434 VK_FALSE, // VkBool32 depthTestEnable; 435 VK_FALSE, // VkBool32 depthWriteEnable; 436 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp; 437 VK_FALSE, // VkBool32 depthBoundsTestEnable; 438 VK_FALSE, // VkBool32 stencilTestEnable; 439 stencilOpState, // VkStencilOpState front; 440 stencilOpState, // VkStencilOpState back; 441 0.0f, // float minDepthBounds; 442 1.0f, // float maxDepthBounds; 443 }; 444 445 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 446 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = 447 { 448 VK_FALSE, // VkBool32 blendEnable; 449 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; 450 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; 451 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; 452 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; 453 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; 454 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; 455 colorComponentsAll, // VkColorComponentFlags colorWriteMask; 456 }; 457 458 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = 459 { 460 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; 461 DE_NULL, // const void* pNext; 462 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; 463 VK_FALSE, // VkBool32 logicOpEnable; 464 VK_LOGIC_OP_COPY, // VkLogicOp logicOp; 465 1u, // deUint32 attachmentCount; 466 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; 467 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; 468 }; 469 470 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo = 471 { 472 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; 473 DE_NULL, // const void* pNext; 474 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; 475 stageCount, // deUint32 stageCount; 476 pStages, // const VkPipelineShaderStageCreateInfo* pStages; 477 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; 478 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; 479 DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; 480 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; 481 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; 482 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; 483 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; 484 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; 485 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; 486 pipelineLayout, // VkPipelineLayout layout; 487 renderPass, // VkRenderPass renderPass; 488 0u, // deUint32 subpass; 489 DE_NULL, // VkPipeline basePipelineHandle; 490 0, // deInt32 basePipelineIndex; 491 }; 492 493 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo); 494 } 495 496 //! Return true if there are any red (or all zero) pixels in the image 497 bool imageHasErrorPixels (const tcu::ConstPixelBufferAccess image) 498 { 499 const Vec4 errorColor = Vec4(1.0f, 0.0f, 0.0f, 1.0f); 500 const Vec4 blankColor = Vec4(); 501 502 for (int y = 0; y < image.getHeight(); ++y) 503 for (int x = 0; x < image.getWidth(); ++x) 504 { 505 const Vec4 color = image.getPixel(x, y); 506 if (color == errorColor || color == blankColor) 507 return true; 508 } 509 510 return false; 511 } 512 513 class Renderer 514 { 515 public: 516 typedef std::map<VkShaderStageFlagBits, const VkSpecializationInfo*> SpecializationMap; 517 518 //! Use the delegate to bind descriptor sets, vertex buffers, etc. and make a draw call 519 struct Delegate 520 { 521 virtual ~Delegate (void) {} 522 virtual void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const = 0; 523 }; 524 525 Renderer (const DeviceInterface& vk, 526 const VkDevice device, 527 Allocator& allocator, 528 const deUint32 queueFamilyIndex, 529 const VkDescriptorSetLayout descriptorSetLayout, //!< may be NULL, if no descriptors are used 530 BinaryCollection& binaryCollection, 531 const std::string& vertexName, 532 const std::string& fragmentName, 533 const VkBuffer colorBuffer, 534 const IVec2& renderSize, 535 const VkFormat colorFormat, 536 const Vec4& clearColor, 537 const VkPrimitiveTopology topology, 538 SpecializationMap specMap = SpecializationMap()) 539 : m_colorBuffer (colorBuffer) 540 , m_renderSize (renderSize) 541 , m_colorFormat (colorFormat) 542 , m_colorSubresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)) 543 , m_clearColor (clearColor) 544 , m_topology (topology) 545 , m_descriptorSetLayout (descriptorSetLayout) 546 { 547 m_colorImage = makeImage (vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)); 548 m_colorImageAlloc = bindImage (vk, device, allocator, *m_colorImage, MemoryRequirement::Any); 549 m_colorAttachment = makeImageView (vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange); 550 551 m_vertexModule = createShaderModule (vk, device, binaryCollection.get(vertexName), 0u); 552 m_fragmentModule = createShaderModule (vk, device, binaryCollection.get(fragmentName), 0u); 553 554 const VkPipelineShaderStageCreateInfo pShaderStages[] = 555 { 556 { 557 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; 558 DE_NULL, // const void* pNext; 559 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; 560 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; 561 *m_vertexModule, // VkShaderModule module; 562 "main", // const char* pName; 563 specMap[VK_SHADER_STAGE_VERTEX_BIT], // const VkSpecializationInfo* pSpecializationInfo; 564 }, 565 { 566 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; 567 DE_NULL, // const void* pNext; 568 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; 569 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; 570 *m_fragmentModule, // VkShaderModule module; 571 "main", // const char* pName; 572 specMap[VK_SHADER_STAGE_FRAGMENT_BIT], // const VkSpecializationInfo* pSpecializationInfo; 573 } 574 }; 575 576 m_renderPass = makeRenderPass (vk, device, m_colorFormat); 577 m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, 1u, &m_colorAttachment.get(), 578 static_cast<deUint32>(m_renderSize.x()), static_cast<deUint32>(m_renderSize.y())); 579 m_pipelineLayout = makePipelineLayout (vk, device, m_descriptorSetLayout); 580 m_pipeline = makeGraphicsPipeline (vk, device, *m_pipelineLayout, *m_renderPass, m_renderSize, m_topology, DE_LENGTH_OF_ARRAY(pShaderStages), pShaderStages); 581 m_cmdPool = makeCommandPool (vk, device, queueFamilyIndex); 582 m_cmdBuffer = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); 583 } 584 585 void draw (const DeviceInterface& vk, 586 const VkDevice device, 587 const VkQueue queue, 588 const Delegate& drawDelegate, 589 const bool useDeviceGroups, 590 const deUint32 deviceID) const 591 { 592 beginCommandBuffer(vk, *m_cmdBuffer); 593 594 const VkClearValue clearValue = makeClearValueColor(m_clearColor); 595 const VkRect2D renderArea = 596 { 597 makeOffset2D(0, 0), 598 makeExtent2D(m_renderSize.x(), m_renderSize.y()), 599 }; 600 const VkRenderPassBeginInfo renderPassBeginInfo = 601 { 602 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; 603 DE_NULL, // const void* pNext; 604 *m_renderPass, // VkRenderPass renderPass; 605 *m_framebuffer, // VkFramebuffer framebuffer; 606 renderArea, // VkRect2D renderArea; 607 1u, // uint32_t clearValueCount; 608 &clearValue, // const VkClearValue* pClearValues; 609 }; 610 vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 611 612 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 613 drawDelegate.rendererDraw(*m_pipelineLayout, *m_cmdBuffer); 614 615 vk.cmdEndRenderPass(*m_cmdBuffer); 616 617 // Prepare color image for copy 618 { 619 const VkImageMemoryBarrier barriers[] = 620 { 621 { 622 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; 623 DE_NULL, // const void* pNext; 624 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags outputMask; 625 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags inputMask; 626 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout; 627 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout; 628 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; 629 VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex; 630 *m_colorImage, // VkImage image; 631 m_colorSubresourceRange, // VkImageSubresourceRange subresourceRange; 632 }, 633 }; 634 635 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 636 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers); 637 } 638 // Color image -> host buffer 639 { 640 const VkBufferImageCopy region = 641 { 642 0ull, // VkDeviceSize bufferOffset; 643 0u, // uint32_t bufferRowLength; 644 0u, // uint32_t bufferImageHeight; 645 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource; 646 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset; 647 makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u), // VkExtent3D imageExtent; 648 }; 649 650 vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_colorBuffer, 1u, ®ion); 651 } 652 // Buffer write barrier 653 { 654 const VkBufferMemoryBarrier barriers[] = 655 { 656 { 657 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; 658 DE_NULL, // const void* pNext; 659 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; 660 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; 661 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; 662 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; 663 m_colorBuffer, // VkBuffer buffer; 664 0ull, // VkDeviceSize offset; 665 VK_WHOLE_SIZE, // VkDeviceSize size; 666 }, 667 }; 668 669 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 670 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u); 671 } 672 673 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); 674 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer, 0U, DE_NULL, DE_NULL, 0U, DE_NULL, useDeviceGroups, deviceID); 675 } 676 677 private: 678 const VkBuffer m_colorBuffer; 679 const IVec2 m_renderSize; 680 const VkFormat m_colorFormat; 681 const VkImageSubresourceRange m_colorSubresourceRange; 682 const Vec4 m_clearColor; 683 const VkPrimitiveTopology m_topology; 684 const VkDescriptorSetLayout m_descriptorSetLayout; 685 686 Move<VkImage> m_colorImage; 687 MovePtr<Allocation> m_colorImageAlloc; 688 Move<VkImageView> m_colorAttachment; 689 Move<VkShaderModule> m_vertexModule; 690 Move<VkShaderModule> m_fragmentModule; 691 Move<VkRenderPass> m_renderPass; 692 Move<VkFramebuffer> m_framebuffer; 693 Move<VkPipelineLayout> m_pipelineLayout; 694 Move<VkPipeline> m_pipeline; 695 Move<VkCommandPool> m_cmdPool; 696 Move<VkCommandBuffer> m_cmdBuffer; 697 698 // "deleted" 699 Renderer (const Renderer&); 700 Renderer& operator= (const Renderer&); 701 }; 702 703 void bindSparseBuffer (const DeviceInterface& vk, const VkDevice device, const VkQueue sparseQueue, const VkBuffer buffer, const SparseAllocation& sparseAllocation, 704 const bool useDeviceGroups, deUint32 resourceDevId, deUint32 memoryDeviceId) 705 { 706 const VkSparseBufferMemoryBindInfo sparseBufferMemoryBindInfo = 707 { 708 buffer, // VkBuffer buffer; 709 static_cast<deUint32>(sparseAllocation.memoryBinds.size()), // uint32_t bindCount; 710 &sparseAllocation.memoryBinds[0], // const VkSparseMemoryBind* pBinds; 711 }; 712 713 const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo = 714 { 715 VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR, //VkStructureType sType; 716 DE_NULL, //const void* pNext; 717 resourceDevId, //deUint32 resourceDeviceIndex; 718 memoryDeviceId, //deUint32 memoryDeviceIndex; 719 }; 720 721 const VkBindSparseInfo bindInfo = 722 { 723 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType; 724 useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL, // const void* pNext; 725 0u, // uint32_t waitSemaphoreCount; 726 DE_NULL, // const VkSemaphore* pWaitSemaphores; 727 1u, // uint32_t bufferBindCount; 728 &sparseBufferMemoryBindInfo, // const VkSparseBufferMemoryBindInfo* pBufferBinds; 729 0u, // uint32_t imageOpaqueBindCount; 730 DE_NULL, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; 731 0u, // uint32_t imageBindCount; 732 DE_NULL, // const VkSparseImageMemoryBindInfo* pImageBinds; 733 0u, // uint32_t signalSemaphoreCount; 734 DE_NULL, // const VkSemaphore* pSignalSemaphores; 735 }; 736 737 const Unique<VkFence> fence(createFence(vk, device)); 738 739 VK_CHECK(vk.queueBindSparse(sparseQueue, 1u, &bindInfo, *fence)); 740 VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), VK_TRUE, ~0ull)); 741 } 742 743 class SparseBufferTestInstance : public SparseResourcesBaseInstance, Renderer::Delegate 744 { 745 public: 746 SparseBufferTestInstance (Context& context, const TestFlags flags) 747 : SparseResourcesBaseInstance (context, (flags & TEST_FLAG_ENABLE_DEVICE_GROUPS) != 0) 748 , m_aliased ((flags & TEST_FLAG_ALIASED) != 0) 749 , m_residency ((flags & TEST_FLAG_RESIDENCY) != 0) 750 , m_nonResidentStrict ((flags & TEST_FLAG_NON_RESIDENT_STRICT) != 0) 751 , m_renderSize (RENDER_SIZE, RENDER_SIZE) 752 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM) 753 , m_colorBufferSize (m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat))) 754 { 755 { 756 QueueRequirementsVec requirements; 757 requirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u)); 758 requirements.push_back(QueueRequirements(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 1u)); 759 760 createDeviceSupportingQueues(requirements); 761 } 762 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(m_context.getInstanceInterface(), getPhysicalDevice()); 763 764 if (!features.sparseBinding) 765 TCU_THROW(NotSupportedError, "Missing feature: sparseBinding"); 766 767 if (m_residency && !features.sparseResidencyBuffer) 768 TCU_THROW(NotSupportedError, "Missing feature: sparseResidencyBuffer"); 769 770 if (m_aliased && !features.sparseResidencyAliased) 771 TCU_THROW(NotSupportedError, "Missing feature: sparseResidencyAliased"); 772 773 if (m_nonResidentStrict && !m_context.getDeviceProperties().sparseProperties.residencyNonResidentStrict) 774 TCU_THROW(NotSupportedError, "Missing sparse property: residencyNonResidentStrict"); 775 776 const DeviceInterface& vk = getDeviceInterface(); 777 m_sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0u); 778 m_universalQueue = getQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0u); 779 780 m_sharedQueueFamilyIndices[0] = m_sparseQueue.queueFamilyIndex; 781 m_sharedQueueFamilyIndices[1] = m_universalQueue.queueFamilyIndex; 782 783 m_colorBuffer = makeBuffer(vk, getDevice(), makeBufferCreateInfo(m_colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)); 784 m_colorBufferAlloc = bindBuffer(vk, getDevice(), getAllocator(), *m_colorBuffer, MemoryRequirement::HostVisible); 785 786 deMemset(m_colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(m_colorBufferSize)); 787 flushMappedMemoryRange(vk, getDevice(), m_colorBufferAlloc->getMemory(), m_colorBufferAlloc->getOffset(), m_colorBufferSize); 788 } 789 790 protected: 791 VkBufferCreateInfo getSparseBufferCreateInfo (const VkBufferUsageFlags usage) const 792 { 793 VkBufferCreateFlags flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; 794 if (m_residency) 795 flags |= VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT; 796 if (m_aliased) 797 flags |= VK_BUFFER_CREATE_SPARSE_ALIASED_BIT; 798 799 VkBufferCreateInfo referenceBufferCreateInfo = 800 { 801 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; 802 DE_NULL, // const void* pNext; 803 flags, // VkBufferCreateFlags flags; 804 0u, // override later // VkDeviceSize size; 805 VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage, // VkBufferUsageFlags usage; 806 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 807 0u, // uint32_t queueFamilyIndexCount; 808 DE_NULL, // const uint32_t* pQueueFamilyIndices; 809 }; 810 811 if (m_sparseQueue.queueFamilyIndex != m_universalQueue.queueFamilyIndex) 812 { 813 referenceBufferCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; 814 referenceBufferCreateInfo.queueFamilyIndexCount = DE_LENGTH_OF_ARRAY(m_sharedQueueFamilyIndices); 815 referenceBufferCreateInfo.pQueueFamilyIndices = m_sharedQueueFamilyIndices; 816 } 817 818 return referenceBufferCreateInfo; 819 } 820 821 void draw (const VkPrimitiveTopology topology, 822 const VkDescriptorSetLayout descriptorSetLayout = DE_NULL, 823 Renderer::SpecializationMap specMap = Renderer::SpecializationMap(), 824 bool useDeviceGroups = false, 825 deUint32 deviceID = 0) 826 { 827 const UniquePtr<Renderer> renderer(new Renderer( 828 getDeviceInterface(), getDevice(), getAllocator(), m_universalQueue.queueFamilyIndex, descriptorSetLayout, 829 m_context.getBinaryCollection(), "vert", "frag", *m_colorBuffer, m_renderSize, m_colorFormat, Vec4(1.0f, 0.0f, 0.0f, 1.0f), topology, specMap)); 830 831 renderer->draw(getDeviceInterface(), getDevice(), m_universalQueue.queueHandle, *this, useDeviceGroups, deviceID); 832 } 833 834 bool isResultImageCorrect (void) const 835 { 836 invalidateMappedMemoryRange(getDeviceInterface(), getDevice(), m_colorBufferAlloc->getMemory(), 0ull, m_colorBufferSize); 837 838 const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(m_colorFormat), m_renderSize.x(), m_renderSize.y(), 1u, m_colorBufferAlloc->getHostPtr()); 839 840 m_context.getTestContext().getLog() 841 << tcu::LogImageSet("Result", "Result") << tcu::LogImage("color0", "", resultImage) << tcu::TestLog::EndImageSet; 842 843 return !imageHasErrorPixels(resultImage); 844 } 845 846 const bool m_aliased; 847 const bool m_residency; 848 const bool m_nonResidentStrict; 849 850 Queue m_sparseQueue; 851 Queue m_universalQueue; 852 853 private: 854 const IVec2 m_renderSize; 855 const VkFormat m_colorFormat; 856 const VkDeviceSize m_colorBufferSize; 857 858 Move<VkBuffer> m_colorBuffer; 859 MovePtr<Allocation> m_colorBufferAlloc; 860 861 deUint32 m_sharedQueueFamilyIndices[2]; 862 }; 863 864 void initProgramsDrawWithUBO (vk::SourceCollections& programCollection, const TestFlags flags) 865 { 866 // Vertex shader 867 { 868 std::ostringstream src; 869 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 870 << "\n" 871 << "layout(location = 0) in vec4 in_position;\n" 872 << "\n" 873 << "out gl_PerVertex {\n" 874 << " vec4 gl_Position;\n" 875 << "};\n" 876 << "\n" 877 << "void main(void)\n" 878 << "{\n" 879 << " gl_Position = in_position;\n" 880 << "}\n"; 881 882 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 883 } 884 885 // Fragment shader 886 { 887 const bool aliased = (flags & TEST_FLAG_ALIASED) != 0; 888 const bool residency = (flags & TEST_FLAG_RESIDENCY) != 0; 889 const bool nonResidentStrict = (flags & TEST_FLAG_NON_RESIDENT_STRICT) != 0; 890 const std::string valueExpr = (aliased ? "ivec4(3*(ndx % nonAliasedSize) ^ 127, 0, 0, 0)" : "ivec4(3*ndx ^ 127, 0, 0, 0)"); 891 892 std::ostringstream src; 893 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 894 << "\n" 895 << "layout(location = 0) out vec4 o_color;\n" 896 << "\n" 897 << "layout(constant_id = 1) const int dataSize = 1;\n" 898 << "layout(constant_id = 2) const int chunkSize = 1;\n" 899 << "\n" 900 << "layout(set = 0, binding = 0, std140) uniform SparseBuffer {\n" 901 << " ivec4 data[dataSize];\n" 902 << "} ubo;\n" 903 << "\n" 904 << "void main(void)\n" 905 << "{\n" 906 << " const int fragNdx = int(gl_FragCoord.x) + " << RENDER_SIZE << " * int(gl_FragCoord.y);\n" 907 << " const int pageSize = " << RENDER_SIZE << " * " << RENDER_SIZE << ";\n" 908 << " const int numChunks = dataSize / chunkSize;\n"; 909 910 if (aliased) 911 src << " const int nonAliasedSize = (numChunks > 1 ? dataSize - chunkSize : dataSize);\n"; 912 913 src << " bool ok = true;\n" 914 << "\n" 915 << " for (int ndx = fragNdx; ndx < dataSize; ndx += pageSize)\n" 916 << " {\n"; 917 918 if (residency && nonResidentStrict) 919 { 920 src << " if (ndx >= chunkSize && ndx < 2*chunkSize)\n" 921 << " ok = ok && (ubo.data[ndx] == ivec4(0));\n" 922 << " else\n" 923 << " ok = ok && (ubo.data[ndx] == " + valueExpr + ");\n"; 924 } 925 else if (residency) 926 { 927 src << " if (ndx >= chunkSize && ndx < 2*chunkSize)\n" 928 << " continue;\n" 929 << " ok = ok && (ubo.data[ndx] == " << valueExpr << ");\n"; 930 } 931 else 932 src << " ok = ok && (ubo.data[ndx] == " << valueExpr << ");\n"; 933 934 src << " }\n" 935 << "\n" 936 << " if (ok)\n" 937 << " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n" 938 << " else\n" 939 << " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n" 940 << "}\n"; 941 942 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 943 } 944 } 945 946 //! Sparse buffer backing a UBO 947 class UBOTestInstance : public SparseBufferTestInstance 948 { 949 public: 950 UBOTestInstance (Context& context, const TestFlags flags) 951 : SparseBufferTestInstance (context, flags) 952 { 953 } 954 955 void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const 956 { 957 const DeviceInterface& vk = getDeviceInterface(); 958 const VkDeviceSize vertexOffset = 0ull; 959 960 vk.cmdBindVertexBuffers (cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexOffset); 961 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL); 962 vk.cmdDraw (cmdBuffer, 4u, 1u, 0u, 0u); 963 } 964 965 tcu::TestStatus iterate (void) 966 { 967 const DeviceInterface& vk = getDeviceInterface(); 968 MovePtr<SparseAllocation> sparseAllocation; 969 Move<VkBuffer> sparseBuffer; 970 Move<VkBuffer> sparseBufferAliased; 971 bool setupDescriptors = true; 972 973 // Go through all physical devices 974 for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++) 975 { 976 const deUint32 firstDeviceID = physDevID; 977 const deUint32 secondDeviceID = (firstDeviceID + 1) % m_numPhysicalDevices; 978 979 // Set up the sparse buffer 980 { 981 VkBufferCreateInfo referenceBufferCreateInfo = getSparseBufferCreateInfo(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); 982 const VkDeviceSize minChunkSize = 512u; // make sure the smallest allocation is at least this big 983 deUint32 numMaxChunks = 0u; 984 985 // Check how many chunks we can allocate given the alignment and size requirements of UBOs 986 { 987 const UniquePtr<SparseAllocation> minAllocation(SparseAllocationBuilder() 988 .addMemoryBind() 989 .build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize)); 990 991 numMaxChunks = deMaxu32(static_cast<deUint32>(m_context.getDeviceProperties().limits.maxUniformBufferRange / minAllocation->resourceSize), 1u); 992 } 993 994 if (numMaxChunks < 4) 995 { 996 sparseAllocation = SparseAllocationBuilder() 997 .addMemoryBind() 998 .build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize); 999 } 1000 else 1001 { 1002 // Try to use a non-trivial memory allocation scheme to make it different from a non-sparse binding 1003 SparseAllocationBuilder builder; 1004 builder.addMemoryBind(); 1005 1006 if (m_residency) 1007 builder.addResourceHole(); 1008 1009 builder 1010 .addMemoryAllocation() 1011 .addMemoryHole() 1012 .addMemoryBind(); 1013 1014 if (m_aliased) 1015 builder.addAliasedMemoryBind(0u, 0u); 1016 1017 sparseAllocation = builder.build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize); 1018 DE_ASSERT(sparseAllocation->resourceSize <= m_context.getDeviceProperties().limits.maxUniformBufferRange); 1019 } 1020 1021 // Create the buffer 1022 referenceBufferCreateInfo.size = sparseAllocation->resourceSize; 1023 sparseBuffer = makeBuffer(vk, getDevice(), referenceBufferCreateInfo); 1024 bindSparseBuffer(vk, getDevice(), m_sparseQueue.queueHandle, *sparseBuffer, *sparseAllocation, usingDeviceGroups(), firstDeviceID, secondDeviceID); 1025 1026 if (m_aliased) 1027 { 1028 sparseBufferAliased = makeBuffer(vk, getDevice(), referenceBufferCreateInfo); 1029 bindSparseBuffer(vk, getDevice(), m_sparseQueue.queueHandle, *sparseBufferAliased, *sparseAllocation, usingDeviceGroups(), firstDeviceID, secondDeviceID); 1030 } 1031 } 1032 1033 // Set uniform data 1034 { 1035 const bool hasAliasedChunk = (m_aliased && sparseAllocation->memoryBinds.size() > 1u); 1036 const VkDeviceSize chunkSize = sparseAllocation->resourceSize / sparseAllocation->numResourceChunks; 1037 const VkDeviceSize stagingBufferSize = sparseAllocation->resourceSize - (hasAliasedChunk ? chunkSize : 0); 1038 const deUint32 numBufferEntries = static_cast<deUint32>(stagingBufferSize / sizeof(IVec4)); 1039 1040 const Unique<VkBuffer> stagingBuffer (makeBuffer(vk, getDevice(), makeBufferCreateInfo(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT))); 1041 const UniquePtr<Allocation> stagingBufferAlloc (bindBuffer(vk, getDevice(), getAllocator(), *stagingBuffer, MemoryRequirement::HostVisible)); 1042 1043 { 1044 // If aliased chunk is used, the staging buffer is smaller than the sparse buffer and we don't overwrite the last chunk 1045 IVec4* const pData = static_cast<IVec4*>(stagingBufferAlloc->getHostPtr()); 1046 for (deUint32 i = 0; i < numBufferEntries; ++i) 1047 pData[i] = IVec4(3*i ^ 127, 0, 0, 0); 1048 1049 flushMappedMemoryRange(vk, getDevice(), stagingBufferAlloc->getMemory(), stagingBufferAlloc->getOffset(), stagingBufferSize); 1050 1051 const VkBufferCopy copyRegion = 1052 { 1053 0ull, // VkDeviceSize srcOffset; 1054 0ull, // VkDeviceSize dstOffset; 1055 stagingBufferSize, // VkDeviceSize size; 1056 }; 1057 1058 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, getDevice(), m_universalQueue.queueFamilyIndex)); 1059 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, getDevice(), *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 1060 1061 beginCommandBuffer (vk, *cmdBuffer); 1062 vk.cmdCopyBuffer (*cmdBuffer, *stagingBuffer, *sparseBuffer, 1u, ©Region); 1063 endCommandBuffer (vk, *cmdBuffer); 1064 1065 submitCommandsAndWait(vk, getDevice(), m_universalQueue.queueHandle, *cmdBuffer, 0u, DE_NULL, DE_NULL, 0, DE_NULL, usingDeviceGroups(), firstDeviceID); 1066 // Once the fence is signaled, the write is also available to the aliasing buffer. 1067 } 1068 } 1069 1070 // Make sure that we don't try to access a larger range than is allowed. This only applies to a single chunk case. 1071 const deUint32 maxBufferRange = deMinu32(static_cast<deUint32>(sparseAllocation->resourceSize), m_context.getDeviceProperties().limits.maxUniformBufferRange); 1072 1073 // Descriptor sets 1074 { 1075 // Setup only once 1076 if (setupDescriptors) 1077 { 1078 m_descriptorSetLayout = DescriptorSetLayoutBuilder() 1079 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT) 1080 .build(vk, getDevice()); 1081 1082 m_descriptorPool = DescriptorPoolBuilder() 1083 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) 1084 .build(vk, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 1085 1086 m_descriptorSet = makeDescriptorSet(vk, getDevice(), *m_descriptorPool, *m_descriptorSetLayout); 1087 setupDescriptors = false; 1088 } 1089 1090 const VkBuffer buffer = (m_aliased ? *sparseBufferAliased : *sparseBuffer); 1091 const VkDescriptorBufferInfo sparseBufferInfo = makeDescriptorBufferInfo(buffer, 0ull, maxBufferRange); 1092 1093 DescriptorSetUpdateBuilder() 1094 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &sparseBufferInfo) 1095 .update(vk, getDevice()); 1096 } 1097 1098 // Vertex data 1099 { 1100 const Vec4 vertexData[] = 1101 { 1102 Vec4(-1.0f, -1.0f, 0.0f, 1.0f), 1103 Vec4(-1.0f, 1.0f, 0.0f, 1.0f), 1104 Vec4( 1.0f, -1.0f, 0.0f, 1.0f), 1105 Vec4( 1.0f, 1.0f, 0.0f, 1.0f), 1106 }; 1107 1108 const VkDeviceSize vertexBufferSize = sizeof(vertexData); 1109 1110 m_vertexBuffer = makeBuffer(vk, getDevice(), makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); 1111 m_vertexBufferAlloc = bindBuffer(vk, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible); 1112 1113 deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertexData[0], vertexBufferSize); 1114 flushMappedMemoryRange(vk, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferSize); 1115 } 1116 1117 // Draw 1118 { 1119 std::vector<deInt32> specializationData; 1120 { 1121 const deUint32 numBufferEntries = maxBufferRange / static_cast<deUint32>(sizeof(IVec4)); 1122 const deUint32 numEntriesPerChunk = numBufferEntries / sparseAllocation->numResourceChunks; 1123 1124 specializationData.push_back(numBufferEntries); 1125 specializationData.push_back(numEntriesPerChunk); 1126 } 1127 1128 const VkSpecializationMapEntry specMapEntries[] = 1129 { 1130 { 1131 1u, // uint32_t constantID; 1132 0u, // uint32_t offset; 1133 sizeof(deInt32), // size_t size; 1134 }, 1135 { 1136 2u, // uint32_t constantID; 1137 sizeof(deInt32), // uint32_t offset; 1138 sizeof(deInt32), // size_t size; 1139 }, 1140 }; 1141 1142 const VkSpecializationInfo specInfo = 1143 { 1144 DE_LENGTH_OF_ARRAY(specMapEntries), // uint32_t mapEntryCount; 1145 specMapEntries, // const VkSpecializationMapEntry* pMapEntries; 1146 sizeInBytes(specializationData), // size_t dataSize; 1147 getDataOrNullptr(specializationData), // const void* pData; 1148 }; 1149 1150 Renderer::SpecializationMap specMap; 1151 specMap[VK_SHADER_STAGE_FRAGMENT_BIT] = &specInfo; 1152 1153 draw(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, *m_descriptorSetLayout, specMap, usingDeviceGroups(), firstDeviceID); 1154 } 1155 1156 if(!isResultImageCorrect()) 1157 return tcu::TestStatus::fail("Some buffer values were incorrect"); 1158 } 1159 return tcu::TestStatus::pass("Pass"); 1160 } 1161 1162 private: 1163 Move<VkBuffer> m_vertexBuffer; 1164 MovePtr<Allocation> m_vertexBufferAlloc; 1165 1166 Move<VkDescriptorSetLayout> m_descriptorSetLayout; 1167 Move<VkDescriptorPool> m_descriptorPool; 1168 Move<VkDescriptorSet> m_descriptorSet; 1169 }; 1170 1171 void initProgramsDrawGrid (vk::SourceCollections& programCollection, const TestFlags flags) 1172 { 1173 DE_UNREF(flags); 1174 1175 // Vertex shader 1176 { 1177 std::ostringstream src; 1178 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1179 << "\n" 1180 << "layout(location = 0) in vec4 in_position;\n" 1181 << "layout(location = 0) out int out_ndx;\n" 1182 << "\n" 1183 << "out gl_PerVertex {\n" 1184 << " vec4 gl_Position;\n" 1185 << "};\n" 1186 << "\n" 1187 << "void main(void)\n" 1188 << "{\n" 1189 << " gl_Position = in_position;\n" 1190 << " out_ndx = gl_VertexIndex;\n" 1191 << "}\n"; 1192 1193 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 1194 } 1195 1196 // Fragment shader 1197 { 1198 std::ostringstream src; 1199 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1200 << "\n" 1201 << "layout(location = 0) flat in int in_ndx;\n" 1202 << "layout(location = 0) out vec4 o_color;\n" 1203 << "\n" 1204 << "void main(void)\n" 1205 << "{\n" 1206 << " if (in_ndx % 2 == 0)\n" 1207 << " o_color = vec4(vec3(1.0), 1.0);\n" 1208 << " else\n" 1209 << " o_color = vec4(vec3(0.75), 1.0);\n" 1210 << "}\n"; 1211 1212 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 1213 } 1214 } 1215 1216 //! Generate vertex positions for a grid of tiles composed of two triangles each (6 vertices) 1217 void generateGrid (void* pRawData, const float step, const float ox, const float oy, const deUint32 numX, const deUint32 numY, const float z = 0.0f) 1218 { 1219 typedef Vec4 (*TilePtr)[6]; 1220 1221 TilePtr const pData = static_cast<TilePtr>(pRawData); 1222 { 1223 for (deUint32 iy = 0; iy < numY; ++iy) 1224 for (deUint32 ix = 0; ix < numX; ++ix) 1225 { 1226 const deUint32 ndx = ix + numX * iy; 1227 const float x = ox + step * static_cast<float>(ix); 1228 const float y = oy + step * static_cast<float>(iy); 1229 1230 pData[ndx][0] = Vec4(x + step, y, z, 1.0f); 1231 pData[ndx][1] = Vec4(x, y, z, 1.0f); 1232 pData[ndx][2] = Vec4(x, y + step, z, 1.0f); 1233 1234 pData[ndx][3] = Vec4(x, y + step, z, 1.0f); 1235 pData[ndx][4] = Vec4(x + step, y + step, z, 1.0f); 1236 pData[ndx][5] = Vec4(x + step, y, z, 1.0f); 1237 } 1238 } 1239 } 1240 1241 //! Base test for a sparse buffer backing a vertex/index buffer 1242 class DrawGridTestInstance : public SparseBufferTestInstance 1243 { 1244 public: 1245 DrawGridTestInstance (Context& context, const TestFlags flags, const VkBufferUsageFlags usage, const VkDeviceSize minChunkSize) 1246 : SparseBufferTestInstance (context, flags) 1247 { 1248 const DeviceInterface& vk = getDeviceInterface(); 1249 VkBufferCreateInfo referenceBufferCreateInfo = getSparseBufferCreateInfo(usage); 1250 1251 { 1252 // Allocate two chunks, each covering half of the viewport 1253 SparseAllocationBuilder builder; 1254 builder.addMemoryBind(); 1255 1256 if (m_residency) 1257 builder.addResourceHole(); 1258 1259 builder 1260 .addMemoryAllocation() 1261 .addMemoryHole() 1262 .addMemoryBind(); 1263 1264 if (m_aliased) 1265 builder.addAliasedMemoryBind(0u, 0u); 1266 1267 m_sparseAllocation = builder.build(vk, getDevice(), getAllocator(), referenceBufferCreateInfo, minChunkSize); 1268 } 1269 1270 // Create the buffer 1271 referenceBufferCreateInfo.size = m_sparseAllocation->resourceSize; 1272 m_sparseBuffer = makeBuffer(vk, getDevice(), referenceBufferCreateInfo); 1273 1274 1275 m_perDrawBufferOffset = m_sparseAllocation->resourceSize / m_sparseAllocation->numResourceChunks; 1276 m_stagingBufferSize = 2 * m_perDrawBufferOffset; 1277 m_stagingBuffer = makeBuffer(vk, getDevice(), makeBufferCreateInfo(m_stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)); 1278 m_stagingBufferAlloc = bindBuffer(vk, getDevice(), getAllocator(), *m_stagingBuffer, MemoryRequirement::HostVisible); 1279 1280 1281 } 1282 1283 tcu::TestStatus iterate (void) 1284 { 1285 const DeviceInterface& vk = getDeviceInterface(); 1286 1287 for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++) 1288 { 1289 const deUint32 firstDeviceID = physDevID; 1290 const deUint32 secondDeviceID = (firstDeviceID + 1) % m_numPhysicalDevices; 1291 1292 // Bind the memory 1293 bindSparseBuffer(vk, getDevice(), m_sparseQueue.queueHandle, *m_sparseBuffer, *m_sparseAllocation, usingDeviceGroups(), firstDeviceID, secondDeviceID); 1294 1295 initializeBuffers(); 1296 1297 // Upload to the sparse buffer 1298 { 1299 flushMappedMemoryRange(vk, getDevice(), m_stagingBufferAlloc->getMemory(), m_stagingBufferAlloc->getOffset(), m_stagingBufferSize); 1300 1301 VkDeviceSize firstChunkOffset = 0ull; 1302 VkDeviceSize secondChunkOffset = m_perDrawBufferOffset; 1303 1304 if (m_residency) 1305 secondChunkOffset += m_perDrawBufferOffset; 1306 1307 if (m_aliased) 1308 firstChunkOffset = secondChunkOffset + m_perDrawBufferOffset; 1309 1310 const VkBufferCopy copyRegions[] = 1311 { 1312 { 1313 0ull, // VkDeviceSize srcOffset; 1314 firstChunkOffset, // VkDeviceSize dstOffset; 1315 m_perDrawBufferOffset, // VkDeviceSize size; 1316 }, 1317 { 1318 m_perDrawBufferOffset, // VkDeviceSize srcOffset; 1319 secondChunkOffset, // VkDeviceSize dstOffset; 1320 m_perDrawBufferOffset, // VkDeviceSize size; 1321 }, 1322 }; 1323 1324 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, getDevice(), m_universalQueue.queueFamilyIndex)); 1325 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, getDevice(), *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 1326 1327 beginCommandBuffer (vk, *cmdBuffer); 1328 vk.cmdCopyBuffer (*cmdBuffer, *m_stagingBuffer, *m_sparseBuffer, DE_LENGTH_OF_ARRAY(copyRegions), copyRegions); 1329 endCommandBuffer (vk, *cmdBuffer); 1330 1331 submitCommandsAndWait(vk, getDevice(), m_universalQueue.queueHandle, *cmdBuffer, 0u, DE_NULL, DE_NULL, 0, DE_NULL, usingDeviceGroups(), firstDeviceID); 1332 } 1333 1334 1335 Renderer::SpecializationMap specMap; 1336 draw(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, DE_NULL, specMap, usingDeviceGroups(), firstDeviceID); 1337 1338 if(!isResultImageCorrect()) 1339 return tcu::TestStatus::fail("Some buffer values were incorrect"); 1340 } 1341 return tcu::TestStatus::pass("Pass"); 1342 } 1343 1344 protected: 1345 virtual void initializeBuffers (void) = 0; 1346 1347 VkDeviceSize m_perDrawBufferOffset; 1348 1349 VkDeviceSize m_stagingBufferSize; 1350 Move<VkBuffer> m_stagingBuffer; 1351 MovePtr<Allocation> m_stagingBufferAlloc; 1352 1353 MovePtr<SparseAllocation> m_sparseAllocation; 1354 Move<VkBuffer> m_sparseBuffer; 1355 }; 1356 1357 //! Sparse buffer backing a vertex input buffer 1358 class VertexBufferTestInstance : public DrawGridTestInstance 1359 { 1360 public: 1361 VertexBufferTestInstance (Context& context, const TestFlags flags) 1362 : DrawGridTestInstance (context, 1363 flags, 1364 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1365 GRID_SIZE * GRID_SIZE * 6 * sizeof(Vec4)) 1366 { 1367 } 1368 1369 void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const 1370 { 1371 DE_UNREF(pipelineLayout); 1372 1373 m_context.getTestContext().getLog() 1374 << tcu::TestLog::Message << "Drawing a grid of triangles backed by a sparse vertex buffer. There should be no red pixels visible." << tcu::TestLog::EndMessage; 1375 1376 const DeviceInterface& vk = getDeviceInterface(); 1377 const deUint32 vertexCount = 6 * (GRID_SIZE * GRID_SIZE) / 2; 1378 VkDeviceSize vertexOffset = 0ull; 1379 1380 vk.cmdBindVertexBuffers (cmdBuffer, 0u, 1u, &m_sparseBuffer.get(), &vertexOffset); 1381 vk.cmdDraw (cmdBuffer, vertexCount, 1u, 0u, 0u); 1382 1383 vertexOffset += m_perDrawBufferOffset * (m_residency ? 2 : 1); 1384 1385 vk.cmdBindVertexBuffers (cmdBuffer, 0u, 1u, &m_sparseBuffer.get(), &vertexOffset); 1386 vk.cmdDraw (cmdBuffer, vertexCount, 1u, 0u, 0u); 1387 } 1388 1389 void initializeBuffers (void) 1390 { 1391 deUint8* pData = static_cast<deUint8*>(m_stagingBufferAlloc->getHostPtr()); 1392 const float step = 2.0f / static_cast<float>(GRID_SIZE); 1393 1394 // Prepare data for two draw calls 1395 generateGrid(pData, step, -1.0f, -1.0f, GRID_SIZE, GRID_SIZE/2); 1396 generateGrid(pData + m_perDrawBufferOffset, step, -1.0f, 0.0f, GRID_SIZE, GRID_SIZE/2); 1397 } 1398 }; 1399 1400 //! Sparse buffer backing an index buffer 1401 class IndexBufferTestInstance : public DrawGridTestInstance 1402 { 1403 public: 1404 IndexBufferTestInstance (Context& context, const TestFlags flags) 1405 : DrawGridTestInstance (context, 1406 flags, 1407 VK_BUFFER_USAGE_INDEX_BUFFER_BIT, 1408 GRID_SIZE * GRID_SIZE * 6 * sizeof(deUint32)) 1409 , m_halfVertexCount (6 * (GRID_SIZE * GRID_SIZE) / 2) 1410 { 1411 } 1412 1413 void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const 1414 { 1415 DE_UNREF(pipelineLayout); 1416 1417 m_context.getTestContext().getLog() 1418 << tcu::TestLog::Message << "Drawing a grid of triangles from a sparse index buffer. There should be no red pixels visible." << tcu::TestLog::EndMessage; 1419 1420 const DeviceInterface& vk = getDeviceInterface(); 1421 const VkDeviceSize vertexOffset = 0ull; 1422 VkDeviceSize indexOffset = 0ull; 1423 1424 vk.cmdBindVertexBuffers (cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexOffset); 1425 1426 vk.cmdBindIndexBuffer (cmdBuffer, *m_sparseBuffer, indexOffset, VK_INDEX_TYPE_UINT32); 1427 vk.cmdDrawIndexed (cmdBuffer, m_halfVertexCount, 1u, 0u, 0, 0u); 1428 1429 indexOffset += m_perDrawBufferOffset * (m_residency ? 2 : 1); 1430 1431 vk.cmdBindIndexBuffer (cmdBuffer, *m_sparseBuffer, indexOffset, VK_INDEX_TYPE_UINT32); 1432 vk.cmdDrawIndexed (cmdBuffer, m_halfVertexCount, 1u, 0u, 0, 0u); 1433 } 1434 1435 void initializeBuffers (void) 1436 { 1437 // Vertex buffer 1438 const DeviceInterface& vk = getDeviceInterface(); 1439 const VkDeviceSize vertexBufferSize = 2 * m_halfVertexCount * sizeof(Vec4); 1440 m_vertexBuffer = makeBuffer(vk, getDevice(), makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); 1441 m_vertexBufferAlloc = bindBuffer(vk, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible); 1442 1443 { 1444 const float step = 2.0f / static_cast<float>(GRID_SIZE); 1445 1446 generateGrid(m_vertexBufferAlloc->getHostPtr(), step, -1.0f, -1.0f, GRID_SIZE, GRID_SIZE); 1447 1448 flushMappedMemoryRange(vk, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferSize); 1449 } 1450 1451 // Sparse index buffer 1452 for (deUint32 chunkNdx = 0u; chunkNdx < 2; ++chunkNdx) 1453 { 1454 deUint8* const pData = static_cast<deUint8*>(m_stagingBufferAlloc->getHostPtr()) + chunkNdx * m_perDrawBufferOffset; 1455 deUint32* const pIndexData = reinterpret_cast<deUint32*>(pData); 1456 const deUint32 ndxBase = chunkNdx * m_halfVertexCount; 1457 1458 for (deUint32 i = 0u; i < m_halfVertexCount; ++i) 1459 pIndexData[i] = ndxBase + i; 1460 } 1461 } 1462 1463 private: 1464 const deUint32 m_halfVertexCount; 1465 Move<VkBuffer> m_vertexBuffer; 1466 MovePtr<Allocation> m_vertexBufferAlloc; 1467 }; 1468 1469 //! Draw from a sparse indirect buffer 1470 class IndirectBufferTestInstance : public DrawGridTestInstance 1471 { 1472 public: 1473 IndirectBufferTestInstance (Context& context, const TestFlags flags) 1474 : DrawGridTestInstance (context, 1475 flags, 1476 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, 1477 sizeof(VkDrawIndirectCommand)) 1478 { 1479 } 1480 1481 void rendererDraw (const VkPipelineLayout pipelineLayout, const VkCommandBuffer cmdBuffer) const 1482 { 1483 DE_UNREF(pipelineLayout); 1484 1485 m_context.getTestContext().getLog() 1486 << tcu::TestLog::Message << "Drawing two triangles covering the whole viewport. There should be no red pixels visible." << tcu::TestLog::EndMessage; 1487 1488 const DeviceInterface& vk = getDeviceInterface(); 1489 const VkDeviceSize vertexOffset = 0ull; 1490 VkDeviceSize indirectOffset = 0ull; 1491 1492 vk.cmdBindVertexBuffers (cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexOffset); 1493 vk.cmdDrawIndirect (cmdBuffer, *m_sparseBuffer, indirectOffset, 1u, 0u); 1494 1495 indirectOffset += m_perDrawBufferOffset * (m_residency ? 2 : 1); 1496 1497 vk.cmdDrawIndirect (cmdBuffer, *m_sparseBuffer, indirectOffset, 1u, 0u); 1498 } 1499 1500 void initializeBuffers (void) 1501 { 1502 // Vertex buffer 1503 const DeviceInterface& vk = getDeviceInterface(); 1504 const VkDeviceSize vertexBufferSize = 2 * 3 * sizeof(Vec4); 1505 m_vertexBuffer = makeBuffer(vk, getDevice(), makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); 1506 m_vertexBufferAlloc = bindBuffer(vk, getDevice(), getAllocator(), *m_vertexBuffer, MemoryRequirement::HostVisible); 1507 1508 { 1509 generateGrid(m_vertexBufferAlloc->getHostPtr(), 2.0f, -1.0f, -1.0f, 1, 1); 1510 flushMappedMemoryRange(vk, getDevice(), m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferSize); 1511 } 1512 1513 // Indirect buffer 1514 for (deUint32 chunkNdx = 0u; chunkNdx < 2; ++chunkNdx) 1515 { 1516 deUint8* const pData = static_cast<deUint8*>(m_stagingBufferAlloc->getHostPtr()) + chunkNdx * m_perDrawBufferOffset; 1517 VkDrawIndirectCommand* const pCmdData = reinterpret_cast<VkDrawIndirectCommand*>(pData); 1518 1519 pCmdData->firstVertex = 3u * chunkNdx; 1520 pCmdData->firstInstance = 0u; 1521 pCmdData->vertexCount = 3u; 1522 pCmdData->instanceCount = 1u; 1523 } 1524 } 1525 1526 private: 1527 Move<VkBuffer> m_vertexBuffer; 1528 MovePtr<Allocation> m_vertexBufferAlloc; 1529 }; 1530 1531 //! Similar to the class in vktTestCaseUtil.hpp, but uses Arg0 directly rather than through a InstanceFunction1 1532 template<typename Arg0> 1533 class FunctionProgramsSimple1 1534 { 1535 public: 1536 typedef void (*Function) (vk::SourceCollections& dst, Arg0 arg0); 1537 FunctionProgramsSimple1 (Function func) : m_func(func) {} 1538 void init (vk::SourceCollections& dst, const Arg0& arg0) const { m_func(dst, arg0); } 1539 1540 private: 1541 const Function m_func; 1542 }; 1543 1544 //! Convenience function to create a TestCase based on a freestanding initPrograms and a TestInstance implementation 1545 template<typename TestInstanceT, typename Arg0> 1546 TestCase* createTestInstanceWithPrograms (tcu::TestContext& testCtx, 1547 const std::string& name, 1548 const std::string& desc, 1549 typename FunctionProgramsSimple1<Arg0>::Function initPrograms, 1550 Arg0 arg0) 1551 { 1552 return new InstanceFactory1<TestInstanceT, Arg0, FunctionProgramsSimple1<Arg0> >( 1553 testCtx, tcu::NODETYPE_SELF_VALIDATE, name, desc, FunctionProgramsSimple1<Arg0>(initPrograms), arg0); 1554 } 1555 1556 void populateTestGroup (tcu::TestCaseGroup* parentGroup) 1557 { 1558 const struct 1559 { 1560 std::string name; 1561 TestFlags flags; 1562 } groups[] = 1563 { 1564 { "sparse_binding", 0u, }, 1565 { "sparse_binding_aliased", TEST_FLAG_ALIASED, }, 1566 { "sparse_residency", TEST_FLAG_RESIDENCY, }, 1567 { "sparse_residency_aliased", TEST_FLAG_RESIDENCY | TEST_FLAG_ALIASED, }, 1568 { "sparse_residency_non_resident_strict", TEST_FLAG_RESIDENCY | TEST_FLAG_NON_RESIDENT_STRICT,}, 1569 }; 1570 1571 const int numGroupsIncludingNonResidentStrict = DE_LENGTH_OF_ARRAY(groups); 1572 const int numGroupsDefaultList = numGroupsIncludingNonResidentStrict - 1; 1573 std::string devGroupPrefix = "device_group_"; 1574 1575 // Transfer 1576 { 1577 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "transfer", "")); 1578 { 1579 MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(parentGroup->getTestContext(), "sparse_binding", "")); 1580 addBufferSparseBindingTests(subGroup.get(), false); 1581 group->addChild(subGroup.release()); 1582 1583 MovePtr<tcu::TestCaseGroup> subGroupDeviceGroups(new tcu::TestCaseGroup(parentGroup->getTestContext(), "device_group_sparse_binding", "")); 1584 addBufferSparseBindingTests(subGroupDeviceGroups.get(), true); 1585 group->addChild(subGroupDeviceGroups.release()); 1586 } 1587 parentGroup->addChild(group.release()); 1588 } 1589 1590 // SSBO 1591 { 1592 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "ssbo", "")); 1593 { 1594 MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(parentGroup->getTestContext(), "sparse_binding_aliased", "")); 1595 addBufferSparseMemoryAliasingTests(subGroup.get(), false); 1596 group->addChild(subGroup.release()); 1597 1598 MovePtr<tcu::TestCaseGroup> subGroupDeviceGroups(new tcu::TestCaseGroup(parentGroup->getTestContext(), "device_group_sparse_binding_aliased", "")); 1599 addBufferSparseMemoryAliasingTests(subGroupDeviceGroups.get(), true); 1600 group->addChild(subGroupDeviceGroups.release()); 1601 } 1602 { 1603 MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(parentGroup->getTestContext(), "sparse_residency", "")); 1604 addBufferSparseResidencyTests(subGroup.get(), false); 1605 group->addChild(subGroup.release()); 1606 1607 MovePtr<tcu::TestCaseGroup> subGroupDeviceGroups(new tcu::TestCaseGroup(parentGroup->getTestContext(), "device_group_sparse_residency", "")); 1608 addBufferSparseResidencyTests(subGroupDeviceGroups.get(), true); 1609 group->addChild(subGroupDeviceGroups.release()); 1610 } 1611 parentGroup->addChild(group.release()); 1612 } 1613 1614 // UBO 1615 { 1616 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "ubo", "")); 1617 1618 for (int groupNdx = 0u; groupNdx < numGroupsIncludingNonResidentStrict; ++groupNdx) 1619 { 1620 group->addChild(createTestInstanceWithPrograms<UBOTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawWithUBO, groups[groupNdx].flags)); 1621 } 1622 for (int groupNdx = 0u; groupNdx < numGroupsIncludingNonResidentStrict; ++groupNdx) 1623 { 1624 group->addChild(createTestInstanceWithPrograms<UBOTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawWithUBO, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS)); 1625 } 1626 parentGroup->addChild(group.release()); 1627 } 1628 1629 // Vertex buffer 1630 { 1631 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "vertex_buffer", "")); 1632 1633 for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx) 1634 { 1635 group->addChild(createTestInstanceWithPrograms<VertexBufferTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags)); 1636 } 1637 for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx) 1638 { 1639 group->addChild(createTestInstanceWithPrograms<VertexBufferTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS)); 1640 } 1641 1642 parentGroup->addChild(group.release()); 1643 } 1644 1645 // Index buffer 1646 { 1647 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "index_buffer", "")); 1648 1649 for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx) 1650 { 1651 group->addChild(createTestInstanceWithPrograms<IndexBufferTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags)); 1652 } 1653 for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx) 1654 { 1655 group->addChild(createTestInstanceWithPrograms<IndexBufferTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS)); 1656 } 1657 1658 parentGroup->addChild(group.release()); 1659 } 1660 1661 // Indirect buffer 1662 { 1663 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(parentGroup->getTestContext(), "indirect_buffer", "")); 1664 1665 for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx) 1666 { 1667 group->addChild(createTestInstanceWithPrograms<IndirectBufferTestInstance>(group->getTestContext(), groups[groupNdx].name.c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags)); 1668 } 1669 for (int groupNdx = 0u; groupNdx < numGroupsDefaultList; ++groupNdx) 1670 { 1671 group->addChild(createTestInstanceWithPrograms<IndirectBufferTestInstance>(group->getTestContext(), (devGroupPrefix + groups[groupNdx].name).c_str(), "", initProgramsDrawGrid, groups[groupNdx].flags | TEST_FLAG_ENABLE_DEVICE_GROUPS)); 1672 } 1673 1674 parentGroup->addChild(group.release()); 1675 } 1676 } 1677 1678 } // anonymous ns 1679 1680 tcu::TestCaseGroup* createSparseBufferTests (tcu::TestContext& testCtx) 1681 { 1682 return createTestGroup(testCtx, "buffer", "Sparse buffer usage tests", populateTestGroup); 1683 } 1684 1685 } // sparse 1686 } // vkt 1687