1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Vulkan Buffers Tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktApiBufferTests.hpp"
27 #include "deStringUtil.hpp"
28 #include "gluVarType.hpp"
29 #include "tcuTestLog.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vktTestCase.hpp"
44 struct BufferCaseParameters
46 VkBufferUsageFlags usage;
47 VkBufferCreateFlags flags;
48 VkSharingMode sharingMode;
51 class BufferTestInstance : public TestInstance
54 BufferTestInstance (Context& ctx,
55 BufferCaseParameters testCase)
57 , m_testCase (testCase)
58 , m_sparseContext (createSparseContext())
60 virtual tcu::TestStatus iterate (void);
61 tcu::TestStatus bufferCreateAndAllocTest (VkDeviceSize size);
64 BufferCaseParameters m_testCase;
67 // Custom context for sparse cases
70 SparseContext (Move<VkDevice>& device, const deUint32 queueFamilyIndex, const InstanceInterface& interface)
72 , m_queueFamilyIndex (queueFamilyIndex)
73 , m_deviceInterface (interface, *m_device)
76 Unique<VkDevice> m_device;
77 const deUint32 m_queueFamilyIndex;
78 DeviceDriver m_deviceInterface;
81 de::UniquePtr<SparseContext> m_sparseContext;
83 // Wrapper functions around m_context calls to support sparse cases.
84 VkPhysicalDevice getPhysicalDevice (void) const
86 // Same in sparse and regular case
87 return m_context.getPhysicalDevice();
90 VkDevice getDevice (void) const
93 return *(m_sparseContext->m_device);
95 return m_context.getDevice();
98 const InstanceInterface& getInstanceInterface (void) const
100 // Same in sparse and regular case
101 return m_context.getInstanceInterface();
104 const DeviceInterface& getDeviceInterface (void) const
107 return m_sparseContext->m_deviceInterface;
109 return m_context.getDeviceInterface();
112 deUint32 getUniversalQueueFamilyIndex (void) const
115 return m_sparseContext->m_queueFamilyIndex;
117 return m_context.getUniversalQueueFamilyIndex();
120 static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
122 const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
124 for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
126 if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
127 return (deUint32)queueNdx;
130 TCU_THROW(NotSupportedError, "No matching queue found");
133 // Create the sparseContext
134 SparseContext* createSparseContext (void) const
136 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
137 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
138 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
140 const InstanceInterface& vk = getInstanceInterface();
141 const VkPhysicalDevice physicalDevice = getPhysicalDevice();
142 const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice);
144 const deUint32 queueIndex = findQueueFamilyIndexWithCaps(vk, physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT);
146 VkDeviceQueueCreateInfo queueInfo;
147 VkDeviceCreateInfo deviceInfo;
148 const float queuePriority = 1.0f;
150 deMemset(&queueInfo, 0, sizeof(queueInfo));
151 deMemset(&deviceInfo, 0, sizeof(deviceInfo));
153 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
154 queueInfo.pNext = DE_NULL;
155 queueInfo.flags = (VkDeviceQueueCreateFlags)0u;
156 queueInfo.queueFamilyIndex = queueIndex;
157 queueInfo.queueCount = 1u;
158 queueInfo.pQueuePriorities = &queuePriority;
160 deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
161 deviceInfo.pNext = DE_NULL;
162 deviceInfo.queueCreateInfoCount = 1u;
163 deviceInfo.pQueueCreateInfos = &queueInfo;
164 deviceInfo.enabledExtensionCount = 0u;
165 deviceInfo.ppEnabledExtensionNames = DE_NULL;
166 deviceInfo.enabledLayerCount = 0u;
167 deviceInfo.ppEnabledLayerNames = DE_NULL;
168 deviceInfo.pEnabledFeatures = &deviceFeatures;
170 Move<VkDevice> device = createDevice(vk, physicalDevice, &deviceInfo);
172 return new SparseContext(device, queueIndex, vk);
179 class BuffersTestCase : public TestCase
182 BuffersTestCase (tcu::TestContext& testCtx,
183 const std::string& name,
184 const std::string& description,
185 BufferCaseParameters testCase)
186 : TestCase(testCtx, name, description)
187 , m_testCase(testCase)
190 virtual ~BuffersTestCase (void) {}
191 virtual TestInstance* createInstance (Context& ctx) const
193 tcu::TestLog& log = m_testCtx.getLog();
194 log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
195 return new BufferTestInstance(ctx, m_testCase);
199 BufferCaseParameters m_testCase;
202 inline VkDeviceSize alignDeviceSize (VkDeviceSize val, VkDeviceSize align)
204 DE_ASSERT(deIsPowerOfTwo64(align));
205 DE_ASSERT(val + align >= val); // crash on overflow
206 return (val + align - 1) & ~(align - 1);
209 tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
211 const VkPhysicalDevice vkPhysicalDevice = getPhysicalDevice();
212 const InstanceInterface& vkInstance = getInstanceInterface();
213 const VkDevice vkDevice = getDevice();
214 const DeviceInterface& vk = getDeviceInterface();
215 const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
216 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
217 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits;
218 Move<VkBuffer> buffer;
219 Move<VkDeviceMemory> memory;
220 VkMemoryRequirements memReqs;
222 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
223 size = std::min(size, limits.sparseAddressSpaceSize);
225 // Create the test buffer and a memory allocation for it
227 // Create a minimal buffer first to get the supported memory types
228 VkBufferCreateInfo bufferParams =
230 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
231 DE_NULL, // const void* pNext;
232 m_testCase.flags, // VkBufferCreateFlags flags;
233 1u, // VkDeviceSize size;
234 m_testCase.usage, // VkBufferUsageFlags usage;
235 m_testCase.sharingMode, // VkSharingMode sharingMode;
236 1u, // uint32_t queueFamilyIndexCount;
237 &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices;
240 buffer = createBuffer(vk, vkDevice, &bufferParams);
241 vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs);
243 const deUint32 heapTypeIndex = (deUint32)deCtz32(memReqs.memoryTypeBits);
244 const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex];
245 const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex];
246 const VkDeviceSize maxBufferSize = alignDeviceSize(memoryHeap.size >> 1, memReqs.alignment);
247 const deUint32 shrinkBits = 4; // number of bits to shift when reducing the size with each iteration
249 size = std::min(size, maxBufferSize);
251 while (*memory == DE_NULL)
255 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
256 VkBuffer rawBuffer = DE_NULL;
258 bufferParams.size = size;
259 buffer = Move<VkBuffer>(); // free the previous buffer, if any
260 result = vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer);
262 if (result != VK_SUCCESS)
264 size = alignDeviceSize(size >> shrinkBits, memReqs.alignment);
266 if (size == 0 || bufferParams.size == memReqs.alignment)
267 return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")");
269 continue; // didn't work, try with a smaller buffer
272 buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL));
275 vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs); // get the proper size requirement
277 if (size > memReqs.size)
279 std::ostringstream errorMsg;
280 errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
281 return tcu::TestStatus::fail(errorMsg.str());
284 // Allocate the memory
286 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
287 VkDeviceMemory rawMemory = DE_NULL;
289 const VkMemoryAllocateInfo memAlloc =
291 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType;
292 NULL, // const void* pNext;
293 memReqs.size, // VkDeviceSize allocationSize;
294 heapTypeIndex, // uint32_t memoryTypeIndex;
297 result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory);
299 if (result != VK_SUCCESS)
301 size = alignDeviceSize(size >> shrinkBits, memReqs.alignment);
303 if (size == 0 || memReqs.size == memReqs.alignment)
304 return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory");
306 continue; // didn't work, try with a smaller allocation (and a smaller buffer)
309 memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL));
315 if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0)
317 VkQueue queue = DE_NULL;
319 vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue);
321 const VkSparseMemoryBind sparseMemoryBind =
323 0, // VkDeviceSize resourceOffset;
324 memReqs.size, // VkDeviceSize size;
325 *memory, // VkDeviceMemory memory;
326 0, // VkDeviceSize memoryOffset;
327 0 // VkSparseMemoryBindFlags flags;
330 const VkSparseBufferMemoryBindInfo sparseBufferMemoryBindInfo =
332 *buffer, // VkBuffer buffer;
333 1u, // deUint32 bindCount;
334 &sparseMemoryBind // const VkSparseMemoryBind* pBinds;
337 const VkBindSparseInfo bindSparseInfo =
339 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType;
340 DE_NULL, // const void* pNext;
341 0, // deUint32 waitSemaphoreCount;
342 DE_NULL, // const VkSemaphore* pWaitSemaphores;
343 1u, // deUint32 bufferBindCount;
344 &sparseBufferMemoryBindInfo, // const VkSparseBufferMemoryBindInfo* pBufferBinds;
345 0, // deUint32 imageOpaqueBindCount;
346 DE_NULL, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
347 0, // deUint32 imageBindCount;
348 DE_NULL, // const VkSparseImageMemoryBindInfo* pImageBinds;
349 0, // deUint32 signalSemaphoreCount;
350 DE_NULL, // const VkSemaphore* pSignalSemaphores;
353 const VkFenceCreateInfo fenceParams =
355 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
356 DE_NULL, // const void* pNext;
357 0u // VkFenceCreateFlags flags;
360 const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams));
362 if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
363 return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
365 VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
369 if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS)
370 return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
373 return tcu::TestStatus::pass("Pass");
376 tcu::TestStatus BufferTestInstance::iterate (void)
378 const VkPhysicalDeviceFeatures& physicalDeviceFeatures = getPhysicalDeviceFeatures(getInstanceInterface(), getPhysicalDevice());
380 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding)
381 TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
383 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer)
384 TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
386 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased)
387 TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
389 const VkDeviceSize testSizes[] =
395 ~0ull, // try to exercise a very large buffer too (will be clamped to a sensible size later)
398 for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i)
400 const tcu::TestStatus testStatus = bufferCreateAndAllocTest(testSizes[i]);
402 if (testStatus.getCode() != QP_TEST_RESULT_PASS)
406 return tcu::TestStatus::pass("Pass");
411 tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
413 const VkBufferUsageFlags bufferUsageModes[] =
415 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
416 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
417 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
418 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
419 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
420 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
421 VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
422 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
423 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
426 // \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag.
427 const VkBufferCreateFlags bufferCreateFlags[] =
430 VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
431 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
432 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
433 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
436 de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
438 const deUint32 maximumValueOfBufferUsageFlags = (1u << (DE_LENGTH_OF_ARRAY(bufferUsageModes) - 1)) - 1u;
440 for (deUint32 bufferCreateFlagsNdx = 0u; bufferCreateFlagsNdx < DE_LENGTH_OF_ARRAY(bufferCreateFlags); bufferCreateFlagsNdx++)
441 for (deUint32 combinedBufferUsageFlags = 1u; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++)
443 const BufferCaseParameters testParams =
445 combinedBufferUsageFlags,
446 bufferCreateFlags[bufferCreateFlagsNdx],
447 VK_SHARING_MODE_EXCLUSIVE
449 std::ostringstream testName;
450 std::ostringstream testDescription;
451 testName << "create_buffer_" << combinedBufferUsageFlags << "_" << testParams.flags;
452 testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << testParams.flags;
453 buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams));
456 return buffersTests.release();