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