1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 The Khronos Group Inc. 6 * Copyright (c) 2015 Samsung Electronics Co., Ltd. 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 Vulkan Buffers Tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktApiBufferTests.hpp" 26 #include "gluVarType.hpp" 27 #include "deStringUtil.hpp" 28 #include "tcuTestLog.hpp" 29 #include "vkPlatform.hpp" 30 #include "vkPrograms.hpp" 31 #include "vkQueryUtil.hpp" 32 #include "vkRefUtil.hpp" 33 #include "vktTestCase.hpp" 34 #include "tcuPlatform.hpp" 35 36 #include <algorithm> 37 38 namespace vkt 39 { 40 namespace api 41 { 42 namespace 43 { 44 using namespace vk; 45 46 enum AllocationKind 47 { 48 ALLOCATION_KIND_SUBALLOCATED = 0, 49 ALLOCATION_KIND_DEDICATED, 50 51 ALLOCATION_KIND_LAST, 52 }; 53 54 PlatformMemoryLimits getPlatformMemoryLimits (Context& context) 55 { 56 PlatformMemoryLimits memoryLimits; 57 58 context.getTestContext().getPlatform().getVulkanPlatform().getMemoryLimits(memoryLimits); 59 60 return memoryLimits; 61 } 62 63 VkDeviceSize getMaxBufferSize(const VkDeviceSize& bufferSize, 64 const VkDeviceSize& alignment, 65 const PlatformMemoryLimits& limits) 66 { 67 VkDeviceSize size = bufferSize; 68 69 if (limits.totalDeviceLocalMemory == 0) 70 { 71 // 'UMA' systems where device memory counts against system memory 72 size = std::min(bufferSize, limits.totalSystemMemory - alignment); 73 } 74 else 75 { 76 // 'LMA' systems where device memory is local to the GPU 77 size = std::min(bufferSize, limits.totalDeviceLocalMemory - alignment); 78 } 79 80 return size; 81 } 82 83 struct BufferCaseParameters 84 { 85 VkBufferUsageFlags usage; 86 VkBufferCreateFlags flags; 87 VkSharingMode sharingMode; 88 }; 89 90 class BufferTestInstance : public TestInstance 91 { 92 public: 93 BufferTestInstance (Context& ctx, 94 BufferCaseParameters testCase) 95 : TestInstance (ctx) 96 , m_testCase (testCase) 97 , m_sparseContext (createSparseContext()) 98 { 99 } 100 virtual tcu::TestStatus iterate (void); 101 virtual tcu::TestStatus bufferCreateAndAllocTest (VkDeviceSize size); 102 103 protected: 104 BufferCaseParameters m_testCase; 105 106 // Wrapper functions around m_context calls to support sparse cases. 107 VkPhysicalDevice getPhysicalDevice (void) const 108 { 109 // Same in sparse and regular case 110 return m_context.getPhysicalDevice(); 111 } 112 113 VkDevice getDevice (void) const 114 { 115 if (m_sparseContext) 116 { 117 return *(m_sparseContext->m_device); 118 } 119 return m_context.getDevice(); 120 } 121 122 const InstanceInterface& getInstanceInterface (void) const 123 { 124 // Same in sparse and regular case 125 return m_context.getInstanceInterface(); 126 } 127 128 const DeviceInterface& getDeviceInterface (void) const 129 { 130 if (m_sparseContext) 131 { 132 return m_sparseContext->m_deviceInterface; 133 } 134 return m_context.getDeviceInterface(); 135 } 136 137 deUint32 getUniversalQueueFamilyIndex (void) const 138 { 139 if (m_sparseContext) 140 { 141 return m_sparseContext->m_queueFamilyIndex; 142 } 143 return m_context.getUniversalQueueFamilyIndex(); 144 } 145 146 private: 147 // Custom context for sparse cases 148 struct SparseContext 149 { 150 SparseContext (Move<VkDevice>& device, 151 const deUint32 queueFamilyIndex, 152 const InstanceInterface& interface) 153 : m_device (device) 154 , m_queueFamilyIndex (queueFamilyIndex) 155 , m_deviceInterface (interface, *m_device) 156 { 157 } 158 159 Unique<VkDevice> m_device; 160 const deUint32 m_queueFamilyIndex; 161 DeviceDriver m_deviceInterface; 162 }; 163 164 de::UniquePtr<SparseContext> m_sparseContext; 165 166 static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, 167 VkPhysicalDevice physicalDevice, 168 VkQueueFlags requiredCaps) 169 { 170 const std::vector<vk::VkQueueFamilyProperties> 171 queueProps = getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice); 172 173 for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++) 174 { 175 if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps) 176 { 177 return (deUint32)queueNdx; 178 } 179 } 180 181 TCU_THROW(NotSupportedError, "No matching queue found"); 182 } 183 184 // Create the sparseContext 185 SparseContext* createSparseContext (void) const 186 { 187 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) 188 || (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) 189 || (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) 190 { 191 const InstanceInterface& vk = getInstanceInterface(); 192 const VkPhysicalDevice physicalDevice = getPhysicalDevice(); 193 const vk::VkPhysicalDeviceFeatures 194 deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice); 195 const deUint32 queueIndex = findQueueFamilyIndexWithCaps(vk, physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT); 196 const float queuePriority = 1.0f; 197 VkDeviceQueueCreateInfo queueInfo = 198 { 199 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 200 DE_NULL, 201 static_cast<VkDeviceQueueCreateFlags>(0u), 202 queueIndex, 203 1u, 204 &queuePriority 205 }; 206 VkDeviceCreateInfo deviceInfo = 207 { 208 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 209 DE_NULL, 210 static_cast<VkDeviceQueueCreateFlags>(0u), 211 1u, 212 &queueInfo, 213 0u, 214 DE_NULL, 215 0u, 216 DE_NULL, 217 &deviceFeatures 218 }; 219 220 Move<VkDevice> device = createDevice(vk, physicalDevice, &deviceInfo); 221 222 return new SparseContext(device, queueIndex, vk); 223 } 224 225 return DE_NULL; 226 } 227 }; 228 229 class DedicatedAllocationBufferTestInstance : public BufferTestInstance 230 { 231 public: 232 DedicatedAllocationBufferTestInstance 233 (Context& ctx, 234 BufferCaseParameters testCase) 235 : BufferTestInstance (ctx, testCase) 236 { 237 } 238 virtual tcu::TestStatus bufferCreateAndAllocTest (VkDeviceSize size); 239 }; 240 241 class BuffersTestCase : public TestCase 242 { 243 public: 244 BuffersTestCase (tcu::TestContext& testCtx, 245 const std::string& name, 246 const std::string& description, 247 BufferCaseParameters testCase) 248 : TestCase (testCtx, name, description) 249 , m_testCase (testCase) 250 { 251 } 252 253 virtual ~BuffersTestCase (void) 254 { 255 } 256 257 virtual TestInstance* createInstance (Context& ctx) const 258 { 259 tcu::TestLog& log = m_testCtx.getLog(); 260 log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage; 261 return new BufferTestInstance(ctx, m_testCase); 262 } 263 264 private: 265 BufferCaseParameters m_testCase; 266 }; 267 268 class DedicatedAllocationBuffersTestCase : public TestCase 269 { 270 public: 271 DedicatedAllocationBuffersTestCase 272 (tcu::TestContext& testCtx, 273 const std::string& name, 274 const std::string& description, 275 BufferCaseParameters testCase) 276 : TestCase (testCtx, name, description) 277 , m_testCase (testCase) 278 { 279 } 280 281 virtual ~DedicatedAllocationBuffersTestCase 282 (void) 283 { 284 } 285 286 virtual TestInstance* createInstance (Context& ctx) const 287 { 288 tcu::TestLog& log = m_testCtx.getLog(); 289 log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage; 290 const std::vector<std::string>& extensions = ctx.getDeviceExtensions(); 291 const deBool isSupported = isDeviceExtensionSupported(ctx.getUsedApiVersion(), extensions, "VK_KHR_dedicated_allocation"); 292 if (!isSupported) 293 { 294 TCU_THROW(NotSupportedError, "Not supported"); 295 } 296 return new DedicatedAllocationBufferTestInstance(ctx, m_testCase); 297 } 298 299 private: 300 BufferCaseParameters m_testCase; 301 }; 302 303 tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size) 304 { 305 const VkPhysicalDevice vkPhysicalDevice = getPhysicalDevice(); 306 const InstanceInterface& vkInstance = getInstanceInterface(); 307 const VkDevice vkDevice = getDevice(); 308 const DeviceInterface& vk = getDeviceInterface(); 309 const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex(); 310 const VkPhysicalDeviceMemoryProperties 311 memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice); 312 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits; 313 Move<VkBuffer> buffer; 314 Move<VkDeviceMemory> memory; 315 VkMemoryRequirements memReqs; 316 317 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0) 318 { 319 size = std::min(size, limits.sparseAddressSpaceSize); 320 } 321 322 // Create the test buffer and a memory allocation for it 323 { 324 // Create a minimal buffer first to get the supported memory types 325 VkBufferCreateInfo bufferParams = 326 { 327 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; 328 DE_NULL, // const void* pNext; 329 m_testCase.flags, // VkBufferCreateFlags flags; 330 1u, // VkDeviceSize size; 331 m_testCase.usage, // VkBufferUsageFlags usage; 332 m_testCase.sharingMode, // VkSharingMode sharingMode; 333 1u, // uint32_t queueFamilyIndexCount; 334 &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices; 335 }; 336 337 buffer = createBuffer(vk, vkDevice, &bufferParams); 338 vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs); 339 340 const deUint32 heapTypeIndex = (deUint32)deCtz32(memReqs.memoryTypeBits); 341 const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex]; 342 const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex]; 343 const deUint32 shrinkBits = 4u; // number of bits to shift when reducing the size with each iteration 344 345 // Buffer size - Choose half of the reported heap size for the maximum buffer size, we 346 // should attempt to test as large a portion as possible. 347 // 348 // However on a system where device memory is shared with the system, the maximum size 349 // should be tested against the platform memory limits as significant portion of the heap 350 // may already be in use by the operating system and other running processes. 351 const VkDeviceSize availableBufferSize = getMaxBufferSize(memoryHeap.size, 352 memReqs.alignment, 353 getPlatformMemoryLimits(m_context)); 354 355 // For our test buffer size, halve the maximum available size and align 356 const VkDeviceSize maxBufferSize = deAlign64(availableBufferSize >> 1, memReqs.alignment); 357 358 size = std::min(size, maxBufferSize); 359 360 while (*memory == DE_NULL) 361 { 362 // Create the buffer 363 { 364 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY; 365 VkBuffer rawBuffer = DE_NULL; 366 367 bufferParams.size = size; 368 buffer = Move<VkBuffer>(); // free the previous buffer, if any 369 result = vk.createBuffer(vkDevice, &bufferParams, (vk::VkAllocationCallbacks*)DE_NULL, &rawBuffer); 370 371 if (result != VK_SUCCESS) 372 { 373 size = deAlign64(size >> shrinkBits, memReqs.alignment); 374 375 if (size == 0 || bufferParams.size == memReqs.alignment) 376 { 377 return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")"); 378 } 379 380 continue; // didn't work, try with a smaller buffer 381 } 382 383 buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL)); 384 } 385 386 vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs); // get the proper size requirement 387 388 if (size > memReqs.size) 389 { 390 std::ostringstream errorMsg; 391 errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!"; 392 return tcu::TestStatus::fail(errorMsg.str()); 393 } 394 395 // Allocate the memory 396 { 397 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY; 398 VkDeviceMemory rawMemory = DE_NULL; 399 400 const VkMemoryAllocateInfo 401 memAlloc = 402 { 403 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType; 404 NULL, // const void* pNext; 405 memReqs.size, // VkDeviceSize allocationSize; 406 heapTypeIndex, // uint32_t memoryTypeIndex; 407 }; 408 409 result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory); 410 411 if (result != VK_SUCCESS) 412 { 413 size = deAlign64(size >> shrinkBits, memReqs.alignment); 414 415 if (size == 0 || memReqs.size == memReqs.alignment) 416 { 417 return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory"); 418 } 419 420 continue; // didn't work, try with a smaller allocation (and a smaller buffer) 421 } 422 423 memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL)); 424 } 425 } // while 426 } 427 428 // Bind the memory 429 if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0) 430 { 431 const VkQueue queue = getDeviceQueue(vk, vkDevice, queueFamilyIndex, 0); 432 433 const VkSparseMemoryBind sparseMemoryBind = 434 { 435 0, // VkDeviceSize resourceOffset; 436 memReqs.size, // VkDeviceSize size; 437 *memory, // VkDeviceMemory memory; 438 0, // VkDeviceSize memoryOffset; 439 0 // VkSparseMemoryBindFlags flags; 440 }; 441 442 const VkSparseBufferMemoryBindInfo 443 sparseBufferMemoryBindInfo = 444 { 445 *buffer, // VkBuffer buffer; 446 1u, // deUint32 bindCount; 447 &sparseMemoryBind // const VkSparseMemoryBind* pBinds; 448 }; 449 450 const VkBindSparseInfo bindSparseInfo = 451 { 452 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType; 453 DE_NULL, // const void* pNext; 454 0, // deUint32 waitSemaphoreCount; 455 DE_NULL, // const VkSemaphore* pWaitSemaphores; 456 1u, // deUint32 bufferBindCount; 457 &sparseBufferMemoryBindInfo, // const VkSparseBufferMemoryBindInfo* pBufferBinds; 458 0, // deUint32 imageOpaqueBindCount; 459 DE_NULL, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; 460 0, // deUint32 imageBindCount; 461 DE_NULL, // const VkSparseImageMemoryBindInfo* pImageBinds; 462 0, // deUint32 signalSemaphoreCount; 463 DE_NULL, // const VkSemaphore* pSignalSemaphores; 464 }; 465 466 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, vkDevice)); 467 468 if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS) 469 return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")"); 470 471 VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */)); 472 } 473 else if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS) 474 return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")"); 475 476 return tcu::TestStatus::pass("Pass"); 477 } 478 479 tcu::TestStatus BufferTestInstance::iterate (void) 480 { 481 const VkPhysicalDeviceFeatures& physicalDeviceFeatures = getPhysicalDeviceFeatures(getInstanceInterface(), getPhysicalDevice()); 482 483 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding) 484 TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported"); 485 486 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer) 487 TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported"); 488 489 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased) 490 TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported"); 491 492 const VkDeviceSize testSizes[] = 493 { 494 1, 495 1181, 496 15991, 497 16384, 498 ~0ull, // try to exercise a very large buffer too (will be clamped to a sensible size later) 499 }; 500 501 for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i) 502 { 503 const tcu::TestStatus testStatus = bufferCreateAndAllocTest(testSizes[i]); 504 505 if (testStatus.getCode() != QP_TEST_RESULT_PASS) 506 return testStatus; 507 } 508 509 return tcu::TestStatus::pass("Pass"); 510 } 511 512 tcu::TestStatus DedicatedAllocationBufferTestInstance::bufferCreateAndAllocTest 513 (VkDeviceSize size) 514 { 515 const VkPhysicalDevice vkPhysicalDevice = getPhysicalDevice(); 516 const InstanceInterface& vkInstance = getInstanceInterface(); 517 const VkDevice vkDevice = getDevice(); 518 const DeviceInterface& vk = getDeviceInterface(); 519 const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex(); 520 const VkPhysicalDeviceMemoryProperties 521 memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice); 522 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits; 523 524 VkMemoryDedicatedRequirements dedicatedRequirements = 525 { 526 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, // VkStructureType sType; 527 DE_NULL, // const void* pNext; 528 false, // VkBool32 prefersDedicatedAllocation 529 false // VkBool32 requiresDedicatedAllocation 530 }; 531 VkMemoryRequirements2 memReqs = 532 { 533 VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, // VkStructureType sType 534 &dedicatedRequirements, // void* pNext 535 {0, 0, 0} // VkMemoryRequirements memoryRequirements 536 }; 537 538 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0) 539 size = std::min(size, limits.sparseAddressSpaceSize); 540 541 // Create a minimal buffer first to get the supported memory types 542 VkBufferCreateInfo bufferParams = 543 { 544 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType 545 DE_NULL, // const void* pNext 546 m_testCase.flags, // VkBufferCreateFlags flags 547 1u, // VkDeviceSize size 548 m_testCase.usage, // VkBufferUsageFlags usage 549 m_testCase.sharingMode, // VkSharingMode sharingMode 550 1u, // uint32_t queueFamilyIndexCount 551 &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices 552 }; 553 554 Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &bufferParams); 555 556 VkBufferMemoryRequirementsInfo2 info = 557 { 558 VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, // VkStructureType sType 559 DE_NULL, // const void* pNext 560 *buffer // VkBuffer buffer 561 }; 562 563 vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs); 564 565 if (dedicatedRequirements.requiresDedicatedAllocation == VK_TRUE) 566 { 567 std::ostringstream errorMsg; 568 errorMsg << "Nonexternal objects cannot require dedicated allocation."; 569 return tcu::TestStatus::fail(errorMsg.str()); 570 } 571 572 const deUint32 heapTypeIndex = static_cast<deUint32>(deCtz32(memReqs.memoryRequirements.memoryTypeBits)); 573 const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex]; 574 const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex]; 575 const deUint32 shrinkBits = 4u; // number of bits to shift when reducing the size with each iteration 576 577 // Buffer size - Choose half of the reported heap size for the maximum buffer size, we 578 // should attempt to test as large a portion as possible. 579 // 580 // However on a system where device memory is shared with the system, the maximum size 581 // should be tested against the platform memory limits as a significant portion of the heap 582 // may already be in use by the operating system and other running processes. 583 const VkDeviceSize maxBufferSize = getMaxBufferSize(memoryHeap.size, 584 memReqs.memoryRequirements.alignment, 585 getPlatformMemoryLimits(m_context)); 586 587 Move<VkDeviceMemory> memory; 588 size = deAlign64(std::min(size, maxBufferSize >> 1), memReqs.memoryRequirements.alignment); 589 while (*memory == DE_NULL) 590 { 591 // Create the buffer 592 { 593 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY; 594 VkBuffer rawBuffer = DE_NULL; 595 596 bufferParams.size = size; 597 buffer = Move<VkBuffer>(); // free the previous buffer, if any 598 result = vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer); 599 600 if (result != VK_SUCCESS) 601 { 602 size = deAlign64(size >> shrinkBits, memReqs.memoryRequirements.alignment); 603 604 if (size == 0 || bufferParams.size == memReqs.memoryRequirements.alignment) 605 return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")"); 606 607 continue; // didn't work, try with a smaller buffer 608 } 609 610 buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL)); 611 } 612 613 info.buffer = *buffer; 614 vk.getBufferMemoryRequirements2(vkDevice, &info, &memReqs); // get the proper size requirement 615 616 if (size > memReqs.memoryRequirements.size) 617 { 618 std::ostringstream errorMsg; 619 errorMsg << "Requied memory size (" << memReqs.memoryRequirements.size << " bytes) smaller than the buffer's size (" << size << " bytes)!"; 620 return tcu::TestStatus::fail(errorMsg.str()); 621 } 622 623 // Allocate the memory 624 { 625 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY; 626 VkDeviceMemory rawMemory = DE_NULL; 627 628 vk::VkMemoryDedicatedAllocateInfo 629 dedicatedInfo = 630 { 631 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, // VkStructureType sType 632 DE_NULL, // const void* pNext 633 DE_NULL, // VkImage image 634 *buffer // VkBuffer buffer 635 }; 636 637 VkMemoryAllocateInfo memoryAllocateInfo = 638 { 639 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType 640 &dedicatedInfo, // const void* pNext 641 memReqs.memoryRequirements.size, // VkDeviceSize allocationSize 642 heapTypeIndex, // deUint32 memoryTypeIndex 643 }; 644 645 result = vk.allocateMemory(vkDevice, &memoryAllocateInfo, (VkAllocationCallbacks*)DE_NULL, &rawMemory); 646 647 if (result != VK_SUCCESS) 648 { 649 size = deAlign64(size >> shrinkBits, memReqs.memoryRequirements.alignment); 650 651 if (size == 0 || memReqs.memoryRequirements.size == memReqs.memoryRequirements.alignment) 652 return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.memoryRequirements.size) + " bytes of memory"); 653 654 continue; // didn't work, try with a smaller allocation (and a smaller buffer) 655 } 656 657 memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL)); 658 } 659 } // while 660 661 if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS) 662 return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")"); 663 664 return tcu::TestStatus::pass("Pass"); 665 } 666 667 std::string getBufferUsageFlagsName (const VkBufferUsageFlags flags) 668 { 669 switch (flags) 670 { 671 case VK_BUFFER_USAGE_TRANSFER_SRC_BIT: return "transfer_src"; 672 case VK_BUFFER_USAGE_TRANSFER_DST_BIT: return "transfer_dst"; 673 case VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT: return "uniform_texel"; 674 case VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT: return "storage_texel"; 675 case VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT: return "uniform"; 676 case VK_BUFFER_USAGE_STORAGE_BUFFER_BIT: return "storage"; 677 case VK_BUFFER_USAGE_INDEX_BUFFER_BIT: return "index"; 678 case VK_BUFFER_USAGE_VERTEX_BUFFER_BIT: return "vertex"; 679 case VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT: return "indirect"; 680 default: 681 DE_FATAL("Unknown buffer usage flag"); 682 return ""; 683 } 684 } 685 686 std::string getBufferCreateFlagsName (const VkBufferCreateFlags flags) 687 { 688 std::ostringstream name; 689 690 if (flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) 691 name << "_binding"; 692 if (flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) 693 name << "_residency"; 694 if (flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) 695 name << "_aliased"; 696 if (flags == 0u) 697 name << "_zero"; 698 699 DE_ASSERT(!name.str().empty()); 700 701 return name.str().substr(1); 702 } 703 704 // Create all VkBufferUsageFlags combinations recursively 705 void createBufferUsageCases (tcu::TestCaseGroup& testGroup, const deUint32 firstNdx, const deUint32 bufferUsageFlags, const AllocationKind allocationKind) 706 { 707 const VkBufferUsageFlags bufferUsageModes[] = 708 { 709 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 710 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 711 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 712 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, 713 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 714 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 715 VK_BUFFER_USAGE_INDEX_BUFFER_BIT, 716 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 717 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT 718 }; 719 720 tcu::TestContext& testCtx = testGroup.getTestContext(); 721 722 // Add test groups 723 for (deUint32 currentNdx = firstNdx; currentNdx < DE_LENGTH_OF_ARRAY(bufferUsageModes); currentNdx++) 724 { 725 const deUint32 newBufferUsageFlags = bufferUsageFlags | bufferUsageModes[currentNdx]; 726 const std::string newGroupName = getBufferUsageFlagsName(bufferUsageModes[currentNdx]); 727 de::MovePtr<tcu::TestCaseGroup> newTestGroup (new tcu::TestCaseGroup(testCtx, newGroupName.c_str(), "")); 728 729 createBufferUsageCases(*newTestGroup, currentNdx + 1u, newBufferUsageFlags, allocationKind); 730 testGroup.addChild(newTestGroup.release()); 731 } 732 733 // Add test cases 734 if (bufferUsageFlags != 0u) 735 { 736 // \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag. 737 const VkBufferCreateFlags bufferCreateFlags[] = 738 { 739 0, 740 VK_BUFFER_CREATE_SPARSE_BINDING_BIT, 741 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, 742 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, 743 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, 744 }; 745 746 // Dedicated allocation does not support sparse feature 747 const int numBufferCreateFlags = (allocationKind == ALLOCATION_KIND_SUBALLOCATED) ? DE_LENGTH_OF_ARRAY(bufferCreateFlags) : 1; 748 749 de::MovePtr<tcu::TestCaseGroup> newTestGroup (new tcu::TestCaseGroup(testCtx, "create", "")); 750 751 for (int bufferCreateFlagsNdx = 0; bufferCreateFlagsNdx < numBufferCreateFlags; bufferCreateFlagsNdx++) 752 { 753 const BufferCaseParameters testParams = 754 { 755 bufferUsageFlags, 756 bufferCreateFlags[bufferCreateFlagsNdx], 757 VK_SHARING_MODE_EXCLUSIVE 758 }; 759 760 const std::string allocStr = (allocationKind == ALLOCATION_KIND_SUBALLOCATED) ? "suballocation of " : "dedicated alloc. of "; 761 const std::string caseName = getBufferCreateFlagsName(bufferCreateFlags[bufferCreateFlagsNdx]); 762 const std::string caseDesc = "vkCreateBuffer test: " + allocStr + de::toString(bufferUsageFlags) + " " + de::toString(testParams.flags); 763 764 switch (allocationKind) 765 { 766 case ALLOCATION_KIND_SUBALLOCATED: 767 newTestGroup->addChild(new BuffersTestCase(testCtx, caseName.c_str(), caseDesc.c_str(), testParams)); 768 break; 769 case ALLOCATION_KIND_DEDICATED: 770 newTestGroup->addChild(new DedicatedAllocationBuffersTestCase(testCtx, caseName.c_str(), caseDesc.c_str(), testParams)); 771 break; 772 default: 773 DE_FATAL("Unknown test type"); 774 } 775 } 776 testGroup.addChild(newTestGroup.release()); 777 } 778 } 779 780 } // anonymous 781 782 tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx) 783 { 784 de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests")); 785 786 { 787 de::MovePtr<tcu::TestCaseGroup> regularAllocation (new tcu::TestCaseGroup(testCtx, "suballocation", "Regular suballocation of memory.")); 788 createBufferUsageCases(*regularAllocation, 0u, 0u, ALLOCATION_KIND_SUBALLOCATED); 789 buffersTests->addChild(regularAllocation.release()); 790 } 791 792 { 793 de::MovePtr<tcu::TestCaseGroup> dedicatedAllocation (new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "Dedicated allocation of memory.")); 794 createBufferUsageCases(*dedicatedAllocation, 0u, 0u, ALLOCATION_KIND_DEDICATED); 795 buffersTests->addChild(dedicatedAllocation.release()); 796 } 797 798 return buffersTests.release(); 799 } 800 801 } // api 802 } // vk 803