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