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