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"
47 static const deUint32 MAX_BUFFER_SIZE_DIVISOR = 16;
49 struct BufferCaseParameters
51 VkBufferUsageFlags usage;
52 VkBufferCreateFlags flags;
53 VkSharingMode sharingMode;
56 class BufferTestInstance : public TestInstance
59 BufferTestInstance (Context& ctx,
60 BufferCaseParameters testCase)
62 , m_testCase (testCase)
63 , m_sparseContext (createSparseContext())
65 virtual tcu::TestStatus iterate (void);
66 tcu::TestStatus bufferCreateAndAllocTest (VkDeviceSize size);
69 BufferCaseParameters m_testCase;
72 // Custom context for sparse cases
75 SparseContext (Move<VkDevice>& device, const deUint32 queueFamilyIndex, const InstanceInterface& interface)
77 , m_queueFamilyIndex (queueFamilyIndex)
78 , m_deviceInterface (interface, *m_device)
81 Unique<VkDevice> m_device;
82 const deUint32 m_queueFamilyIndex;
83 DeviceDriver m_deviceInterface;
86 de::UniquePtr<SparseContext> m_sparseContext;
88 // Wrapper functions around m_context calls to support sparse cases.
89 VkPhysicalDevice getPhysicalDevice (void) const
91 // Same in sparse and regular case
92 return m_context.getPhysicalDevice();
95 VkDevice getDevice (void) const
98 return *(m_sparseContext->m_device);
100 return m_context.getDevice();
103 const InstanceInterface& getInstanceInterface (void) const
105 // Same in sparse and regular case
106 return m_context.getInstanceInterface();
109 const DeviceInterface& getDeviceInterface (void) const
112 return m_sparseContext->m_deviceInterface;
114 return m_context.getDeviceInterface();
117 deUint32 getUniversalQueueFamilyIndex (void) const
120 return m_sparseContext->m_queueFamilyIndex;
122 return m_context.getUniversalQueueFamilyIndex();
125 static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps)
127 const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice);
129 for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
131 if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps)
132 return (deUint32)queueNdx;
135 TCU_THROW(NotSupportedError, "No matching queue found");
138 // Create the sparseContext
139 SparseContext* createSparseContext (void) const
141 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
142 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
143 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
145 const InstanceInterface& vk = getInstanceInterface();
146 const VkPhysicalDevice physicalDevice = getPhysicalDevice();
147 const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice);
149 const deUint32 queueIndex = findQueueFamilyIndexWithCaps(vk, physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT);
151 VkDeviceQueueCreateInfo queueInfo;
152 VkDeviceCreateInfo deviceInfo;
153 const float queuePriority = 1.0f;
155 deMemset(&queueInfo, 0, sizeof(queueInfo));
156 deMemset(&deviceInfo, 0, sizeof(deviceInfo));
158 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
159 queueInfo.pNext = DE_NULL;
160 queueInfo.flags = (VkDeviceQueueCreateFlags)0u;
161 queueInfo.queueFamilyIndex = queueIndex;
162 queueInfo.queueCount = 1u;
163 queueInfo.pQueuePriorities = &queuePriority;
165 deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
166 deviceInfo.pNext = DE_NULL;
167 deviceInfo.queueCreateInfoCount = 1u;
168 deviceInfo.pQueueCreateInfos = &queueInfo;
169 deviceInfo.enabledExtensionCount = 0u;
170 deviceInfo.ppEnabledExtensionNames = DE_NULL;
171 deviceInfo.enabledLayerCount = 0u;
172 deviceInfo.ppEnabledLayerNames = DE_NULL;
173 deviceInfo.pEnabledFeatures = &deviceFeatures;
175 Move<VkDevice> device = createDevice(vk, physicalDevice, &deviceInfo);
177 return new SparseContext(device, queueIndex, vk);
184 class BuffersTestCase : public TestCase
187 BuffersTestCase (tcu::TestContext& testCtx,
188 const std::string& name,
189 const std::string& description,
190 BufferCaseParameters testCase)
191 : TestCase(testCtx, name, description)
192 , m_testCase(testCase)
195 virtual ~BuffersTestCase (void) {}
196 virtual TestInstance* createInstance (Context& ctx) const
198 tcu::TestLog& log = m_testCtx.getLog();
199 log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
200 return new BufferTestInstance(ctx, m_testCase);
204 BufferCaseParameters m_testCase;
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 Move<VkBuffer> testBuffer;
216 VkMemoryRequirements memReqs;
217 Move<VkDeviceMemory> memory;
218 const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex();
219 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
223 VkBufferCreateInfo bufferParams =
225 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
230 m_testCase.sharingMode,
231 1u, // deUint32 queueFamilyCount;
237 testBuffer = createBuffer(vk, vkDevice, &bufferParams);
239 catch (const vk::Error& error)
241 return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
244 vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
246 const deUint32 heapTypeIndex = (deUint32)deCtz32(memReqs.memoryTypeBits);
247 const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex];
248 const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex];
249 const VkDeviceSize maxBufferSize = memoryHeap.size / MAX_BUFFER_SIZE_DIVISOR;
250 // If the requested size is too large, clamp it based on the selected heap size
251 if (size > maxBufferSize)
253 size = maxBufferSize;
254 bufferParams.size = size;
257 // allocate a new buffer with the adjusted size, the old one will be destroyed by the smart pointer
258 testBuffer = createBuffer(vk, vkDevice, &bufferParams);
260 catch (const vk::Error& error)
262 return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
264 vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
267 if (size > memReqs.size)
269 std::ostringstream errorMsg;
270 errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
271 return tcu::TestStatus::fail(errorMsg.str());
275 // Allocate and bind memory
277 const VkMemoryAllocateInfo memAlloc =
279 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
282 (deUint32)deCtz32(memReqs.memoryTypeBits) // deUint32 memoryTypeIndex
287 memory = allocateMemory(vk, vkDevice, &memAlloc, (const VkAllocationCallbacks*)DE_NULL);
289 catch (const vk::Error& error)
291 return tcu::TestStatus::fail("Alloc memory failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
294 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
295 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
296 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
300 vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue);
302 const VkSparseMemoryBind sparseMemoryBind =
304 0, // VkDeviceSize resourceOffset;
305 memReqs.size, // VkDeviceSize size;
306 *memory, // VkDeviceMemory memory;
307 0, // VkDeviceSize memoryOffset;
308 0 // VkSparseMemoryBindFlags flags;
311 const VkSparseBufferMemoryBindInfo sparseBufferMemoryBindInfo =
313 *testBuffer, // VkBuffer buffer;
314 1u, // deUint32 bindCount;
315 &sparseMemoryBind // const VkSparseMemoryBind* pBinds;
318 const VkBindSparseInfo bindSparseInfo =
320 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType;
321 DE_NULL, // const void* pNext;
322 0, // deUint32 waitSemaphoreCount;
323 DE_NULL, // const VkSemaphore* pWaitSemaphores;
324 1u, // deUint32 bufferBindCount;
325 &sparseBufferMemoryBindInfo, // const VkSparseBufferMemoryBindInfo* pBufferBinds;
326 0, // deUint32 imageOpaqueBindCount;
327 DE_NULL, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
328 0, // deUint32 imageBindCount;
329 DE_NULL, // const VkSparseImageMemoryBindInfo* pImageBinds;
330 0, // deUint32 signalSemaphoreCount;
331 DE_NULL, // const VkSemaphore* pSignalSemaphores;
334 const VkFenceCreateInfo fenceParams =
336 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
337 DE_NULL, // const void* pNext;
338 0u // VkFenceCreateFlags flags;
341 const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams));
343 VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
344 if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
345 return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
347 VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
349 if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
350 return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
353 return tcu::TestStatus::pass("Buffer test");
356 tcu::TestStatus BufferTestInstance::iterate (void)
358 const VkPhysicalDeviceFeatures& physicalDeviceFeatures = getPhysicalDeviceFeatures(getInstanceInterface(), getPhysicalDevice());
360 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding)
361 TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
363 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer)
364 TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
366 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased)
367 TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
369 const VkDeviceSize testSizes[] =
376 tcu::TestStatus testStatus = tcu::TestStatus::pass("Buffer test");
378 for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); i++)
380 if ((testStatus = bufferCreateAndAllocTest(testSizes[i])).getCode() != QP_TEST_RESULT_PASS)
384 if (m_testCase.usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT))
386 const VkPhysicalDevice vkPhysicalDevice = getPhysicalDevice();
387 const InstanceInterface& vkInstance = getInstanceInterface();
388 VkPhysicalDeviceProperties props;
390 vkInstance.getPhysicalDeviceProperties(vkPhysicalDevice, &props);
391 testStatus = bufferCreateAndAllocTest((VkDeviceSize) props.limits.maxTexelBufferElements);
399 tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
401 const VkBufferUsageFlags bufferUsageModes[] =
403 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
404 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
405 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
406 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
407 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
408 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
409 VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
410 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
411 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
414 const VkBufferCreateFlags bufferCreateFlags[] =
416 VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
417 VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
418 VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
421 de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
423 deUint32 numberOfBufferUsageFlags = DE_LENGTH_OF_ARRAY(bufferUsageModes);
424 deUint32 numberOfBufferCreateFlags = DE_LENGTH_OF_ARRAY(bufferCreateFlags);
425 deUint32 maximumValueOfBufferUsageFlags = (1 << (numberOfBufferUsageFlags - 1)) - 1;
426 deUint32 maximumValueOfBufferCreateFlags = (1 << (numberOfBufferCreateFlags)) - 1;
428 for (deUint32 combinedBufferCreateFlags = 0; combinedBufferCreateFlags <= maximumValueOfBufferCreateFlags; combinedBufferCreateFlags++)
430 for (deUint32 combinedBufferUsageFlags = 1; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++)
432 if (combinedBufferCreateFlags == VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)
434 // spec says: If flags contains VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, it must also contain at least one of
435 // VK_BUFFER_CREATE_SPARSE_BINDING_BIT or VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT
438 BufferCaseParameters testParams =
440 combinedBufferUsageFlags,
441 combinedBufferCreateFlags,
442 VK_SHARING_MODE_EXCLUSIVE
444 std::ostringstream testName;
445 std::ostringstream testDescription;
446 testName << "create_buffer_" << combinedBufferUsageFlags << "_" << combinedBufferCreateFlags;
447 testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << combinedBufferCreateFlags;
448 buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams));
452 return buffersTests.release();