1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 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  vktSparseResourcesBase.cpp
21  * \brief Sparse Resources Base Instance
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSparseResourcesBase.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktCustomInstancesDevices.hpp"
27 #include "vkMemUtil.hpp"
28 #include "vkRefUtil.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkDeviceUtil.hpp"
32 
33 using namespace vk;
34 
35 namespace vkt
36 {
37 namespace sparse
38 {
39 namespace
40 {
41 
42 struct QueueFamilyQueuesCount
43 {
QueueFamilyQueuesCountvkt::sparse::__anona9b242450111::QueueFamilyQueuesCount44     QueueFamilyQueuesCount() : queueCount(0u)
45     {
46     }
47 
48     uint32_t queueCount;
49 };
50 
findMatchingQueueFamilyIndex(const std::vector<VkQueueFamilyProperties> & queueFamilyProperties,const VkQueueFlags queueFlags,const uint32_t startIndex)51 uint32_t findMatchingQueueFamilyIndex(const std::vector<VkQueueFamilyProperties> &queueFamilyProperties,
52                                       const VkQueueFlags queueFlags, const uint32_t startIndex)
53 {
54     for (uint32_t queueNdx = startIndex; queueNdx < queueFamilyProperties.size(); ++queueNdx)
55     {
56         if ((queueFamilyProperties[queueNdx].queueFlags & queueFlags) == queueFlags)
57             return queueNdx;
58     }
59 
60     return NO_MATCH_FOUND;
61 }
62 
63 } // namespace
64 
createDeviceSupportingQueues(const QueueRequirementsVec & queueRequirements,bool requireShaderImageAtomicInt64Features,bool requireMaintenance5)65 void SparseResourcesBaseInstance::createDeviceSupportingQueues(const QueueRequirementsVec &queueRequirements,
66                                                                bool requireShaderImageAtomicInt64Features,
67                                                                bool requireMaintenance5)
68 {
69     typedef std::map<VkQueueFlags, std::vector<Queue>> QueuesMap;
70     typedef std::map<uint32_t, QueueFamilyQueuesCount> SelectedQueuesMap;
71     typedef std::map<uint32_t, std::vector<float>> QueuePrioritiesMap;
72 
73     std::vector<VkPhysicalDeviceGroupProperties> devGroupProperties;
74     std::vector<const char *> deviceExtensions;
75     VkDeviceGroupDeviceCreateInfo deviceGroupInfo = {
76         VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, //stype
77         DE_NULL,                                           //pNext
78         0,                                                 //physicalDeviceCount
79         DE_NULL                                            //physicalDevices
80     };
81     m_physicalDevices.push_back(m_context.getPhysicalDevice());
82 
83     // If requested, create an intance with device groups
84     if (m_useDeviceGroups)
85     {
86         const std::vector<std::string> requiredExtensions{"VK_KHR_device_group_creation",
87                                                           "VK_KHR_get_physical_device_properties2"};
88         m_deviceGroupInstance = createCustomInstanceWithExtensions(m_context, requiredExtensions);
89         devGroupProperties    = enumeratePhysicalDeviceGroups(m_context.getInstanceInterface(), m_deviceGroupInstance);
90         m_numPhysicalDevices  = devGroupProperties[m_deviceGroupIdx].physicalDeviceCount;
91 
92         m_physicalDevices.clear();
93         for (size_t physDeviceID = 0; physDeviceID < m_numPhysicalDevices; physDeviceID++)
94         {
95             m_physicalDevices.push_back(devGroupProperties[m_deviceGroupIdx].physicalDevices[physDeviceID]);
96         }
97         if (m_numPhysicalDevices < 2)
98             TCU_THROW(NotSupportedError, "Sparse binding device group tests not supported with 1 physical device");
99 
100         deviceGroupInfo.physicalDeviceCount = devGroupProperties[m_deviceGroupIdx].physicalDeviceCount;
101         deviceGroupInfo.pPhysicalDevices    = devGroupProperties[m_deviceGroupIdx].physicalDevices;
102 
103         if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_device_group"))
104             deviceExtensions.push_back("VK_KHR_device_group");
105     }
106     else
107     {
108         m_context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
109     }
110 
111     const VkInstance &instance(m_useDeviceGroups ? m_deviceGroupInstance : m_context.getInstance());
112     InstanceDriver instanceDriver(m_context.getPlatformInterface(), instance);
113     const VkPhysicalDevice physicalDevice = getPhysicalDevice();
114     uint32_t queueFamilyPropertiesCount   = 0u;
115     instanceDriver.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertiesCount, DE_NULL);
116 
117     if (queueFamilyPropertiesCount == 0u)
118         TCU_THROW(ResourceError, "Device reports an empty set of queue family properties");
119 
120     std::vector<VkQueueFamilyProperties> queueFamilyProperties;
121     queueFamilyProperties.resize(queueFamilyPropertiesCount);
122 
123     instanceDriver.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertiesCount,
124                                                           &queueFamilyProperties[0]);
125 
126     if (queueFamilyPropertiesCount == 0u)
127         TCU_THROW(ResourceError, "Device reports an empty set of queue family properties");
128 
129     SelectedQueuesMap selectedQueueFamilies;
130     QueuePrioritiesMap queuePriorities;
131 
132     for (uint32_t queueReqNdx = 0; queueReqNdx < queueRequirements.size(); ++queueReqNdx)
133     {
134         const QueueRequirements &queueRequirement = queueRequirements[queueReqNdx];
135 
136         uint32_t queueFamilyIndex = 0u;
137         uint32_t queuesFoundCount = 0u;
138 
139         do
140         {
141             queueFamilyIndex =
142                 findMatchingQueueFamilyIndex(queueFamilyProperties, queueRequirement.queueFlags, queueFamilyIndex);
143 
144             if (queueFamilyIndex == NO_MATCH_FOUND)
145                 TCU_THROW(NotSupportedError, "No match found for queue requirements");
146 
147             const uint32_t queuesPerFamilyCount = deMin32(queueFamilyProperties[queueFamilyIndex].queueCount,
148                                                           queueRequirement.queueCount - queuesFoundCount);
149 
150             selectedQueueFamilies[queueFamilyIndex].queueCount =
151                 deMax32(queuesPerFamilyCount, selectedQueueFamilies[queueFamilyIndex].queueCount);
152 
153             for (uint32_t queueNdx = 0; queueNdx < queuesPerFamilyCount; ++queueNdx)
154             {
155                 Queue queue            = {DE_NULL, 0, 0};
156                 queue.queueFamilyIndex = queueFamilyIndex;
157                 queue.queueIndex       = queueNdx;
158 
159                 m_queues[queueRequirement.queueFlags].push_back(queue);
160             }
161 
162             queuesFoundCount += queuesPerFamilyCount;
163 
164             ++queueFamilyIndex;
165         } while (queuesFoundCount < queueRequirement.queueCount);
166     }
167 
168     std::vector<VkDeviceQueueCreateInfo> queueInfos;
169 
170     for (SelectedQueuesMap::iterator queueFamilyIter = selectedQueueFamilies.begin();
171          queueFamilyIter != selectedQueueFamilies.end(); ++queueFamilyIter)
172     {
173         for (uint32_t queueNdx = 0; queueNdx < queueFamilyIter->second.queueCount; ++queueNdx)
174             queuePriorities[queueFamilyIter->first].push_back(1.0f);
175 
176         const VkDeviceQueueCreateInfo queueInfo = {
177             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,  // VkStructureType sType;
178             DE_NULL,                                     // const void* pNext;
179             (VkDeviceQueueCreateFlags)0u,                // VkDeviceQueueCreateFlags flags;
180             queueFamilyIter->first,                      // uint32_t queueFamilyIndex;
181             queueFamilyIter->second.queueCount,          // uint32_t queueCount;
182             &queuePriorities[queueFamilyIter->first][0], // const float* pQueuePriorities;
183         };
184 
185         queueInfos.push_back(queueInfo);
186     }
187 
188     vk::VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT shaderImageAtomicInt64Features =
189         m_context.getShaderImageAtomicInt64FeaturesEXT();
190     vk::VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5Features = m_context.getMaintenance5Features();
191     shaderImageAtomicInt64Features.pNext                             = nullptr;
192     maintenance5Features.pNext                                       = nullptr;
193 
194     const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(instanceDriver, physicalDevice);
195     vk::VkPhysicalDeviceFeatures2 deviceFeatures2 = getPhysicalDeviceFeatures2(instanceDriver, physicalDevice);
196 
197     const bool useFeatures2 = (requireShaderImageAtomicInt64Features || requireMaintenance5);
198 
199     void *pNext = nullptr;
200 
201     if (useFeatures2)
202     {
203         pNext = &deviceFeatures2;
204 
205         if (m_useDeviceGroups)
206         {
207             deviceGroupInfo.pNext = deviceFeatures2.pNext;
208             deviceFeatures2.pNext = &deviceGroupInfo;
209         }
210 
211         if (requireShaderImageAtomicInt64Features)
212         {
213             shaderImageAtomicInt64Features.pNext = deviceFeatures2.pNext;
214             deviceFeatures2.pNext                = &shaderImageAtomicInt64Features;
215 
216             deviceExtensions.push_back("VK_EXT_shader_image_atomic_int64");
217         }
218 
219         if (requireMaintenance5)
220         {
221             maintenance5Features.pNext = deviceFeatures2.pNext;
222             deviceFeatures2.pNext      = &maintenance5Features;
223 
224             deviceExtensions.push_back("VK_KHR_maintenance5");
225         }
226     }
227     else if (m_useDeviceGroups)
228     {
229         pNext = &deviceGroupInfo;
230     }
231     const VkDeviceCreateInfo deviceInfo = {
232         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                     // VkStructureType sType;
233         pNext,                                                    // const void* pNext;
234         (VkDeviceCreateFlags)0,                                   // VkDeviceCreateFlags flags;
235         static_cast<uint32_t>(queueInfos.size()),                 // uint32_t queueCreateInfoCount;
236         &queueInfos[0],                                           // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
237         0u,                                                       // uint32_t enabledLayerCount;
238         DE_NULL,                                                  // const char* const* ppEnabledLayerNames;
239         uint32_t(deviceExtensions.size()),                        // uint32_t enabledExtensionCount;
240         deviceExtensions.size() ? &deviceExtensions[0] : DE_NULL, // const char* const* ppEnabledExtensionNames;
241         useFeatures2 ? nullptr : &deviceFeatures,                 // const VkPhysicalDeviceFeatures* pEnabledFeatures;
242     };
243 
244     m_logicalDevice =
245         createCustomDevice(m_context.getTestContext().getCommandLine().isValidationEnabled(),
246                            m_context.getPlatformInterface(), instance, instanceDriver, physicalDevice, &deviceInfo);
247     m_deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(m_context.getPlatformInterface(), instance,
248                                                                 *m_logicalDevice, m_context.getUsedApiVersion(),
249                                                                 m_context.getTestContext().getCommandLine()));
250     m_allocator    = de::MovePtr<Allocator>(new SimpleAllocator(
251         *m_deviceDriver, *m_logicalDevice, getPhysicalDeviceMemoryProperties(instanceDriver, physicalDevice)));
252 
253     for (QueuesMap::iterator queuesIter = m_queues.begin(); queuesIter != m_queues.end(); ++queuesIter)
254     {
255         for (uint32_t queueNdx = 0u; queueNdx < queuesIter->second.size(); ++queueNdx)
256         {
257             Queue &queue = queuesIter->second[queueNdx];
258 
259             queue.queueHandle =
260                 getDeviceQueue(*m_deviceDriver, *m_logicalDevice, queue.queueFamilyIndex, queue.queueIndex);
261         }
262     }
263 }
264 
getQueue(const VkQueueFlags queueFlags,const uint32_t queueIndex) const265 const Queue &SparseResourcesBaseInstance::getQueue(const VkQueueFlags queueFlags, const uint32_t queueIndex) const
266 {
267     return m_queues.find(queueFlags)->second[queueIndex];
268 }
269 
270 } // namespace sparse
271 } // namespace vkt
272