From 0dc70785d813dc2e0e6236d96303632f1281e1c5 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Thu, 11 Jun 2020 11:48:05 +0000 Subject: [PATCH] Vulkan: handle Instance extensions more programmatically At the moment each instance extension needs special handling in 6+ places when added to the Vulkan backend. This is very error-prone and makes it difficult to do changes in how they are extensions are handled. This CL makes instance extensions linked with an enum class and a bitset to know which are available (instead of individual booleans). A table of known extensions with more information like `versionPromoted` so that they can be handled programmatically. Bug: dawn:457 Change-Id: I266deb730eb2b7f3ab0ee7ada1b06ff9748a60e4 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22940 Reviewed-by: Corentin Wallez Commit-Queue: Corentin Wallez --- src/dawn_native/BUILD.gn | 2 + src/dawn_native/CMakeLists.txt | 2 + src/dawn_native/vulkan/BackendVk.cpp | 103 ++++--------- src/dawn_native/vulkan/VulkanExtensions.cpp | 135 ++++++++++++++++++ src/dawn_native/vulkan/VulkanExtensions.h | 75 ++++++++++ src/dawn_native/vulkan/VulkanFunctions.cpp | 18 +-- src/dawn_native/vulkan/VulkanInfo.cpp | 115 ++++++--------- src/dawn_native/vulkan/VulkanInfo.h | 24 +--- .../external_memory/MemoryServiceDmaBuf.cpp | 4 +- .../external_memory/MemoryServiceOpaqueFD.cpp | 6 +- .../MemoryServiceZirconHandle.cpp | 6 +- .../SemaphoreServiceOpaqueFD.cpp | 6 +- .../SemaphoreServiceZirconHandle.cpp | 6 +- 13 files changed, 311 insertions(+), 191 deletions(-) create mode 100644 src/dawn_native/vulkan/VulkanExtensions.cpp create mode 100644 src/dawn_native/vulkan/VulkanExtensions.h diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn index 3f24ba39d8..f6974c8a3d 100644 --- a/src/dawn_native/BUILD.gn +++ b/src/dawn_native/BUILD.gn @@ -519,6 +519,8 @@ source_set("dawn_native_sources") { "vulkan/UtilsVulkan.h", "vulkan/VulkanError.cpp", "vulkan/VulkanError.h", + "vulkan/VulkanExtensions.cpp", + "vulkan/VulkanExtensions.h", "vulkan/VulkanFunctions.cpp", "vulkan/VulkanFunctions.h", "vulkan/VulkanInfo.cpp", diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt index 7cee0d0918..cabbc1a6c3 100644 --- a/src/dawn_native/CMakeLists.txt +++ b/src/dawn_native/CMakeLists.txt @@ -412,6 +412,8 @@ if (DAWN_ENABLE_VULKAN) "vulkan/UtilsVulkan.h" "vulkan/VulkanError.cpp" "vulkan/VulkanError.h" + "vulkan/VulkanExtensions.cpp" + "vulkan/VulkanExtensions.h" "vulkan/VulkanFunctions.cpp" "vulkan/VulkanFunctions.h" "vulkan/VulkanInfo.cpp" diff --git a/src/dawn_native/vulkan/BackendVk.cpp b/src/dawn_native/vulkan/BackendVk.cpp index f664cd6404..c682b72453 100644 --- a/src/dawn_native/vulkan/BackendVk.cpp +++ b/src/dawn_native/vulkan/BackendVk.cpp @@ -14,6 +14,7 @@ #include "dawn_native/vulkan/BackendVk.h" +#include "common/BitSetIterator.h" #include "common/Log.h" #include "common/SystemUtils.h" #include "dawn_native/Instance.h" @@ -149,7 +150,7 @@ namespace dawn_native { namespace vulkan { DAWN_TRY(mFunctions.LoadInstanceProcs(mInstance, mGlobalInfo)); - if (usedGlobalKnobs.debugReport) { + if (usedGlobalKnobs.HasExt(InstanceExt::DebugReport)) { DAWN_TRY(RegisterDebugReport()); } @@ -176,9 +177,7 @@ namespace dawn_native { namespace vulkan { ResultOrError Backend::CreateInstance() { VulkanGlobalKnobs usedKnobs = {}; - - std::vector layersToRequest; - std::vector extensionsToRequest; + std::vector layerNames; // vktrace works by instering a layer, but we hide it behind a macro due to the vktrace // layer crashes when used without vktrace server started. See this vktrace issue: @@ -187,7 +186,7 @@ namespace dawn_native { namespace vulkan { // by other layers. #if defined(DAWN_USE_VKTRACE) if (mGlobalInfo.vktrace) { - layersToRequest.push_back(kLayerNameLunargVKTrace); + layerNames.push_back(kLayerNameLunargVKTrace); usedKnobs.vktrace = true; } #endif @@ -195,86 +194,38 @@ namespace dawn_native { namespace vulkan { // it unless we are debugging in RenderDoc so we hide it behind a macro. #if defined(DAWN_USE_RENDERDOC) if (mGlobalInfo.renderDocCapture) { - layersToRequest.push_back(kLayerNameRenderDocCapture); + layerNames.push_back(kLayerNameRenderDocCapture); usedKnobs.renderDocCapture = true; } #endif if (GetInstance()->IsBackendValidationEnabled()) { if (mGlobalInfo.validation) { - layersToRequest.push_back(kLayerNameKhronosValidation); + layerNames.push_back(kLayerNameKhronosValidation); usedKnobs.validation = true; } - if (mGlobalInfo.debugReport) { - extensionsToRequest.push_back(kExtensionNameExtDebugReport); - usedKnobs.debugReport = true; - } } - // Always request all extensions used to create VkSurfaceKHR objects so that they are - // always available for embedders looking to create VkSurfaceKHR on our VkInstance. - if (mGlobalInfo.fuchsiaImagePipeSwapchain) { - layersToRequest.push_back(kLayerNameFuchsiaImagePipeSwapchain); - usedKnobs.fuchsiaImagePipeSwapchain = true; - } - if (mGlobalInfo.metalSurface) { - extensionsToRequest.push_back(kExtensionNameExtMetalSurface); - usedKnobs.metalSurface = true; - } - if (mGlobalInfo.surface) { - extensionsToRequest.push_back(kExtensionNameKhrSurface); - usedKnobs.surface = true; - } - if (mGlobalInfo.waylandSurface) { - extensionsToRequest.push_back(kExtensionNameKhrWaylandSurface); - usedKnobs.waylandSurface = true; - } - if (mGlobalInfo.win32Surface) { - extensionsToRequest.push_back(kExtensionNameKhrWin32Surface); - usedKnobs.win32Surface = true; - } - if (mGlobalInfo.xcbSurface) { - extensionsToRequest.push_back(kExtensionNameKhrXcbSurface); - usedKnobs.xcbSurface = true; - } - if (mGlobalInfo.xlibSurface) { - extensionsToRequest.push_back(kExtensionNameKhrXlibSurface); - usedKnobs.xlibSurface = true; - } - if (mGlobalInfo.fuchsiaImagePipeSurface) { - extensionsToRequest.push_back(kExtensionNameFuchsiaImagePipeSurface); - usedKnobs.fuchsiaImagePipeSurface = true; + // Available and known instance extensions default to being requested, but some special + // cases are removed. + InstanceExtSet extensionsToRequest = mGlobalInfo.extensions; + + // TODO(cwallez@chromium.org): don't request extensions that have been promoted to Vulkan + // 1.1. This can only happen when we correctly detect and handle VkPhysicalDevice instance + // extensions that are promoted to be "device" extensions in the core Vulkan. If we don't + // do this there is a crash because a Vulkan 1.1 loader instance will not emulate the call + // on a Vulkan 1.0 ICD (and call nullptr). + // See https://github.com/KhronosGroup/Vulkan-Loader/issues/412. + + if (!GetInstance()->IsBackendValidationEnabled()) { + extensionsToRequest.Set(InstanceExt::DebugReport, false); } - // Mark the promoted extensions as present if the core version in which they were promoted - // is used. This allows having a single boolean that checks if the functionality from that - // extension is available (instead of checking extension || coreVersion). - if (mGlobalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - usedKnobs.getPhysicalDeviceProperties2 = true; - usedKnobs.externalMemoryCapabilities = true; - usedKnobs.externalSemaphoreCapabilities = true; - } + usedKnobs.extensions = extensionsToRequest; - // The Vulkan-Loader has emulation of VkPhysicalDevices functions such as - // vkGetPhysicalDeviceProperties2 when the ICD doesn't support the extension. However the - // loader has a bug where if the instance is created with Vulkan 1.1 and not the promoted - // extensions, it will skip emulation and if the ICD doesn't support Vulkan 1.1 nor the - // extensions, we will crash on nullptr function pointer when the loader tries to call the - // ICD's vkGetPhysicalDeviceProperties2. See - // https://github.com/KhronosGroup/Vulkan-Loader/issues/412. We work around this by - // specifying we want to enable the promoted extensions, even when we create a Vulkan 1.1 - // instance. - if (mGlobalInfo.externalMemoryCapabilities) { - extensionsToRequest.push_back(kExtensionNameKhrExternalMemoryCapabilities); - usedKnobs.externalMemoryCapabilities = true; - } - if (mGlobalInfo.externalSemaphoreCapabilities) { - extensionsToRequest.push_back(kExtensionNameKhrExternalSemaphoreCapabilities); - usedKnobs.externalSemaphoreCapabilities = true; - } - if (mGlobalInfo.getPhysicalDeviceProperties2) { - extensionsToRequest.push_back(kExtensionNameKhrGetPhysicalDeviceProperties2); - usedKnobs.getPhysicalDeviceProperties2 = true; + std::vector extensionNames; + for (uint32_t ext : IterateBitSet(extensionsToRequest.extensionBitSet)) { + extensionNames.push_back(GetInstanceExtInfo(static_cast(ext)).name); } VkApplicationInfo appInfo; @@ -291,10 +242,10 @@ namespace dawn_native { namespace vulkan { createInfo.pNext = nullptr; createInfo.flags = 0; createInfo.pApplicationInfo = &appInfo; - createInfo.enabledLayerCount = static_cast(layersToRequest.size()); - createInfo.ppEnabledLayerNames = layersToRequest.data(); - createInfo.enabledExtensionCount = static_cast(extensionsToRequest.size()); - createInfo.ppEnabledExtensionNames = extensionsToRequest.data(); + createInfo.enabledLayerCount = static_cast(layerNames.size()); + createInfo.ppEnabledLayerNames = layerNames.data(); + createInfo.enabledExtensionCount = static_cast(extensionNames.size()); + createInfo.ppEnabledExtensionNames = extensionNames.data(); DAWN_TRY(CheckVkSuccess(mFunctions.CreateInstance(&createInfo, nullptr, &mInstance), "vkCreateInstance")); diff --git a/src/dawn_native/vulkan/VulkanExtensions.cpp b/src/dawn_native/vulkan/VulkanExtensions.cpp new file mode 100644 index 0000000000..ea0ccabbd1 --- /dev/null +++ b/src/dawn_native/vulkan/VulkanExtensions.cpp @@ -0,0 +1,135 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_native/vulkan/VulkanExtensions.h" + +#include "common/Assert.h" +#include "common/vulkan_platform.h" + +#include +#include + +namespace dawn_native { namespace vulkan { + + static constexpr uint32_t VulkanVersion_1_1 = VK_MAKE_VERSION(1, 1, 0); + static constexpr uint32_t NeverPromoted = std::numeric_limits::max(); + + // A static array for InstanceExtInfo that can be indexed with InstanceExts. + // GetInstanceExtInfo checks that "index" matches the index used to access this array so an + // assert will fire if it isn't in the correct order. + static constexpr size_t kInstanceExtCount = static_cast(InstanceExt::EnumCount); + static constexpr std::array sInstanceExtInfos{{ + // + {InstanceExt::GetPhysicalDeviceProperties2, "VK_KHR_get_physical_device_properties2", + VulkanVersion_1_1}, + {InstanceExt::ExternalMemoryCapabilities, "VK_KHR_external_memory_capabilities", + VulkanVersion_1_1}, + {InstanceExt::ExternalSemaphoreCapabilities, "VK_KHR_external_semaphore_capabilities", + VulkanVersion_1_1}, + + {InstanceExt::Surface, "VK_KHR_surface", NeverPromoted}, + {InstanceExt::FuchsiaImagePipeSurface, "VK_FUCHSIA_imagepipe_surface", NeverPromoted}, + {InstanceExt::MetalSurface, "VK_EXT_metal_surface", NeverPromoted}, + {InstanceExt::WaylandSurface, "VK_KHR_wayland_surface", NeverPromoted}, + {InstanceExt::Win32Surface, "VK_KHR_win32_surface", NeverPromoted}, + {InstanceExt::XcbSurface, "VK_KHR_xcb_surface", NeverPromoted}, + {InstanceExt::XlibSurface, "VK_KHR_xlib_surface", NeverPromoted}, + + {InstanceExt::DebugReport, "VK_EXT_debug_report", NeverPromoted} + // + }}; + + void InstanceExtSet::Set(InstanceExt extension, bool enabled) { + extensionBitSet.set(static_cast(extension), enabled); + } + + bool InstanceExtSet::Has(InstanceExt extension) const { + return extensionBitSet[static_cast(extension)]; + } + + const InstanceExtInfo& GetInstanceExtInfo(InstanceExt ext) { + uint32_t index = static_cast(ext); + ASSERT(index < sInstanceExtInfos.size()); + ASSERT(sInstanceExtInfos[index].index == ext); + return sInstanceExtInfos[index]; + } + + std::unordered_map CreateInstanceExtNameMap() { + std::unordered_map result; + for (const InstanceExtInfo& info : sInstanceExtInfos) { + result[info.name] = info.index; + } + return result; + } + + InstanceExtSet EnsureDependencies(const InstanceExtSet& advertisedExts) { + // We need to check that all transitive dependencies of extensions are advertised. + // To do that in a single pass and no data structures, the extensions are topologically + // sorted in the definition of InstanceExt. + // To ensure the order is correct, we mark visited extensions in `visitedSet` and each + // dependency check will first assert all its dependents have been visited. + InstanceExtSet visitedSet; + InstanceExtSet trimmedSet; + + auto HasDep = [&](InstanceExt ext) -> bool { + ASSERT(visitedSet.Has(ext)); + return trimmedSet.Has(ext); + }; + + for (uint32_t i = 0; i < sInstanceExtInfos.size(); i++) { + InstanceExt ext = static_cast(i); + + bool hasDependencies = false; + switch (ext) { + case InstanceExt::GetPhysicalDeviceProperties2: + case InstanceExt::Surface: + case InstanceExt::DebugReport: + hasDependencies = true; + break; + + case InstanceExt::ExternalMemoryCapabilities: + case InstanceExt::ExternalSemaphoreCapabilities: + hasDependencies = HasDep(InstanceExt::GetPhysicalDeviceProperties2); + break; + + case InstanceExt::FuchsiaImagePipeSurface: + case InstanceExt::MetalSurface: + case InstanceExt::WaylandSurface: + case InstanceExt::Win32Surface: + case InstanceExt::XcbSurface: + case InstanceExt::XlibSurface: + hasDependencies = HasDep(InstanceExt::Surface); + break; + + default: + UNREACHABLE(); + break; + } + + trimmedSet.Set(ext, hasDependencies && advertisedExts.Has(ext)); + visitedSet.Set(ext, true); + } + + return trimmedSet; + } + + void MarkPromotedExtensions(InstanceExtSet* extensions, uint32_t version) { + for (const InstanceExtInfo& info : sInstanceExtInfos) { + if (info.versionPromoted <= version) { + extensions->Set(info.index, true); + } + } + } + +}} // namespace dawn_native::vulkan diff --git a/src/dawn_native/vulkan/VulkanExtensions.h b/src/dawn_native/vulkan/VulkanExtensions.h new file mode 100644 index 0000000000..a604faa224 --- /dev/null +++ b/src/dawn_native/vulkan/VulkanExtensions.h @@ -0,0 +1,75 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNNATIVE_VULKAN_VULKANEXTENSIONS_H_ +#define DAWNNATIVE_VULKAN_VULKANEXTENSIONS_H_ + +#include +#include + +namespace dawn_native { namespace vulkan { + + // The list of known instance extensions. They must be in dependency order (this is checked + // inside EnsureDependencies) + enum class InstanceExt { + // Promoted to 1.1 + GetPhysicalDeviceProperties2, + ExternalMemoryCapabilities, + ExternalSemaphoreCapabilities, + + // Surface extensions + Surface, + FuchsiaImagePipeSurface, + MetalSurface, + WaylandSurface, + Win32Surface, + XcbSurface, + XlibSurface, + + // Others + DebugReport, + + EnumCount, + }; + + // A bitset wrapper that is indexed with InstanceExt. + struct InstanceExtSet { + std::bitset(InstanceExt::EnumCount)> extensionBitSet; + void Set(InstanceExt extension, bool enabled); + bool Has(InstanceExt extension) const; + }; + + // Information about a known instance extension. + struct InstanceExtInfo { + InstanceExt index; + const char* name; + // The version in which this extension was promoted as built with VK_MAKE_VERSION, + // or NeverPromoted if it was never promoted. + uint32_t versionPromoted; + }; + + // Returns the information about a known InstanceExt + const InstanceExtInfo& GetInstanceExtInfo(InstanceExt ext); + // Returns a map that maps a Vulkan extension name to its InstanceExt. + std::unordered_map CreateInstanceExtNameMap(); + + // Sets entries in `extensions` to true if that entry was promoted in Vulkan version `version` + void MarkPromotedExtensions(InstanceExtSet* extensions, uint32_t version); + // From a set of extensions advertised as supported by the instance (or promoted), remove all + // extensions that don't have all their transitive dependencies in advertisedExts. + InstanceExtSet EnsureDependencies(const InstanceExtSet& advertisedExts); + +}} // namespace dawn_native::vulkan + +#endif // DAWNNATIVE_VULKAN_VULKANEXTENSIONS_H_ diff --git a/src/dawn_native/vulkan/VulkanFunctions.cpp b/src/dawn_native/vulkan/VulkanFunctions.cpp index 6099c0a321..e31f464df4 100644 --- a/src/dawn_native/vulkan/VulkanFunctions.cpp +++ b/src/dawn_native/vulkan/VulkanFunctions.cpp @@ -74,7 +74,7 @@ namespace dawn_native { namespace vulkan { GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties); GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties); - if (globalInfo.debugReport) { + if (globalInfo.HasExt(InstanceExt::DebugReport)) { GET_INSTANCE_PROC(CreateDebugReportCallbackEXT); GET_INSTANCE_PROC(DebugReportMessageEXT); GET_INSTANCE_PROC(DestroyDebugReportCallbackEXT); @@ -84,13 +84,13 @@ namespace dawn_native { namespace vulkan { // support the vendor entrypoint in GetProcAddress. if (globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { GET_INSTANCE_PROC(GetPhysicalDeviceExternalBufferProperties); - } else if (globalInfo.externalMemoryCapabilities) { + } else if (globalInfo.HasExt(InstanceExt::ExternalMemoryCapabilities)) { GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceExternalBufferProperties, KHR); } if (globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { GET_INSTANCE_PROC(GetPhysicalDeviceExternalSemaphoreProperties); - } else if (globalInfo.externalSemaphoreCapabilities) { + } else if (globalInfo.HasExt(InstanceExt::ExternalSemaphoreCapabilities)) { GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceExternalSemaphoreProperties, KHR); } @@ -102,7 +102,7 @@ namespace dawn_native { namespace vulkan { GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties2); GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties2); GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties2); - } else if (globalInfo.getPhysicalDeviceProperties2) { + } else if (globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2)) { GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceFeatures2, KHR); GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceProperties2, KHR); GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceFormatProperties2, KHR); @@ -112,7 +112,7 @@ namespace dawn_native { namespace vulkan { GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceSparseImageFormatProperties2, KHR); } - if (globalInfo.surface) { + if (globalInfo.HasExt(InstanceExt::Surface)) { GET_INSTANCE_PROC(DestroySurfaceKHR); GET_INSTANCE_PROC(GetPhysicalDeviceSurfaceSupportKHR); GET_INSTANCE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); @@ -121,26 +121,26 @@ namespace dawn_native { namespace vulkan { } #if defined(VK_USE_PLATFORM_FUCHSIA) - if (globalInfo.fuchsiaImagePipeSurface) { + if (globalInfo.HasExt(InstanceExt::FuchsiaImagePipeSurface)) { GET_INSTANCE_PROC(CreateImagePipeSurfaceFUCHSIA); } #endif // defined(VK_USE_PLATFORM_FUCHSIA) #if defined(DAWN_ENABLE_BACKEND_METAL) - if (globalInfo.metalSurface) { + if (globalInfo.HasExt(InstanceExt::MetalSurface)) { GET_INSTANCE_PROC(CreateMetalSurfaceEXT); } #endif // defined(DAWN_ENABLE_BACKEND_METAL) #if defined(DAWN_PLATFORM_WINDOWS) - if (globalInfo.win32Surface) { + if (globalInfo.HasExt(InstanceExt::Win32Surface)) { GET_INSTANCE_PROC(CreateWin32SurfaceKHR); GET_INSTANCE_PROC(GetPhysicalDeviceWin32PresentationSupportKHR); } #endif // defined(DAWN_PLATFORM_WINDOWS) #if defined(DAWN_USE_X11) - if (globalInfo.xlibSurface) { + if (globalInfo.HasExt(InstanceExt::XlibSurface)) { GET_INSTANCE_PROC(CreateXlibSurfaceKHR); GET_INSTANCE_PROC(GetPhysicalDeviceXlibPresentationSupportKHR); } diff --git a/src/dawn_native/vulkan/VulkanInfo.cpp b/src/dawn_native/vulkan/VulkanInfo.cpp index b2d99289af..e713ba6cb4 100644 --- a/src/dawn_native/vulkan/VulkanInfo.cpp +++ b/src/dawn_native/vulkan/VulkanInfo.cpp @@ -55,8 +55,6 @@ namespace dawn_native { namespace vulkan { const char kLayerNameFuchsiaImagePipeSwapchain[] = "VK_LAYER_FUCHSIA_imagepipe_swapchain"; const char kExtensionNameExtDebugMarker[] = "VK_EXT_debug_marker"; - const char kExtensionNameExtDebugReport[] = "VK_EXT_debug_report"; - const char kExtensionNameExtMetalSurface[] = "VK_EXT_metal_surface"; const char kExtensionNameKhrExternalMemory[] = "VK_KHR_external_memory"; const char kExtensionNameKhrExternalMemoryCapabilities[] = "VK_KHR_external_memory_capabilities"; @@ -71,21 +69,32 @@ namespace dawn_native { namespace vulkan { const char kExtensionNameFuchsiaExternalSemaphore[] = "VK_FUCHSIA_external_semaphore"; const char kExtensionNameKhrGetPhysicalDeviceProperties2[] = "VK_KHR_get_physical_device_properties2"; - const char kExtensionNameKhrSurface[] = "VK_KHR_surface"; const char kExtensionNameKhrSwapchain[] = "VK_KHR_swapchain"; - const char kExtensionNameKhrWaylandSurface[] = "VK_KHR_wayland_surface"; - const char kExtensionNameKhrWin32Surface[] = "VK_KHR_win32_surface"; - const char kExtensionNameKhrXcbSurface[] = "VK_KHR_xcb_surface"; - const char kExtensionNameKhrXlibSurface[] = "VK_KHR_xlib_surface"; - const char kExtensionNameFuchsiaImagePipeSurface[] = "VK_FUCHSIA_imagepipe_surface"; const char kExtensionNameKhrMaintenance1[] = "VK_KHR_maintenance1"; const char kExtensionNameKhrShaderFloat16Int8[] = "VK_KHR_shader_float16_int8"; const char kExtensionNameKhr16BitStorage[] = "VK_KHR_16bit_storage"; + bool VulkanGlobalKnobs::HasExt(InstanceExt ext) const { + return extensions.Has(ext); + } + ResultOrError GatherGlobalInfo(const Backend& backend) { VulkanGlobalInfo info = {}; const VulkanFunctions& vkFunctions = backend.GetFunctions(); + // Gather info on available API version + { + uint32_t supportedAPIVersion = VK_MAKE_VERSION(1, 0, 0); + if (vkFunctions.EnumerateInstanceVersion) { + vkFunctions.EnumerateInstanceVersion(&supportedAPIVersion); + } + + // Use Vulkan 1.1 if it's available. + info.apiVersion = (supportedAPIVersion >= VK_MAKE_VERSION(1, 1, 0)) + ? VK_MAKE_VERSION(1, 1, 0) + : VK_MAKE_VERSION(1, 0, 0); + } + // Gather the info about the instance layers { uint32_t count = 0; @@ -124,76 +133,40 @@ namespace dawn_native { namespace vulkan { // Gather the info about the instance extensions { - if (!EnumerateInstanceExtensions(nullptr, vkFunctions, &info.extensions)) { + std::unordered_map knownExts = CreateInstanceExtNameMap(); + + std::vector extensionsProperties; + if (!EnumerateInstanceExtensions(nullptr, vkFunctions, &extensionsProperties)) { return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties"); } - for (const auto& extension : info.extensions) { - if (IsExtensionName(extension, kExtensionNameExtDebugReport)) { - info.debugReport = true; - } - if (IsExtensionName(extension, kExtensionNameExtMetalSurface)) { - info.metalSurface = true; - } - if (IsExtensionName(extension, kExtensionNameKhrExternalMemoryCapabilities)) { - info.externalMemoryCapabilities = true; - } - if (IsExtensionName(extension, kExtensionNameKhrExternalSemaphoreCapabilities)) { - info.externalSemaphoreCapabilities = true; - } - if (IsExtensionName(extension, kExtensionNameKhrGetPhysicalDeviceProperties2)) { - info.getPhysicalDeviceProperties2 = true; - } - if (IsExtensionName(extension, kExtensionNameKhrSurface)) { - info.surface = true; - } - if (IsExtensionName(extension, kExtensionNameKhrWaylandSurface)) { - info.waylandSurface = true; - } - if (IsExtensionName(extension, kExtensionNameKhrWin32Surface)) { - info.win32Surface = true; - } - if (IsExtensionName(extension, kExtensionNameKhrXcbSurface)) { - info.xcbSurface = true; - } - if (IsExtensionName(extension, kExtensionNameKhrXlibSurface)) { - info.xlibSurface = true; - } - if (IsExtensionName(extension, kExtensionNameFuchsiaImagePipeSurface)) { - info.fuchsiaImagePipeSurface = true; + for (const VkExtensionProperties& extension : extensionsProperties) { + auto it = knownExts.find(extension.extensionName); + if (it != knownExts.end()) { + info.extensions.Set(it->second, true); } } - } - // Specific handling for the Fuchsia swapchain surface creation extension - // which is normally part of the Fuchsia-specific swapchain layer. - if (info.fuchsiaImagePipeSwapchain && !info.fuchsiaImagePipeSurface) { - std::vector layer_extensions; - if (!EnumerateInstanceExtensions(kLayerNameFuchsiaImagePipeSwapchain, vkFunctions, - &layer_extensions)) { - return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties"); - } + // Specific handling for the Fuchsia swapchain surface creation extension + // which is normally part of the Fuchsia-specific swapchain layer. + if (info.fuchsiaImagePipeSwapchain && + !info.HasExt(InstanceExt::FuchsiaImagePipeSurface)) { + if (!EnumerateInstanceExtensions(kLayerNameFuchsiaImagePipeSwapchain, vkFunctions, + &extensionsProperties)) { + return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties"); + } - for (const auto& extension : layer_extensions) { - if (IsExtensionName(extension, kExtensionNameFuchsiaImagePipeSurface)) { - info.fuchsiaImagePipeSurface = true; - // For now, copy this to the global extension list. - info.extensions.push_back(extension); + for (const VkExtensionProperties& extension : extensionsProperties) { + auto it = knownExts.find(extension.extensionName); + if (it != knownExts.end() && + it->second == InstanceExt::FuchsiaImagePipeSurface) { + info.extensions.Set(InstanceExt::FuchsiaImagePipeSurface, true); + } } } - } - // Gather info on available API version - { - uint32_t supportedAPIVersion = VK_MAKE_VERSION(1, 0, 0); - if (vkFunctions.EnumerateInstanceVersion) { - vkFunctions.EnumerateInstanceVersion(&supportedAPIVersion); - } - - // Use Vulkan 1.1 if it's available. - info.apiVersion = (supportedAPIVersion >= VK_MAKE_VERSION(1, 1, 0)) - ? VK_MAKE_VERSION(1, 1, 0) - : VK_MAKE_VERSION(1, 0, 0); + MarkPromotedExtensions(&info.extensions, info.apiVersion); + info.extensions = EnsureDependencies(info.extensions); } // TODO(cwallez@chromium:org): Each layer can expose additional extensions, query them? @@ -315,7 +288,7 @@ namespace dawn_native { namespace vulkan { info.maintenance1 = true; } if (IsExtensionName(extension, kExtensionNameKhrShaderFloat16Int8) && - globalInfo.getPhysicalDeviceProperties2) { + globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2)) { info.shaderFloat16Int8 = true; info.shaderFloat16Int8Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; @@ -328,7 +301,7 @@ namespace dawn_native { namespace vulkan { &physicalDeviceFeatures2); } if (IsExtensionName(extension, kExtensionNameKhr16BitStorage) && - globalInfo.getPhysicalDeviceProperties2) { + globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2)) { info._16BitStorage = true; } } @@ -342,7 +315,7 @@ namespace dawn_native { namespace vulkan { // VK_KHR_16bit_storage is promoted to Vulkan 1.1, so gather information if either is // present, and mark the extension as available. if (info._16BitStorage || info.properties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - ASSERT(globalInfo.getPhysicalDeviceProperties2); + ASSERT(globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2)); info._16BitStorage = true; info._16BitStorageFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; diff --git a/src/dawn_native/vulkan/VulkanInfo.h b/src/dawn_native/vulkan/VulkanInfo.h index 81ef0549da..a9d081822a 100644 --- a/src/dawn_native/vulkan/VulkanInfo.h +++ b/src/dawn_native/vulkan/VulkanInfo.h @@ -17,6 +17,7 @@ #include "common/vulkan_platform.h" #include "dawn_native/Error.h" +#include "dawn_native/vulkan/VulkanExtensions.h" #include @@ -31,8 +32,6 @@ namespace dawn_native { namespace vulkan { extern const char kLayerNameFuchsiaImagePipeSwapchain[]; extern const char kExtensionNameExtDebugMarker[]; - extern const char kExtensionNameExtDebugReport[]; - extern const char kExtensionNameExtMetalSurface[]; extern const char kExtensionNameKhrExternalMemory[]; extern const char kExtensionNameKhrExternalMemoryCapabilities[]; extern const char kExtensionNameKhrExternalMemoryFD[]; @@ -44,13 +43,7 @@ namespace dawn_native { namespace vulkan { extern const char kExtensionNameKhrExternalSemaphoreFD[]; extern const char kExtensionNameFuchsiaExternalSemaphore[]; extern const char kExtensionNameKhrGetPhysicalDeviceProperties2[]; - extern const char kExtensionNameKhrSurface[]; extern const char kExtensionNameKhrSwapchain[]; - extern const char kExtensionNameKhrWaylandSurface[]; - extern const char kExtensionNameKhrWin32Surface[]; - extern const char kExtensionNameKhrXcbSurface[]; - extern const char kExtensionNameKhrXlibSurface[]; - extern const char kExtensionNameFuchsiaImagePipeSurface[]; extern const char kExtensionNameKhrMaintenance1[]; extern const char kExtensionNameKhrShaderFloat16Int8[]; extern const char kExtensionNameKhr16BitStorage[]; @@ -63,23 +56,12 @@ namespace dawn_native { namespace vulkan { bool renderDocCapture = false; bool fuchsiaImagePipeSwapchain = false; - // Extensions - bool debugReport = false; - bool externalMemoryCapabilities = false; - bool externalSemaphoreCapabilities = false; - bool getPhysicalDeviceProperties2 = false; - bool metalSurface = false; - bool surface = false; - bool waylandSurface = false; - bool win32Surface = false; - bool xcbSurface = false; - bool xlibSurface = false; - bool fuchsiaImagePipeSurface = false; + bool HasExt(InstanceExt ext) const; + InstanceExtSet extensions; }; struct VulkanGlobalInfo : VulkanGlobalKnobs { std::vector layers; - std::vector extensions; uint32_t apiVersion; // TODO(cwallez@chromium.org): layer instance extensions }; diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp index 35c7a078dd..c521ed1ad3 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp @@ -64,8 +64,8 @@ namespace dawn_native { namespace vulkan { namespace external_memory { const VulkanGlobalInfo& globalInfo = ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); - mSupported = globalInfo.getPhysicalDeviceProperties2 && - globalInfo.externalMemoryCapabilities && deviceInfo.externalMemory && + mSupported = globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2 && + globalInfo.HasExt(InstanceExt::ExternalMemoryCapabilities) && deviceInfo.externalMemory && deviceInfo.externalMemoryFD && deviceInfo.externalMemoryDmaBuf && deviceInfo.imageDrmFormatModifier; } diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp index 872432410a..57b74af22c 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp @@ -27,9 +27,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory { const VulkanGlobalInfo& globalInfo = ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); - mSupported = globalInfo.getPhysicalDeviceProperties2 && - globalInfo.externalMemoryCapabilities && deviceInfo.externalMemory && - deviceInfo.externalMemoryFD; + mSupported = globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2) && + globalInfo.HasExt(InstanceExt::ExternalMemoryCapabilities) && + deviceInfo.externalMemory && deviceInfo.externalMemoryFD; } Service::~Service() = default; diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp index 10b99555e5..ab87a7f848 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp @@ -27,9 +27,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory { const VulkanGlobalInfo& globalInfo = ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); - mSupported = globalInfo.getPhysicalDeviceProperties2 && - globalInfo.externalMemoryCapabilities && deviceInfo.externalMemory && - deviceInfo.externalMemoryFD; + mSupported = globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2) && + globalInfo.HasExt(InstanceExt::ExternalMemoryCapabilities) && + deviceInfo.externalMemory && deviceInfo.externalMemoryFD; } Service::~Service() = default; diff --git a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp index e79288a996..222fcbbaaf 100644 --- a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp +++ b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp @@ -25,9 +25,9 @@ namespace dawn_native { namespace vulkan { namespace external_semaphore { const VulkanGlobalInfo& globalInfo = ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); - mSupported = globalInfo.getPhysicalDeviceProperties2 && - globalInfo.externalSemaphoreCapabilities && deviceInfo.externalSemaphore && - deviceInfo.externalSemaphoreFD; + mSupported = globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2) && + globalInfo.HasExt(InstanceExt::ExternalSemaphoreCapabilities) && + deviceInfo.externalSemaphore && deviceInfo.externalSemaphoreFD; // Early out before we try using extension functions if (!mSupported) { diff --git a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp index fd10076e9e..985cf4f221 100644 --- a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp +++ b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp @@ -25,9 +25,9 @@ namespace dawn_native { namespace vulkan { namespace external_semaphore { const VulkanGlobalInfo& globalInfo = ToBackend(mDevice->GetAdapter())->GetBackend()->GetGlobalInfo(); - mSupported = globalInfo.getPhysicalDeviceProperties2 && - globalInfo.externalSemaphoreCapabilities && deviceInfo.externalSemaphore && - deviceInfo.externalSemaphoreFD; + mSupported = globalInfo.HasExt(InstanceExt::GetPhysicalDeviceProperties2) && + globalInfo.HasExt(InstanceExt::ExternalSemaphoreCapabilities) && + deviceInfo.externalSemaphore && deviceInfo.externalSemaphoreFD; // Early out before we try using extension functions if (!mSupported) {