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,deUint32 excludeIndex)42 deUint32 findQueueFamilyIndex (const InstanceInterface& vki,
43 VkPhysicalDevice dev,
44 VkQueueGlobalPriorityKHR priority,
45 VkQueueFlags includeFlags,
46 VkQueueFlags excludeFlags,
47 deUint32 excludeIndex)
48 {
49 deUint32 queueFamilyPropertyCount = 0;
50 vki.getPhysicalDeviceQueueFamilyProperties2(dev, &queueFamilyPropertyCount, nullptr);
51 DE_ASSERT(queueFamilyPropertyCount);
52
53 std::vector<VkQueueFamilyProperties2> familyProperties2(queueFamilyPropertyCount);
54 std::vector<VkQueueFamilyGlobalPriorityPropertiesKHR> familyPriorityProperties(queueFamilyPropertyCount);
55
56 for (deUint32 familyIdx = 0; familyIdx < queueFamilyPropertyCount; ++familyIdx)
57 {
58 VkQueueFamilyGlobalPriorityPropertiesKHR* pPriorityProps = &familyPriorityProperties[familyIdx];
59 pPriorityProps->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR;
60
61 VkQueueFamilyProperties2* pFamilyProps = &familyProperties2[familyIdx];
62 pFamilyProps->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
63 pFamilyProps->pNext = pPriorityProps;
64 }
65
66 vki.getPhysicalDeviceQueueFamilyProperties2(dev, &queueFamilyPropertyCount, familyProperties2.data());
67
68 deUint32 familyFound = INVALID_UINT32;
69
70 for (deUint32 familyIdx = 0; familyIdx < queueFamilyPropertyCount; ++familyIdx)
71 {
72 if (familyIdx == excludeIndex) continue;
73
74 bool priorityMatches = false;
75 for (uint32_t priorityIdx = 0; !priorityMatches && priorityIdx < familyPriorityProperties[familyIdx].priorityCount; ++priorityIdx)
76 {
77 priorityMatches = (priority == familyPriorityProperties[familyIdx].priorities[priorityIdx]);
78 }
79 if (!priorityMatches) continue;
80
81 const VkQueueFlags queueFlags = familyProperties2[familyIdx].queueFamilyProperties.queueFlags;
82 if ( ((queueFlags & includeFlags) == includeFlags) && ((queueFlags & excludeFlags) == 0) )
83 {
84 familyFound = familyIdx;
85 break;
86 }
87 }
88
89 return familyFound;
90 }
91
92 #define SAVEEXPR(expr, text, file, line) (text=#expr,file=__FILE__,line=__LINE__,expr)
93
SpecialDevice(Context & ctx,VkQueueFlagBits transitionFrom,VkQueueFlagBits transitionTo,VkQueueGlobalPriorityKHR priorityFrom,VkQueueGlobalPriorityKHR priorityTo,bool enableProtected,bool enableSparseBinding)94 SpecialDevice::SpecialDevice (Context& ctx,
95 VkQueueFlagBits transitionFrom,
96 VkQueueFlagBits transitionTo,
97 VkQueueGlobalPriorityKHR priorityFrom,
98 VkQueueGlobalPriorityKHR priorityTo,
99 bool enableProtected,
100 bool enableSparseBinding)
101 : queueFamilyIndexFrom (m_queueFamilyIndexFrom)
102 , queueFamilyIndexTo (m_queueFamilyIndexTo)
103 , handle (m_deviceHandle)
104 , queueFrom (m_queueFrom)
105 , queueTo (m_queueTo)
106 , createResult (m_createResult)
107 , createExpression (m_createExpression)
108 , createFileName (m_createFileName)
109 , createFileLine (m_createFileLine)
110 , m_context (ctx)
111 , m_transitionFrom (transitionFrom)
112 , m_transitionTo (transitionTo)
113 , m_queueFamilyIndexFrom (INVALID_UINT32)
114 , m_queueFamilyIndexTo (INVALID_UINT32)
115 , m_deviceHandle (VK_NULL_HANDLE)
116 , m_queueFrom (VK_NULL_HANDLE)
117 , m_queueTo (VK_NULL_HANDLE)
118 , m_allocator ()
119 , m_createResult (VK_ERROR_UNKNOWN)
120 , m_createExpression (nullptr)
121 , m_createFileName (nullptr)
122 , m_createFileLine (INVALID_UINT32)
123 {
124 const DeviceInterface& vkd = ctx.getDeviceInterface();
125 const InstanceInterface& vki = ctx.getInstanceInterface();
126 const VkInstance instance = ctx.getInstance();
127 const tcu::CommandLine& cmdLine = ctx.getTestContext().getCommandLine();
128 const VkPhysicalDevice phys = chooseDevice(vki, instance, cmdLine);
129 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, phys);
130
131
132 VkQueueFlags flagFrom = transitionFrom;
133 VkQueueFlags flagTo = transitionTo;
134 if (enableProtected)
135 {
136 flagFrom |= VK_QUEUE_PROTECTED_BIT;
137 flagTo |= VK_QUEUE_PROTECTED_BIT;
138 }
139 if (enableSparseBinding)
140 {
141 flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
142 flagTo |= VK_QUEUE_SPARSE_BINDING_BIT;
143 }
144
145 m_queueFamilyIndexFrom = findQueueFamilyIndex(vki, phys, priorityFrom, flagFrom, getColissionFlags(transitionFrom), INVALID_UINT32);
146 m_queueFamilyIndexTo = findQueueFamilyIndex(vki, phys, priorityTo, flagTo, getColissionFlags(transitionTo), m_queueFamilyIndexFrom);
147
148 DE_ASSERT(m_queueFamilyIndexFrom != INVALID_UINT32);
149 DE_ASSERT(m_queueFamilyIndexTo != INVALID_UINT32);
150
151 const float queuePriorities[2] { 1.0f, 0.0f };
152 VkDeviceQueueCreateInfo queueCreateInfos[2];
153 VkDeviceQueueGlobalPriorityCreateInfoKHR priorityCreateInfos[2];
154 {
155 priorityCreateInfos[0].sType = priorityCreateInfos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR;
156 priorityCreateInfos[0].pNext = priorityCreateInfos[1].pNext = nullptr;
157
158 queueCreateInfos[0].sType = queueCreateInfos[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
159 queueCreateInfos[0].flags = queueCreateInfos[1].flags = enableProtected ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0;
160 queueCreateInfos[0].queueCount = queueCreateInfos[1].queueCount = 1;
161
162 priorityCreateInfos[0].globalPriority = priorityFrom;
163 queueCreateInfos[0].pNext = &priorityCreateInfos[0];
164 queueCreateInfos[0].queueFamilyIndex = m_queueFamilyIndexFrom;
165 queueCreateInfos[0].pQueuePriorities = &queuePriorities[0];
166
167 priorityCreateInfos[1].globalPriority = priorityTo;
168 queueCreateInfos[1].pNext = &priorityCreateInfos[1];
169 queueCreateInfos[1].queueFamilyIndex = m_queueFamilyIndexTo;
170 queueCreateInfos[1].pQueuePriorities = &queuePriorities[1];
171 }
172
173 VkPhysicalDeviceProtectedMemoryFeatures memFeatures
174 {
175 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
176 DE_NULL,
177 VK_TRUE
178 };
179 VkPhysicalDeviceFeatures2 devFeatures = ctx.getDeviceFeatures2();
180 if (enableProtected) devFeatures.pNext = &memFeatures;
181
182 const std::vector<const char*>& extensions = ctx.getDeviceCreationExtensions();
183
184 VkDeviceCreateInfo deviceCreateInfo {};
185 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
186 deviceCreateInfo.pNext = &devFeatures;
187 deviceCreateInfo.flags = VkDeviceCreateFlags(0);
188 deviceCreateInfo.queueCreateInfoCount = 2;
189 deviceCreateInfo.pQueueCreateInfos = queueCreateInfos;
190 deviceCreateInfo.pEnabledFeatures = nullptr;
191 deviceCreateInfo.enabledExtensionCount = static_cast<deUint32>(extensions.size());
192 deviceCreateInfo.ppEnabledExtensionNames = de::dataOrNull(extensions);
193 deviceCreateInfo.ppEnabledLayerNames = nullptr;
194 deviceCreateInfo.enabledLayerCount = 0;
195
196 m_createResult = SAVEEXPR(createUncheckedDevice(cmdLine.isValidationEnabled(), vki, phys, &deviceCreateInfo, nullptr, &m_deviceHandle),
197 m_createExpression, m_createFileName, m_createFileLine);
198 if (VK_SUCCESS == m_createResult && VK_NULL_HANDLE != m_deviceHandle)
199 {
200 m_allocator = de::MovePtr<vk::Allocator>(new SimpleAllocator(vkd, m_deviceHandle, memoryProperties));
201
202 if (enableProtected)
203 {
204 VkDeviceQueueInfo2 queueInfo{};
205 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
206 queueInfo.flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
207 queueInfo.queueIndex = 0;
208
209 queueInfo.queueFamilyIndex = m_queueFamilyIndexFrom;
210 vkd.getDeviceQueue2(m_deviceHandle, &queueInfo, &m_queueFrom);
211
212 queueInfo.queueFamilyIndex = m_queueFamilyIndexTo;
213 vkd.getDeviceQueue2(m_deviceHandle, &queueInfo, &m_queueTo);
214 }
215 else
216 {
217 vkd.getDeviceQueue(m_deviceHandle, m_queueFamilyIndexFrom, 0, &m_queueFrom);
218 vkd.getDeviceQueue(m_deviceHandle, m_queueFamilyIndexTo, 0, &m_queueTo);
219 }
220 }
221 }
~SpecialDevice()222 SpecialDevice::~SpecialDevice ()
223 {
224 if (VK_NULL_HANDLE != m_deviceHandle)
225 {
226 m_context.getDeviceInterface().destroyDevice(m_deviceHandle, nullptr);
227 m_createResult = VK_ERROR_UNKNOWN;
228 m_deviceHandle = VK_NULL_HANDLE;
229 }
230 }
getColissionFlags(VkQueueFlags flags)231 VkQueueFlags SpecialDevice::getColissionFlags (VkQueueFlags flags)
232 {
233 if (flags & VK_QUEUE_TRANSFER_BIT)
234 return (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
235
236 if (flags & VK_QUEUE_COMPUTE_BIT)
237 return VK_QUEUE_GRAPHICS_BIT;
238
239 if (flags & VK_QUEUE_GRAPHICS_BIT)
240 return 0;
241
242 DE_ASSERT(false);
243 return 0;
244 }
245
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)246 BufferWithMemory::BufferWithMemory (const vk::InstanceInterface& vki,
247 const DeviceInterface& vkd,
248 const vk::VkPhysicalDevice phys,
249 const VkDevice device,
250 Allocator& allocator,
251 const VkBufferCreateInfo& bufferCreateInfo,
252 const MemoryRequirement memoryRequirement,
253 const VkQueue sparseQueue)
254 : m_amISparse ((bufferCreateInfo.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0)
255 , m_buffer (createBuffer(vkd, device, &bufferCreateInfo))
256 , m_requirements (getBufferMemoryRequirements(vkd, device, *m_buffer))
257 , m_allocations ()
258 , m_size (bufferCreateInfo.size)
259 {
260 if (m_amISparse)
261 {
262 DE_ASSERT(sparseQueue != VkQueue(0));
263 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, phys);
264 const deUint32 memoryTypeIndex = selectMatchingMemoryType(memoryProperties, m_requirements.memoryTypeBits, memoryRequirement);
265 const VkDeviceSize lastChunkSize = m_requirements.size % m_requirements.alignment;
266 const uint32_t chunkCount = static_cast<uint32_t>(m_requirements.size / m_requirements.alignment + (lastChunkSize ? 1 : 0));
267 Move<VkFence> fence = createFence(vkd, device);
268
269 std::vector<VkSparseMemoryBind> bindings(chunkCount);
270
271 for (uint32_t i = 0; i < chunkCount; ++i)
272 {
273 VkMemoryAllocateInfo allocInfo{};
274 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
275 allocInfo.pNext = nullptr;
276 allocInfo.allocationSize = m_requirements.alignment;
277 allocInfo.memoryTypeIndex = memoryTypeIndex;
278
279 de::MovePtr<Allocation> allocation = allocator.allocate(allocInfo, m_requirements.alignment);
280
281 VkSparseMemoryBind& binding = bindings[i];
282 binding.resourceOffset = m_requirements.alignment * i;
283 binding.size = m_requirements.alignment;
284 binding.memory = allocation->getMemory();
285 binding.memoryOffset = allocation->getOffset();
286 binding.flags = 0;
287
288 m_allocations.emplace_back(allocation.release());
289 }
290
291 VkSparseBufferMemoryBindInfo bindInfo{};
292 bindInfo.buffer = *m_buffer;
293 bindInfo.bindCount = chunkCount;
294 bindInfo.pBinds = de::dataOrNull(bindings);
295
296 VkBindSparseInfo sparseInfo{};
297 sparseInfo.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
298 sparseInfo.pNext = nullptr;
299 sparseInfo.waitSemaphoreCount = 0;
300 sparseInfo.pWaitSemaphores = nullptr;
301 sparseInfo.bufferBindCount = 1;
302 sparseInfo.pBufferBinds = &bindInfo;
303 sparseInfo.imageOpaqueBindCount = 0;
304 sparseInfo.pImageOpaqueBinds = nullptr;
305 sparseInfo.imageBindCount = 0;
306 sparseInfo.pImageBinds = nullptr;
307 sparseInfo.signalSemaphoreCount = 0;
308 sparseInfo.pSignalSemaphores = nullptr;
309
310 VK_CHECK(vkd.queueBindSparse(sparseQueue, 1, &sparseInfo, *fence));
311 VK_CHECK(vkd.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
312 }
313 else
314 {
315 de::MovePtr<Allocation> allocation = allocator.allocate(m_requirements, memoryRequirement);
316 VK_CHECK(vkd.bindBufferMemory(device, *m_buffer, allocation->getMemory(), allocation->getOffset()));
317 m_allocations.emplace_back(allocation.release());
318 }
319 }
320
assertIAmSparse() const321 void BufferWithMemory::assertIAmSparse () const
322 {
323 if (m_amISparse) TCU_THROW(NotSupportedError, "Host access pointer not implemented for sparse buffers");
324 }
325
getHostPtr(void) const326 void* BufferWithMemory::getHostPtr (void) const
327 {
328 assertIAmSparse();
329 return m_allocations[0]->getHostPtr();
330 }
331
invalidateAlloc(const DeviceInterface & vk,const VkDevice device) const332 void BufferWithMemory::invalidateAlloc (const DeviceInterface& vk, const VkDevice device) const
333 {
334 assertIAmSparse();
335 ::vk::invalidateAlloc(vk, device, *m_allocations[0]);
336 }
337
flushAlloc(const DeviceInterface & vk,const VkDevice device) const338 void BufferWithMemory::flushAlloc (const DeviceInterface& vk, const VkDevice device) const
339 {
340 assertIAmSparse();
341 ::vk::flushAlloc(vk, device, *m_allocations[0]);
342 }
343
ImageWithMemory(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice phys,const VkDevice device,Allocator & allocator,const VkImageCreateInfo & imageCreateInfo,const VkQueue sparseQueue,const MemoryRequirement memoryRequirement)344 ImageWithMemory::ImageWithMemory (const InstanceInterface& vki,
345 const DeviceInterface& vkd,
346 const VkPhysicalDevice phys,
347 const VkDevice device,
348 Allocator& allocator,
349 const VkImageCreateInfo& imageCreateInfo,
350 const VkQueue sparseQueue,
351 const MemoryRequirement memoryRequirement)
352 : m_image(((imageCreateInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != 0)
353 ? (new image::SparseImage(vkd, device, phys, vki, imageCreateInfo, sparseQueue, allocator, mapVkFormat(imageCreateInfo.format)))
354 : (new image::Image(vkd, device, allocator, imageCreateInfo, memoryRequirement)))
355 {
356 }
357
358 } // synchronization
359 } // vkt
360