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,BufferCaseParameters testCase)123 BuffersTestCase (tcu::TestContext& testCtx,
124 const std::string& name,
125 BufferCaseParameters testCase)
126 : TestCase (testCtx, name)
127 , m_testCase (testCase)
128 {
129 }
130
~BuffersTestCase(void)131 virtual ~BuffersTestCase (void)
132 {
133 }
134
createInstance(Context & ctx) const135 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
checkSupport(Context & ctx) const142 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
156 private:
157 BufferCaseParameters m_testCase;
158 };
159
160 class DedicatedAllocationBuffersTestCase : public TestCase
161 {
162 public:
DedicatedAllocationBuffersTestCase(tcu::TestContext & testCtx,const std::string & name,BufferCaseParameters testCase)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
~DedicatedAllocationBuffersTestCase(void)172 virtual ~DedicatedAllocationBuffersTestCase
173 (void)
174 {
175 }
176
createInstance(Context & ctx) const177 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
checkSupport(Context & ctx) const184 virtual void checkSupport (Context& ctx) const
185 {
186 if (!ctx.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
187 TCU_THROW(NotSupportedError, "Not supported");
188 }
189 private:
190 BufferCaseParameters m_testCase;
191 };
192
bufferCreateAndAllocTest(VkDeviceSize size)193 tcu::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
iterate(void)379 tcu::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
bufferCreateAndAllocTest(VkDeviceSize size)403 tcu::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
getBufferUsageFlagsName(const VkBufferUsageFlags flags)561 std::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
getBufferCreateFlagsName(const VkBufferCreateFlags flags)580 std::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
createBufferUsageCases(tcu::TestCaseGroup & testGroup,const deUint32 firstNdx,const deUint32 bufferUsageFlags,const AllocationKind allocationKind)599 void 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
testDepthStencilBufferFeatures(Context & context,VkFormat format)675 tcu::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
689 struct LargeBufferParameters
690 {
691 deUint64 bufferSize;
692 bool useMaxBufferSize;
693 VkBufferCreateFlags flags;
694 };
695
696 #ifndef CTS_USES_VULKANSC
testLargeBuffer(Context & context,LargeBufferParameters params)697 tcu::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
checkMaintenance4Support(Context & context,LargeBufferParameters params)750 void 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
createBufferTests(tcu::TestContext & testCtx)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