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