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