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