1 // Copyright 2020 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/VulkanExtensions.h" 16 17 #include "common/Assert.h" 18 #include "common/vulkan_platform.h" 19 20 #include <array> 21 #include <limits> 22 23 namespace dawn_native { namespace vulkan { 24 25 static constexpr uint32_t VulkanVersion_1_1 = VK_MAKE_VERSION(1, 1, 0); 26 static constexpr uint32_t VulkanVersion_1_2 = VK_MAKE_VERSION(1, 2, 0); 27 static constexpr uint32_t NeverPromoted = std::numeric_limits<uint32_t>::max(); 28 29 // A static array for InstanceExtInfo that can be indexed with InstanceExts. 30 // GetInstanceExtInfo checks that "index" matches the index used to access this array so an 31 // assert will fire if it isn't in the correct order. 32 static constexpr size_t kInstanceExtCount = static_cast<size_t>(InstanceExt::EnumCount); 33 static constexpr std::array<InstanceExtInfo, kInstanceExtCount> sInstanceExtInfos{{ 34 // 35 {InstanceExt::GetPhysicalDeviceProperties2, "VK_KHR_get_physical_device_properties2", 36 VulkanVersion_1_1}, 37 {InstanceExt::ExternalMemoryCapabilities, "VK_KHR_external_memory_capabilities", 38 VulkanVersion_1_1}, 39 {InstanceExt::ExternalSemaphoreCapabilities, "VK_KHR_external_semaphore_capabilities", 40 VulkanVersion_1_1}, 41 42 {InstanceExt::Surface, "VK_KHR_surface", NeverPromoted}, 43 {InstanceExt::FuchsiaImagePipeSurface, "VK_FUCHSIA_imagepipe_surface", NeverPromoted}, 44 {InstanceExt::MetalSurface, "VK_EXT_metal_surface", NeverPromoted}, 45 {InstanceExt::WaylandSurface, "VK_KHR_wayland_surface", NeverPromoted}, 46 {InstanceExt::Win32Surface, "VK_KHR_win32_surface", NeverPromoted}, 47 {InstanceExt::XcbSurface, "VK_KHR_xcb_surface", NeverPromoted}, 48 {InstanceExt::XlibSurface, "VK_KHR_xlib_surface", NeverPromoted}, 49 50 {InstanceExt::DebugUtils, "VK_EXT_debug_utils", NeverPromoted}, 51 {InstanceExt::ValidationFeatures, "VK_EXT_validation_features", NeverPromoted}, 52 // 53 }}; 54 GetInstanceExtInfo(InstanceExt ext)55 const InstanceExtInfo& GetInstanceExtInfo(InstanceExt ext) { 56 uint32_t index = static_cast<uint32_t>(ext); 57 ASSERT(index < sInstanceExtInfos.size()); 58 ASSERT(sInstanceExtInfos[index].index == ext); 59 return sInstanceExtInfos[index]; 60 } 61 CreateInstanceExtNameMap()62 std::unordered_map<std::string, InstanceExt> CreateInstanceExtNameMap() { 63 std::unordered_map<std::string, InstanceExt> result; 64 for (const InstanceExtInfo& info : sInstanceExtInfos) { 65 result[info.name] = info.index; 66 } 67 return result; 68 } 69 EnsureDependencies(const InstanceExtSet & advertisedExts)70 InstanceExtSet EnsureDependencies(const InstanceExtSet& advertisedExts) { 71 // We need to check that all transitive dependencies of extensions are advertised. 72 // To do that in a single pass and no data structures, the extensions are topologically 73 // sorted in the definition of InstanceExt. 74 // To ensure the order is correct, we mark visited extensions in `visitedSet` and each 75 // dependency check will first assert all its dependents have been visited. 76 InstanceExtSet visitedSet; 77 InstanceExtSet trimmedSet; 78 79 auto HasDep = [&](InstanceExt ext) -> bool { 80 ASSERT(visitedSet[ext]); 81 return trimmedSet[ext]; 82 }; 83 84 for (uint32_t i = 0; i < sInstanceExtInfos.size(); i++) { 85 InstanceExt ext = static_cast<InstanceExt>(i); 86 87 bool hasDependencies = false; 88 switch (ext) { 89 case InstanceExt::GetPhysicalDeviceProperties2: 90 case InstanceExt::Surface: 91 case InstanceExt::DebugUtils: 92 case InstanceExt::ValidationFeatures: 93 hasDependencies = true; 94 break; 95 96 case InstanceExt::ExternalMemoryCapabilities: 97 case InstanceExt::ExternalSemaphoreCapabilities: 98 hasDependencies = HasDep(InstanceExt::GetPhysicalDeviceProperties2); 99 break; 100 101 case InstanceExt::FuchsiaImagePipeSurface: 102 case InstanceExt::MetalSurface: 103 case InstanceExt::WaylandSurface: 104 case InstanceExt::Win32Surface: 105 case InstanceExt::XcbSurface: 106 case InstanceExt::XlibSurface: 107 hasDependencies = HasDep(InstanceExt::Surface); 108 break; 109 110 case InstanceExt::EnumCount: 111 UNREACHABLE(); 112 } 113 114 trimmedSet.set(ext, hasDependencies && advertisedExts[ext]); 115 visitedSet.set(ext, true); 116 } 117 118 return trimmedSet; 119 } 120 MarkPromotedExtensions(InstanceExtSet * extensions,uint32_t version)121 void MarkPromotedExtensions(InstanceExtSet* extensions, uint32_t version) { 122 for (const InstanceExtInfo& info : sInstanceExtInfos) { 123 if (info.versionPromoted <= version) { 124 extensions->set(info.index, true); 125 } 126 } 127 } 128 129 static constexpr size_t kDeviceExtCount = static_cast<size_t>(DeviceExt::EnumCount); 130 static constexpr std::array<DeviceExtInfo, kDeviceExtCount> sDeviceExtInfos{{ 131 // 132 {DeviceExt::BindMemory2, "VK_KHR_bind_memory2", VulkanVersion_1_1}, 133 {DeviceExt::Maintenance1, "VK_KHR_maintenance1", VulkanVersion_1_1}, 134 {DeviceExt::StorageBufferStorageClass, "VK_KHR_storage_buffer_storage_class", 135 VulkanVersion_1_1}, 136 {DeviceExt::GetPhysicalDeviceProperties2, "VK_KHR_get_physical_device_properties2", 137 VulkanVersion_1_1}, 138 {DeviceExt::GetMemoryRequirements2, "VK_KHR_get_memory_requirements2", VulkanVersion_1_1}, 139 {DeviceExt::ExternalMemoryCapabilities, "VK_KHR_external_memory_capabilities", 140 VulkanVersion_1_1}, 141 {DeviceExt::ExternalSemaphoreCapabilities, "VK_KHR_external_semaphore_capabilities", 142 VulkanVersion_1_1}, 143 {DeviceExt::ExternalMemory, "VK_KHR_external_memory", VulkanVersion_1_1}, 144 {DeviceExt::ExternalSemaphore, "VK_KHR_external_semaphore", VulkanVersion_1_1}, 145 {DeviceExt::_16BitStorage, "VK_KHR_16bit_storage", VulkanVersion_1_1}, 146 {DeviceExt::SamplerYCbCrConversion, "VK_KHR_sampler_ycbcr_conversion", VulkanVersion_1_1}, 147 148 {DeviceExt::DriverProperties, "VK_KHR_driver_properties", VulkanVersion_1_2}, 149 {DeviceExt::ImageFormatList, "VK_KHR_image_format_list", VulkanVersion_1_2}, 150 {DeviceExt::ShaderFloat16Int8, "VK_KHR_shader_float16_int8", VulkanVersion_1_2}, 151 152 {DeviceExt::ExternalMemoryFD, "VK_KHR_external_memory_fd", NeverPromoted}, 153 {DeviceExt::ExternalMemoryDmaBuf, "VK_EXT_external_memory_dma_buf", NeverPromoted}, 154 {DeviceExt::ExternalMemoryZirconHandle, "VK_FUCHSIA_external_memory", NeverPromoted}, 155 {DeviceExt::ExternalSemaphoreFD, "VK_KHR_external_semaphore_fd", NeverPromoted}, 156 {DeviceExt::ExternalSemaphoreZirconHandle, "VK_FUCHSIA_external_semaphore", NeverPromoted}, 157 158 {DeviceExt::ImageDrmFormatModifier, "VK_EXT_image_drm_format_modifier", NeverPromoted}, 159 {DeviceExt::Swapchain, "VK_KHR_swapchain", NeverPromoted}, 160 {DeviceExt::SubgroupSizeControl, "VK_EXT_subgroup_size_control", NeverPromoted}, 161 // 162 }}; 163 GetDeviceExtInfo(DeviceExt ext)164 const DeviceExtInfo& GetDeviceExtInfo(DeviceExt ext) { 165 uint32_t index = static_cast<uint32_t>(ext); 166 ASSERT(index < sDeviceExtInfos.size()); 167 ASSERT(sDeviceExtInfos[index].index == ext); 168 return sDeviceExtInfos[index]; 169 } 170 CreateDeviceExtNameMap()171 std::unordered_map<std::string, DeviceExt> CreateDeviceExtNameMap() { 172 std::unordered_map<std::string, DeviceExt> result; 173 for (const DeviceExtInfo& info : sDeviceExtInfos) { 174 result[info.name] = info.index; 175 } 176 return result; 177 } 178 EnsureDependencies(const DeviceExtSet & advertisedExts,const InstanceExtSet & instanceExts,uint32_t icdVersion)179 DeviceExtSet EnsureDependencies(const DeviceExtSet& advertisedExts, 180 const InstanceExtSet& instanceExts, 181 uint32_t icdVersion) { 182 // This is very similar to EnsureDependencies for instanceExtSet. See comment there for 183 // an explanation of what happens. 184 DeviceExtSet visitedSet; 185 DeviceExtSet trimmedSet; 186 187 auto HasDep = [&](DeviceExt ext) -> bool { 188 ASSERT(visitedSet[ext]); 189 return trimmedSet[ext]; 190 }; 191 192 for (uint32_t i = 0; i < sDeviceExtInfos.size(); i++) { 193 DeviceExt ext = static_cast<DeviceExt>(i); 194 195 bool hasDependencies = false; 196 switch (ext) { 197 // Happy extensions don't need anybody else! 198 case DeviceExt::BindMemory2: 199 case DeviceExt::GetMemoryRequirements2: 200 case DeviceExt::Maintenance1: 201 case DeviceExt::ImageFormatList: 202 case DeviceExt::StorageBufferStorageClass: 203 hasDependencies = true; 204 break; 205 206 // Physical device extensions technically don't require the instance to support 207 // them but VulkanFunctions only loads the function pointers if the instance 208 // advertises the extension. So if we didn't have this check, we'd risk a calling 209 // a nullptr. 210 case DeviceExt::GetPhysicalDeviceProperties2: 211 hasDependencies = instanceExts[InstanceExt::GetPhysicalDeviceProperties2]; 212 break; 213 case DeviceExt::ExternalMemoryCapabilities: 214 hasDependencies = instanceExts[InstanceExt::ExternalMemoryCapabilities] && 215 HasDep(DeviceExt::GetPhysicalDeviceProperties2); 216 break; 217 case DeviceExt::ExternalSemaphoreCapabilities: 218 hasDependencies = instanceExts[InstanceExt::ExternalSemaphoreCapabilities] && 219 HasDep(DeviceExt::GetPhysicalDeviceProperties2); 220 break; 221 222 case DeviceExt::ImageDrmFormatModifier: 223 hasDependencies = HasDep(DeviceExt::BindMemory2) && 224 HasDep(DeviceExt::GetPhysicalDeviceProperties2) && 225 HasDep(DeviceExt::ImageFormatList) && 226 HasDep(DeviceExt::SamplerYCbCrConversion); 227 break; 228 229 case DeviceExt::Swapchain: 230 hasDependencies = instanceExts[InstanceExt::Surface]; 231 break; 232 233 case DeviceExt::SamplerYCbCrConversion: 234 hasDependencies = HasDep(DeviceExt::Maintenance1) && 235 HasDep(DeviceExt::BindMemory2) && 236 HasDep(DeviceExt::GetMemoryRequirements2) && 237 HasDep(DeviceExt::GetPhysicalDeviceProperties2); 238 break; 239 240 case DeviceExt::DriverProperties: 241 case DeviceExt::ShaderFloat16Int8: 242 hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2); 243 break; 244 245 case DeviceExt::ExternalMemory: 246 hasDependencies = HasDep(DeviceExt::ExternalMemoryCapabilities); 247 break; 248 249 case DeviceExt::ExternalSemaphore: 250 hasDependencies = HasDep(DeviceExt::ExternalSemaphoreCapabilities); 251 break; 252 253 case DeviceExt::ExternalMemoryFD: 254 case DeviceExt::ExternalMemoryZirconHandle: 255 hasDependencies = HasDep(DeviceExt::ExternalMemory); 256 break; 257 258 case DeviceExt::ExternalMemoryDmaBuf: 259 hasDependencies = HasDep(DeviceExt::ExternalMemoryFD); 260 break; 261 262 case DeviceExt::ExternalSemaphoreFD: 263 case DeviceExt::ExternalSemaphoreZirconHandle: 264 hasDependencies = HasDep(DeviceExt::ExternalSemaphore); 265 break; 266 267 case DeviceExt::_16BitStorage: 268 hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2) && 269 HasDep(DeviceExt::StorageBufferStorageClass); 270 break; 271 272 case DeviceExt::SubgroupSizeControl: 273 // Using the extension requires DeviceExt::GetPhysicalDeviceProperties2, but we 274 // don't need to check for it as it also requires Vulkan 1.1 in which 275 // VK_KHR_get_physical_device_properties2 was promoted. 276 hasDependencies = icdVersion >= VulkanVersion_1_1; 277 break; 278 279 case DeviceExt::EnumCount: 280 UNREACHABLE(); 281 } 282 283 trimmedSet.set(ext, hasDependencies && advertisedExts[ext]); 284 visitedSet.set(ext, true); 285 } 286 287 return trimmedSet; 288 } 289 MarkPromotedExtensions(DeviceExtSet * extensions,uint32_t version)290 void MarkPromotedExtensions(DeviceExtSet* extensions, uint32_t version) { 291 for (const DeviceExtInfo& info : sDeviceExtInfos) { 292 if (info.versionPromoted <= version) { 293 extensions->set(info.index, true); 294 } 295 } 296 } 297 298 // A static array for VulkanLayerInfo that can be indexed with VulkanLayers. 299 // GetVulkanLayerInfo checks that "index" matches the index used to access this array so an 300 // assert will fire if it isn't in the correct order. 301 static constexpr size_t kVulkanLayerCount = static_cast<size_t>(VulkanLayer::EnumCount); 302 static constexpr std::array<VulkanLayerInfo, kVulkanLayerCount> sVulkanLayerInfos{{ 303 // 304 {VulkanLayer::Validation, "VK_LAYER_KHRONOS_validation"}, 305 {VulkanLayer::LunargVkTrace, "VK_LAYER_LUNARG_vktrace"}, 306 {VulkanLayer::RenderDocCapture, "VK_LAYER_RENDERDOC_Capture"}, 307 {VulkanLayer::FuchsiaImagePipeSwapchain, "VK_LAYER_FUCHSIA_imagepipe_swapchain"}, 308 // 309 }}; 310 GetVulkanLayerInfo(VulkanLayer layer)311 const VulkanLayerInfo& GetVulkanLayerInfo(VulkanLayer layer) { 312 uint32_t index = static_cast<uint32_t>(layer); 313 ASSERT(index < sVulkanLayerInfos.size()); 314 ASSERT(sVulkanLayerInfos[index].layer == layer); 315 return sVulkanLayerInfos[index]; 316 } 317 CreateVulkanLayerNameMap()318 std::unordered_map<std::string, VulkanLayer> CreateVulkanLayerNameMap() { 319 std::unordered_map<std::string, VulkanLayer> result; 320 for (const VulkanLayerInfo& info : sVulkanLayerInfos) { 321 result[info.name] = info.layer; 322 } 323 return result; 324 } 325 326 }} // namespace dawn_native::vulkan 327