1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file vktGlobalPriorityQueueUtils.cpp
21 * \brief Global Priority Queue Utils
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktGlobalPriorityQueueUtils.hpp"
25 #include "vkImageUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkTypeUtil.hpp"
28 #include "vkDeviceUtil.hpp"
29 #include "vktCustomInstancesDevices.hpp"
30 #include "vktTestCase.hpp"
31 #include "deStringUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include <vector>
34
35 using namespace vk;
36
37 namespace vkt
38 {
39 namespace synchronization
40 {
41
findQueueFamilyIndex(const InstanceInterface & vki,VkPhysicalDevice dev,VkQueueGlobalPriorityKHR priority,VkQueueFlags includeFlags,VkQueueFlags excludeFlags,uint32_t excludeIndex)42 uint32_t findQueueFamilyIndex(const InstanceInterface &vki, VkPhysicalDevice dev, VkQueueGlobalPriorityKHR priority,
43 VkQueueFlags includeFlags, VkQueueFlags excludeFlags, uint32_t excludeIndex)
44 {
45 uint32_t queueFamilyPropertyCount = 0;
46 vki.getPhysicalDeviceQueueFamilyProperties2(dev, &queueFamilyPropertyCount, nullptr);
47 DE_ASSERT(queueFamilyPropertyCount);
48
49 std::vector<VkQueueFamilyProperties2> familyProperties2(queueFamilyPropertyCount);
50 std::vector<VkQueueFamilyGlobalPriorityPropertiesKHR> familyPriorityProperties(queueFamilyPropertyCount);
51
52 for (uint32_t familyIdx = 0; familyIdx < queueFamilyPropertyCount; ++familyIdx)
53 {
54 VkQueueFamilyGlobalPriorityPropertiesKHR *pPriorityProps = &familyPriorityProperties[familyIdx];
55 pPriorityProps->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR;
56
57 VkQueueFamilyProperties2 *pFamilyProps = &familyProperties2[familyIdx];
58 pFamilyProps->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
59 pFamilyProps->pNext = pPriorityProps;
60 }
61
62 vki.getPhysicalDeviceQueueFamilyProperties2(dev, &queueFamilyPropertyCount, familyProperties2.data());
63
64 uint32_t familyFound = INVALID_UINT32;
65
66 for (uint32_t familyIdx = 0; familyIdx < queueFamilyPropertyCount; ++familyIdx)
67 {
68 if (familyIdx == excludeIndex)
69 continue;
70
71 bool priorityMatches = false;
72 for (uint32_t priorityIdx = 0;
73 !priorityMatches && priorityIdx < familyPriorityProperties[familyIdx].priorityCount; ++priorityIdx)
74 {
75 priorityMatches = (priority == familyPriorityProperties[familyIdx].priorities[priorityIdx]);
76 }
77 if (!priorityMatches)
78 continue;
79
80 const VkQueueFlags queueFlags = familyProperties2[familyIdx].queueFamilyProperties.queueFlags;
81 if (((queueFlags & includeFlags) == includeFlags) && ((queueFlags & excludeFlags) == 0))
82 {
83 familyFound = familyIdx;
84 break;
85 }
86 }
87
88 return familyFound;
89 }
90
91 #define SAVEEXPR(expr, text, file, line) (text = #expr, file = __FILE__, line = __LINE__, expr)
92
SpecialDevice(Context & ctx,VkQueueFlagBits transitionFrom,VkQueueFlagBits transitionTo,VkQueueGlobalPriorityKHR priorityFrom,VkQueueGlobalPriorityKHR priorityTo,bool enableProtected,bool enableSparseBinding)93 SpecialDevice::SpecialDevice(Context &ctx, VkQueueFlagBits transitionFrom, VkQueueFlagBits transitionTo,
94 VkQueueGlobalPriorityKHR priorityFrom, VkQueueGlobalPriorityKHR priorityTo,
95 bool enableProtected, bool enableSparseBinding)
96 : queueFamilyIndexFrom(m_queueFamilyIndexFrom)
97 , queueFamilyIndexTo(m_queueFamilyIndexTo)
98 , handle(m_deviceHandle)
99 , queueFrom(m_queueFrom)
100 , queueTo(m_queueTo)
101 , createResult(m_createResult)
102 , createExpression(m_createExpression)
103 , createFileName(m_createFileName)
104 , createFileLine(m_createFileLine)
105 , m_context(ctx)
106 , m_transitionFrom(transitionFrom)
107 , m_transitionTo(transitionTo)
108 , m_queueFamilyIndexFrom(INVALID_UINT32)
109 , m_queueFamilyIndexTo(INVALID_UINT32)
110 , m_deviceHandle(VK_NULL_HANDLE)
111 , m_queueFrom(VK_NULL_HANDLE)
112 , m_queueTo(VK_NULL_HANDLE)
113 , m_allocator()
114 , m_createResult(VK_ERROR_UNKNOWN)
115 , m_createExpression(nullptr)
116 , m_createFileName(nullptr)
117 , m_createFileLine(INVALID_UINT32)
118 {
119 const DeviceInterface &vkd = ctx.getDeviceInterface();
120 const InstanceInterface &vki = ctx.getInstanceInterface();
121 const VkInstance instance = ctx.getInstance();
122 const tcu::CommandLine &cmdLine = ctx.getTestContext().getCommandLine();
123 const VkPhysicalDevice phys = chooseDevice(vki, instance, cmdLine);
124 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, phys);
125
126 VkQueueFlags flagFrom = transitionFrom;
127 VkQueueFlags flagTo = transitionTo;
128 if (enableProtected)
129 {
130 flagFrom |= VK_QUEUE_PROTECTED_BIT;
131 flagTo |= VK_QUEUE_PROTECTED_BIT;
132 }
133 if (enableSparseBinding)
134 {
135 flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
136 flagTo |= VK_QUEUE_SPARSE_BINDING_BIT;
137 }
138
139 m_queueFamilyIndexFrom =
140 findQueueFamilyIndex(vki, phys, priorityFrom, flagFrom, getColissionFlags(transitionFrom), INVALID_UINT32);
141 m_queueFamilyIndexTo =
142 findQueueFamilyIndex(vki, phys, priorityTo, flagTo, getColissionFlags(transitionTo), m_queueFamilyIndexFrom);
143
144 DE_ASSERT(m_queueFamilyIndexFrom != INVALID_UINT32);
145 DE_ASSERT(m_queueFamilyIndexTo != INVALID_UINT32);
146
147 const float queuePriorities[2]{1.0f, 0.0f};
148 VkDeviceQueueCreateInfo queueCreateInfos[2];
149 VkDeviceQueueGlobalPriorityCreateInfoKHR priorityCreateInfos[2];
150 {
151 priorityCreateInfos[0].sType = priorityCreateInfos[1].sType =
152 VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR;
153 priorityCreateInfos[0].pNext = priorityCreateInfos[1].pNext = nullptr;
154
155 queueCreateInfos[0].sType = queueCreateInfos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
156 queueCreateInfos[0].flags = queueCreateInfos[1].flags =
157 enableProtected ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0;
158 queueCreateInfos[0].queueCount = queueCreateInfos[1].queueCount = 1;
159
160 priorityCreateInfos[0].globalPriority = priorityFrom;
161 queueCreateInfos[0].pNext = &priorityCreateInfos[0];
162 queueCreateInfos[0].queueFamilyIndex = m_queueFamilyIndexFrom;
163 queueCreateInfos[0].pQueuePriorities = &queuePriorities[0];
164
165 priorityCreateInfos[1].globalPriority = priorityTo;
166 queueCreateInfos[1].pNext = &priorityCreateInfos[1];
167 queueCreateInfos[1].queueFamilyIndex = m_queueFamilyIndexTo;
168 queueCreateInfos[1].pQueuePriorities = &queuePriorities[1];
169 }
170
171 VkPhysicalDeviceProtectedMemoryFeatures memFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
172 DE_NULL, VK_TRUE};
173 VkPhysicalDeviceFeatures2 devFeatures = ctx.getDeviceFeatures2();
174 if (enableProtected)
175 devFeatures.pNext = &memFeatures;
176
177 const std::vector<const char *> &extensions = ctx.getDeviceCreationExtensions();
178
179 VkDeviceCreateInfo deviceCreateInfo{};
180 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
181 deviceCreateInfo.pNext = &devFeatures;
182 deviceCreateInfo.flags = VkDeviceCreateFlags(0);
183 deviceCreateInfo.queueCreateInfoCount = 2;
184 deviceCreateInfo.pQueueCreateInfos = queueCreateInfos;
185 deviceCreateInfo.pEnabledFeatures = nullptr;
186 deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
187 deviceCreateInfo.ppEnabledExtensionNames = de::dataOrNull(extensions);
188 deviceCreateInfo.ppEnabledLayerNames = nullptr;
189 deviceCreateInfo.enabledLayerCount = 0;
190
191 m_createResult = SAVEEXPR(
192 createUncheckedDevice(cmdLine.isValidationEnabled(), vki, phys, &deviceCreateInfo, nullptr, &m_deviceHandle),
193 m_createExpression, m_createFileName, m_createFileLine);
194 if (VK_SUCCESS == m_createResult && VK_NULL_HANDLE != m_deviceHandle)
195 {
196 m_allocator = de::MovePtr<vk::Allocator>(new SimpleAllocator(vkd, m_deviceHandle, memoryProperties));
197
198 if (enableProtected)
199 {
200 VkDeviceQueueInfo2 queueInfo{};
201 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
202 queueInfo.flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
203 queueInfo.queueIndex = 0;
204
205 queueInfo.queueFamilyIndex = m_queueFamilyIndexFrom;
206 vkd.getDeviceQueue2(m_deviceHandle, &queueInfo, &m_queueFrom);
207
208 queueInfo.queueFamilyIndex = m_queueFamilyIndexTo;
209 vkd.getDeviceQueue2(m_deviceHandle, &queueInfo, &m_queueTo);
210 }
211 else
212 {
213 vkd.getDeviceQueue(m_deviceHandle, m_queueFamilyIndexFrom, 0, &m_queueFrom);
214 vkd.getDeviceQueue(m_deviceHandle, m_queueFamilyIndexTo, 0, &m_queueTo);
215 }
216 }
217 }
~SpecialDevice()218 SpecialDevice::~SpecialDevice()
219 {
220 if (VK_NULL_HANDLE != m_deviceHandle)
221 {
222 m_context.getDeviceInterface().destroyDevice(m_deviceHandle, nullptr);
223 m_createResult = VK_ERROR_UNKNOWN;
224 m_deviceHandle = VK_NULL_HANDLE;
225 }
226 }
getColissionFlags(VkQueueFlags flags)227 VkQueueFlags SpecialDevice::getColissionFlags(VkQueueFlags flags)
228 {
229 if (flags & VK_QUEUE_TRANSFER_BIT)
230 return (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
231
232 if (flags & VK_QUEUE_COMPUTE_BIT)
233 return VK_QUEUE_GRAPHICS_BIT;
234
235 if (flags & VK_QUEUE_GRAPHICS_BIT)
236 return 0;
237
238 DE_ASSERT(false);
239 return 0;
240 }
241
BufferWithMemory(const vk::InstanceInterface & vki,const DeviceInterface & vkd,const vk::VkPhysicalDevice phys,const VkDevice device,Allocator & allocator,const VkBufferCreateInfo & bufferCreateInfo,const MemoryRequirement memoryRequirement,const VkQueue sparseQueue)242 BufferWithMemory::BufferWithMemory(const vk::InstanceInterface &vki, const DeviceInterface &vkd,
243 const vk::VkPhysicalDevice phys, const VkDevice device, Allocator &allocator,
244 const VkBufferCreateInfo &bufferCreateInfo,
245 const MemoryRequirement memoryRequirement, const VkQueue sparseQueue)
246 : m_amISparse((bufferCreateInfo.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
247 , m_buffer(createBuffer(vkd, device, &bufferCreateInfo))
248 , m_requirements(getBufferMemoryRequirements(vkd, device, *m_buffer))
249 , m_allocations()
250 , m_size(bufferCreateInfo.size)
251 {
252 if (m_amISparse)
253 {
254 DE_ASSERT(sparseQueue != VkQueue(0));
255 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, phys);
256 const uint32_t memoryTypeIndex =
257 selectMatchingMemoryType(memoryProperties, m_requirements.memoryTypeBits, memoryRequirement);
258 const VkDeviceSize lastChunkSize = m_requirements.size % m_requirements.alignment;
259 const uint32_t chunkCount =
260 static_cast<uint32_t>(m_requirements.size / m_requirements.alignment + (lastChunkSize ? 1 : 0));
261 Move<VkFence> fence = createFence(vkd, device);
262
263 std::vector<VkSparseMemoryBind> bindings(chunkCount);
264
265 for (uint32_t i = 0; i < chunkCount; ++i)
266 {
267 VkMemoryAllocateInfo allocInfo{};
268 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
269 allocInfo.pNext = nullptr;
270 allocInfo.allocationSize = m_requirements.alignment;
271 allocInfo.memoryTypeIndex = memoryTypeIndex;
272
273 de::MovePtr<Allocation> allocation = allocator.allocate(allocInfo, m_requirements.alignment);
274
275 VkSparseMemoryBind &binding = bindings[i];
276 binding.resourceOffset = m_requirements.alignment * i;
277 binding.size = m_requirements.alignment;
278 binding.memory = allocation->getMemory();
279 binding.memoryOffset = allocation->getOffset();
280 binding.flags = 0;
281
282 m_allocations.emplace_back(allocation.release());
283 }
284
285 VkSparseBufferMemoryBindInfo bindInfo{};
286 bindInfo.buffer = *m_buffer;
287 bindInfo.bindCount = chunkCount;
288 bindInfo.pBinds = de::dataOrNull(bindings);
289
290 VkBindSparseInfo sparseInfo{};
291 sparseInfo.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
292 sparseInfo.pNext = nullptr;
293 sparseInfo.waitSemaphoreCount = 0;
294 sparseInfo.pWaitSemaphores = nullptr;
295 sparseInfo.bufferBindCount = 1;
296 sparseInfo.pBufferBinds = &bindInfo;
297 sparseInfo.imageOpaqueBindCount = 0;
298 sparseInfo.pImageOpaqueBinds = nullptr;
299 sparseInfo.imageBindCount = 0;
300 sparseInfo.pImageBinds = nullptr;
301 sparseInfo.signalSemaphoreCount = 0;
302 sparseInfo.pSignalSemaphores = nullptr;
303
304 VK_CHECK(vkd.queueBindSparse(sparseQueue, 1, &sparseInfo, *fence));
305 VK_CHECK(vkd.waitForFences(device, 1u, &fence.get(), true, ~0ull));
306 }
307 else
308 {
309 de::MovePtr<Allocation> allocation = allocator.allocate(m_requirements, memoryRequirement);
310 VK_CHECK(vkd.bindBufferMemory(device, *m_buffer, allocation->getMemory(), allocation->getOffset()));
311 m_allocations.emplace_back(allocation.release());
312 }
313 }
314
assertIAmSparse() const315 void BufferWithMemory::assertIAmSparse() const
316 {
317 if (m_amISparse)
318 TCU_THROW(NotSupportedError, "Host access pointer not implemented for sparse buffers");
319 }
320
getHostPtr(void) const321 void *BufferWithMemory::getHostPtr(void) const
322 {
323 assertIAmSparse();
324 return m_allocations[0]->getHostPtr();
325 }
326
invalidateAlloc(const DeviceInterface & vk,const VkDevice device) const327 void BufferWithMemory::invalidateAlloc(const DeviceInterface &vk, const VkDevice device) const
328 {
329 assertIAmSparse();
330 ::vk::invalidateAlloc(vk, device, *m_allocations[0]);
331 }
332
flushAlloc(const DeviceInterface & vk,const VkDevice device) const333 void BufferWithMemory::flushAlloc(const DeviceInterface &vk, const VkDevice device) const
334 {
335 assertIAmSparse();
336 ::vk::flushAlloc(vk, device, *m_allocations[0]);
337 }
338
ImageWithMemory(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice phys,const VkDevice device,Allocator & allocator,const VkImageCreateInfo & imageCreateInfo,const VkQueue sparseQueue,const MemoryRequirement memoryRequirement)339 ImageWithMemory::ImageWithMemory(const InstanceInterface &vki, const DeviceInterface &vkd, const VkPhysicalDevice phys,
340 const VkDevice device, Allocator &allocator, const VkImageCreateInfo &imageCreateInfo,
341 const VkQueue sparseQueue, const MemoryRequirement memoryRequirement)
342 : m_image(((imageCreateInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != 0) ?
343 (new image::SparseImage(vkd, device, phys, vki, imageCreateInfo, sparseQueue, allocator,
344 mapVkFormat(imageCreateInfo.format))) :
345 (new image::Image(vkd, device, allocator, imageCreateInfo, memoryRequirement)))
346 {
347 }
348
349 } // namespace synchronization
350 } // namespace vkt
351