• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/vulkan/VulkanInfo.h"
16 
17 #include "dawn_native/vulkan/AdapterVk.h"
18 #include "dawn_native/vulkan/BackendVk.h"
19 #include "dawn_native/vulkan/UtilsVulkan.h"
20 #include "dawn_native/vulkan/VulkanError.h"
21 
22 #include <cstring>
23 
24 namespace dawn_native { namespace vulkan {
25 
26     namespace {
GatherInstanceExtensions(const char * layerName,const dawn_native::vulkan::VulkanFunctions & vkFunctions,const std::unordered_map<std::string,InstanceExt> & knownExts)27         ResultOrError<InstanceExtSet> GatherInstanceExtensions(
28             const char* layerName,
29             const dawn_native::vulkan::VulkanFunctions& vkFunctions,
30             const std::unordered_map<std::string, InstanceExt>& knownExts) {
31             uint32_t count = 0;
32             VkResult vkResult = VkResult::WrapUnsafe(
33                 vkFunctions.EnumerateInstanceExtensionProperties(layerName, &count, nullptr));
34             if (vkResult != VK_SUCCESS && vkResult != VK_INCOMPLETE) {
35                 return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties");
36             }
37 
38             std::vector<VkExtensionProperties> extensions(count);
39             DAWN_TRY(CheckVkSuccess(vkFunctions.EnumerateInstanceExtensionProperties(
40                                         layerName, &count, extensions.data()),
41                                     "vkEnumerateInstanceExtensionProperties"));
42 
43             InstanceExtSet result;
44             for (const VkExtensionProperties& extension : extensions) {
45                 auto it = knownExts.find(extension.extensionName);
46                 if (it != knownExts.end()) {
47                     result.set(it->second, true);
48                 }
49             }
50 
51             return result;
52         }
53 
54     }  // namespace
55 
HasExt(InstanceExt ext) const56     bool VulkanGlobalKnobs::HasExt(InstanceExt ext) const {
57         return extensions[ext];
58     }
59 
HasExt(DeviceExt ext) const60     bool VulkanDeviceKnobs::HasExt(DeviceExt ext) const {
61         return extensions[ext];
62     }
63 
GatherGlobalInfo(const VulkanFunctions & vkFunctions)64     ResultOrError<VulkanGlobalInfo> GatherGlobalInfo(const VulkanFunctions& vkFunctions) {
65         VulkanGlobalInfo info = {};
66         // Gather info on available API version
67         {
68             info.apiVersion = VK_MAKE_VERSION(1, 0, 0);
69             if (vkFunctions.EnumerateInstanceVersion != nullptr) {
70                 DAWN_TRY(CheckVkSuccess(vkFunctions.EnumerateInstanceVersion(&info.apiVersion),
71                                         "vkEnumerateInstanceVersion"));
72             }
73         }
74 
75         // Gather the info about the instance layers
76         {
77             uint32_t count = 0;
78             VkResult result =
79                 VkResult::WrapUnsafe(vkFunctions.EnumerateInstanceLayerProperties(&count, nullptr));
80             // From the Vulkan spec result should be success if there are 0 layers,
81             // incomplete otherwise. This means that both values represent a success.
82             // This is the same for all Enumarte functions
83             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
84                 return DAWN_INTERNAL_ERROR("vkEnumerateInstanceLayerProperties");
85             }
86 
87             std::vector<VkLayerProperties> layersProperties(count);
88             DAWN_TRY(CheckVkSuccess(
89                 vkFunctions.EnumerateInstanceLayerProperties(&count, layersProperties.data()),
90                 "vkEnumerateInstanceLayerProperties"));
91 
92             std::unordered_map<std::string, VulkanLayer> knownLayers = CreateVulkanLayerNameMap();
93             for (const VkLayerProperties& layer : layersProperties) {
94                 auto it = knownLayers.find(layer.layerName);
95                 if (it != knownLayers.end()) {
96                     info.layers.set(it->second, true);
97                 }
98             }
99         }
100 
101         // Gather the info about the instance extensions
102         {
103             std::unordered_map<std::string, InstanceExt> knownExts = CreateInstanceExtNameMap();
104 
105             DAWN_TRY_ASSIGN(info.extensions,
106                             GatherInstanceExtensions(nullptr, vkFunctions, knownExts));
107             MarkPromotedExtensions(&info.extensions, info.apiVersion);
108             info.extensions = EnsureDependencies(info.extensions);
109 
110             for (VulkanLayer layer : IterateBitSet(info.layers)) {
111                 DAWN_TRY_ASSIGN(info.layerExtensions[layer],
112                                 GatherInstanceExtensions(GetVulkanLayerInfo(layer).name,
113                                                          vkFunctions, knownExts));
114                 MarkPromotedExtensions(&info.layerExtensions[layer], info.apiVersion);
115                 info.layerExtensions[layer] = EnsureDependencies(info.layerExtensions[layer]);
116             }
117         }
118 
119         return std::move(info);
120     }
121 
GatherPhysicalDevices(VkInstance instance,const VulkanFunctions & vkFunctions)122     ResultOrError<std::vector<VkPhysicalDevice>> GatherPhysicalDevices(
123         VkInstance instance,
124         const VulkanFunctions& vkFunctions) {
125         uint32_t count = 0;
126         VkResult result =
127             VkResult::WrapUnsafe(vkFunctions.EnumeratePhysicalDevices(instance, &count, nullptr));
128         if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
129             return DAWN_INTERNAL_ERROR("vkEnumeratePhysicalDevices");
130         }
131 
132         std::vector<VkPhysicalDevice> physicalDevices(count);
133         DAWN_TRY(CheckVkSuccess(
134             vkFunctions.EnumeratePhysicalDevices(instance, &count, physicalDevices.data()),
135             "vkEnumeratePhysicalDevices"));
136 
137         return std::move(physicalDevices);
138     }
139 
GatherDeviceInfo(const Adapter & adapter)140     ResultOrError<VulkanDeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
141         VulkanDeviceInfo info = {};
142         VkPhysicalDevice physicalDevice = adapter.GetPhysicalDevice();
143         const VulkanGlobalInfo& globalInfo = adapter.GetVulkanInstance()->GetGlobalInfo();
144         const VulkanFunctions& vkFunctions = adapter.GetVulkanInstance()->GetFunctions();
145 
146         // Query the device properties first to get the ICD's `apiVersion`
147         vkFunctions.GetPhysicalDeviceProperties(physicalDevice, &info.properties);
148 
149         // Gather info about device memory.
150         {
151             VkPhysicalDeviceMemoryProperties memory;
152             vkFunctions.GetPhysicalDeviceMemoryProperties(physicalDevice, &memory);
153 
154             info.memoryTypes.assign(memory.memoryTypes,
155                                     memory.memoryTypes + memory.memoryTypeCount);
156             info.memoryHeaps.assign(memory.memoryHeaps,
157                                     memory.memoryHeaps + memory.memoryHeapCount);
158         }
159 
160         // Gather info about device queue families
161         {
162             uint32_t count = 0;
163             vkFunctions.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr);
164 
165             info.queueFamilies.resize(count);
166             vkFunctions.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count,
167                                                                info.queueFamilies.data());
168         }
169 
170         // Gather the info about the device layers
171         {
172             uint32_t count = 0;
173             VkResult result = VkResult::WrapUnsafe(
174                 vkFunctions.EnumerateDeviceLayerProperties(physicalDevice, &count, nullptr));
175             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
176                 return DAWN_INTERNAL_ERROR("vkEnumerateDeviceLayerProperties");
177             }
178 
179             info.layers.resize(count);
180             DAWN_TRY(CheckVkSuccess(vkFunctions.EnumerateDeviceLayerProperties(
181                                         physicalDevice, &count, info.layers.data()),
182                                     "vkEnumerateDeviceLayerProperties"));
183         }
184 
185         // Gather the info about the device extensions
186         {
187             uint32_t count = 0;
188             VkResult result = VkResult::WrapUnsafe(vkFunctions.EnumerateDeviceExtensionProperties(
189                 physicalDevice, nullptr, &count, nullptr));
190             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
191                 return DAWN_INTERNAL_ERROR("vkEnumerateDeviceExtensionProperties");
192             }
193 
194             std::vector<VkExtensionProperties> extensionsProperties;
195             extensionsProperties.resize(count);
196             DAWN_TRY(
197                 CheckVkSuccess(vkFunctions.EnumerateDeviceExtensionProperties(
198                                    physicalDevice, nullptr, &count, extensionsProperties.data()),
199                                "vkEnumerateDeviceExtensionProperties"));
200 
201             std::unordered_map<std::string, DeviceExt> knownExts = CreateDeviceExtNameMap();
202 
203             for (const VkExtensionProperties& extension : extensionsProperties) {
204                 auto it = knownExts.find(extension.extensionName);
205                 if (it != knownExts.end()) {
206                     info.extensions.set(it->second, true);
207                 }
208             }
209 
210             MarkPromotedExtensions(&info.extensions, info.properties.apiVersion);
211             info.extensions = EnsureDependencies(info.extensions, globalInfo.extensions,
212                                                  info.properties.apiVersion);
213         }
214 
215         // Gather general and extension features and properties
216         //
217         // Use vkGetPhysicalDevice{Features,Properties}2 if required to gather information about
218         // the extensions. DeviceExt::GetPhysicalDeviceProperties2 is guaranteed to be available
219         // because these extensions (transitively) depend on it in `EnsureDependencies`
220         VkPhysicalDeviceFeatures2 features2 = {};
221         features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
222         PNextChainBuilder featuresChain(&features2);
223 
224         VkPhysicalDeviceProperties2 properties2 = {};
225         properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
226         PNextChainBuilder propertiesChain(&properties2);
227 
228         if (info.extensions[DeviceExt::ShaderFloat16Int8]) {
229             featuresChain.Add(&info.shaderFloat16Int8Features,
230                               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR);
231         }
232 
233         if (info.extensions[DeviceExt::_16BitStorage]) {
234             featuresChain.Add(&info._16BitStorageFeatures,
235                               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES);
236         }
237 
238         if (info.extensions[DeviceExt::SubgroupSizeControl]) {
239             featuresChain.Add(&info.subgroupSizeControlFeatures,
240                               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT);
241             propertiesChain.Add(
242                 &info.subgroupSizeControlProperties,
243                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT);
244         }
245 
246         if (info.extensions[DeviceExt::DriverProperties]) {
247             propertiesChain.Add(&info.driverProperties,
248                                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES);
249         }
250 
251         // If we have DeviceExt::GetPhysicalDeviceProperties2, use features2 and properties2 so
252         // that features no covered by VkPhysicalDevice{Features,Properties} can be queried.
253         //
254         // Note that info.properties has already been filled at the start of this function to get
255         // `apiVersion`.
256         ASSERT(info.properties.apiVersion != 0);
257         if (info.extensions[DeviceExt::GetPhysicalDeviceProperties2]) {
258             vkFunctions.GetPhysicalDeviceProperties2(physicalDevice, &properties2);
259             vkFunctions.GetPhysicalDeviceFeatures2(physicalDevice, &features2);
260             info.features = features2.features;
261         } else {
262             ASSERT(features2.pNext == nullptr && properties2.pNext == nullptr);
263             vkFunctions.GetPhysicalDeviceFeatures(physicalDevice, &info.features);
264         }
265 
266         // TODO(cwallez@chromium.org): gather info about formats
267 
268         return std::move(info);
269     }
270 
GatherSurfaceInfo(const Adapter & adapter,VkSurfaceKHR surface)271     ResultOrError<VulkanSurfaceInfo> GatherSurfaceInfo(const Adapter& adapter,
272                                                        VkSurfaceKHR surface) {
273         VulkanSurfaceInfo info = {};
274 
275         VkPhysicalDevice physicalDevice = adapter.GetPhysicalDevice();
276         const VulkanFunctions& vkFunctions = adapter.GetVulkanInstance()->GetFunctions();
277 
278         // Get the surface capabilities
279         DAWN_TRY(CheckVkSuccess(vkFunctions.GetPhysicalDeviceSurfaceCapabilitiesKHR(
280                                     physicalDevice, surface, &info.capabilities),
281                                 "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
282 
283         // Query which queue families support presenting this surface
284         {
285             size_t nQueueFamilies = adapter.GetDeviceInfo().queueFamilies.size();
286             info.supportedQueueFamilies.resize(nQueueFamilies, false);
287 
288             for (uint32_t i = 0; i < nQueueFamilies; ++i) {
289                 VkBool32 supported = VK_FALSE;
290                 DAWN_TRY(CheckVkSuccess(vkFunctions.GetPhysicalDeviceSurfaceSupportKHR(
291                                             physicalDevice, i, surface, &supported),
292                                         "vkGetPhysicalDeviceSurfaceSupportKHR"));
293 
294                 info.supportedQueueFamilies[i] = (supported == VK_TRUE);
295             }
296         }
297 
298         // Gather supported formats
299         {
300             uint32_t count = 0;
301             VkResult result = VkResult::WrapUnsafe(vkFunctions.GetPhysicalDeviceSurfaceFormatsKHR(
302                 physicalDevice, surface, &count, nullptr));
303             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
304                 return DAWN_INTERNAL_ERROR("vkGetPhysicalDeviceSurfaceFormatsKHR");
305             }
306 
307             info.formats.resize(count);
308             DAWN_TRY(CheckVkSuccess(vkFunctions.GetPhysicalDeviceSurfaceFormatsKHR(
309                                         physicalDevice, surface, &count, info.formats.data()),
310                                     "vkGetPhysicalDeviceSurfaceFormatsKHR"));
311         }
312 
313         // Gather supported presents modes
314         {
315             uint32_t count = 0;
316             VkResult result =
317                 VkResult::WrapUnsafe(vkFunctions.GetPhysicalDeviceSurfacePresentModesKHR(
318                     physicalDevice, surface, &count, nullptr));
319             if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
320                 return DAWN_INTERNAL_ERROR("vkGetPhysicalDeviceSurfacePresentModesKHR");
321             }
322 
323             info.presentModes.resize(count);
324             DAWN_TRY(CheckVkSuccess(vkFunctions.GetPhysicalDeviceSurfacePresentModesKHR(
325                                         physicalDevice, surface, &count, info.presentModes.data()),
326                                     "vkGetPhysicalDeviceSurfacePresentModesKHR"));
327         }
328 
329         return std::move(info);
330     }
331 
332 }}  // namespace dawn_native::vulkan
333