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