diff --git a/src/dawn_native/vulkan/BackendVk.cpp b/src/dawn_native/vulkan/BackendVk.cpp index 254382812c..6e431f15a6 100644 --- a/src/dawn_native/vulkan/BackendVk.cpp +++ b/src/dawn_native/vulkan/BackendVk.cpp @@ -206,37 +206,39 @@ namespace dawn_native { namespace vulkan { ResultOrError Backend::CreateInstance() { VulkanGlobalKnobs usedKnobs = {}; std::vector layerNames; + InstanceExtSet extensionsToRequest = mGlobalInfo.extensions; - // vktrace works by instering a layer, but we hide it behind a macro due to the vktrace + auto UseLayerIfAvailable = [&](VulkanLayer layer) { + if (mGlobalInfo.layers[layer]) { + layerNames.push_back(GetVulkanLayerInfo(layer).name); + usedKnobs.layers.set(layer, true); + extensionsToRequest |= mGlobalInfo.layerExtensions[layer]; + } + }; + + // vktrace works by instering a layer, but we hide it behind a macro because the vktrace // layer crashes when used without vktrace server started. See this vktrace issue: // https://github.com/LunarG/VulkanTools/issues/254 // Also it is good to put it in first position so that it doesn't see Vulkan calls inserted // by other layers. #if defined(DAWN_USE_VKTRACE) - if (mGlobalInfo.vktrace) { - layerNames.push_back(kLayerNameLunargVKTrace); - usedKnobs.vktrace = true; - } + UseLayerIfAvailable(VulkanLayer::LunargVkTrace); #endif // RenderDoc installs a layer at the system level for its capture but we don't want to use // it unless we are debugging in RenderDoc so we hide it behind a macro. #if defined(DAWN_USE_RENDERDOC) - if (mGlobalInfo.renderDocCapture) { - layerNames.push_back(kLayerNameRenderDocCapture); - usedKnobs.renderDocCapture = true; - } + UseLayerIfAvailable(VulkanLayer::RenderDocCapture); #endif if (GetInstance()->IsBackendValidationEnabled()) { - if (mGlobalInfo.validation) { - layerNames.push_back(kLayerNameKhronosValidation); - usedKnobs.validation = true; - } + UseLayerIfAvailable(VulkanLayer::Validation); } + // Always use the Fuchsia swapchain layer if available. + UseLayerIfAvailable(VulkanLayer::FuchsiaImagePipeSwapchain); + // Available and known instance extensions default to being requested, but some special // cases are removed. - InstanceExtSet extensionsToRequest = mGlobalInfo.extensions; usedKnobs.extensions = extensionsToRequest; std::vector extensionNames; @@ -282,7 +284,7 @@ namespace dawn_native { namespace vulkan { // Register the debug callback for instance creation so we receive message for any errors // (validation or other). VkDebugUtilsMessengerCreateInfoEXT utilsMessengerCreateInfo; - if (mGlobalInfo.HasExt(InstanceExt::DebugUtils)) { + if (usedKnobs.HasExt(InstanceExt::DebugUtils)) { utilsMessengerCreateInfo.flags = 0; utilsMessengerCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | diff --git a/src/dawn_native/vulkan/VulkanExtensions.cpp b/src/dawn_native/vulkan/VulkanExtensions.cpp index 05a8d6092d..4c07d69f99 100644 --- a/src/dawn_native/vulkan/VulkanExtensions.cpp +++ b/src/dawn_native/vulkan/VulkanExtensions.cpp @@ -293,4 +293,32 @@ namespace dawn_native { namespace vulkan { } } + // A static array for VulkanLayerInfo that can be indexed with VulkanLayers. + // GetVulkanLayerInfo 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 kVulkanLayerCount = static_cast(VulkanLayer::EnumCount); + static constexpr std::array sVulkanLayerInfos{{ + // + {VulkanLayer::Validation, "VK_LAYER_KHRONOS_validation"}, + {VulkanLayer::LunargVkTrace, "VK_LAYER_LUNARG_vktrace"}, + {VulkanLayer::RenderDocCapture, "VK_LAYER_RENDERDOC_Capture"}, + {VulkanLayer::FuchsiaImagePipeSwapchain, "VK_LAYER_FUCHSIA_imagepipe_swapchain"}, + // + }}; + + const VulkanLayerInfo& GetVulkanLayerInfo(VulkanLayer layer) { + uint32_t index = static_cast(layer); + ASSERT(index < sVulkanLayerInfos.size()); + ASSERT(sVulkanLayerInfos[index].layer == layer); + return sVulkanLayerInfos[index]; + } + + std::unordered_map CreateVulkanLayerNameMap() { + std::unordered_map result; + for (const VulkanLayerInfo& info : sVulkanLayerInfos) { + result[info.name] = info.layer; + } + return result; + } + }} // namespace dawn_native::vulkan diff --git a/src/dawn_native/vulkan/VulkanExtensions.h b/src/dawn_native/vulkan/VulkanExtensions.h index d3950f1451..91af192e21 100644 --- a/src/dawn_native/vulkan/VulkanExtensions.h +++ b/src/dawn_native/vulkan/VulkanExtensions.h @@ -129,6 +129,33 @@ namespace dawn_native { namespace vulkan { const InstanceExtSet& instanceExts, uint32_t icdVersion); + // The list of all known Vulkan layers. + enum class VulkanLayer { + Validation, + LunargVkTrace, + RenderDocCapture, + + // Fuchsia implements the swapchain through a layer (VK_LAYER_FUCHSIA_image_pipe_swapchain), + // which adds an instance extensions (VK_FUCHSIA_image_surface) to all ICDs. + FuchsiaImagePipeSwapchain, + + EnumCount, + }; + + // A bitset that is indexed with VulkanLayer. + using VulkanLayerSet = ityp::bitset(VulkanLayer::EnumCount)>; + + // Information about a known layer + struct VulkanLayerInfo { + VulkanLayer layer; + const char* name; + }; + + // Returns the information about a known VulkanLayer + const VulkanLayerInfo& GetVulkanLayerInfo(VulkanLayer layer); + // Returns a map that maps a Vulkan layer name to its VulkanLayer. + std::unordered_map CreateVulkanLayerNameMap(); + }} // namespace dawn_native::vulkan #endif // DAWNNATIVE_VULKAN_VULKANEXTENSIONS_H_ diff --git a/src/dawn_native/vulkan/VulkanInfo.cpp b/src/dawn_native/vulkan/VulkanInfo.cpp index 365ffa7d4b..9ca7634c51 100644 --- a/src/dawn_native/vulkan/VulkanInfo.cpp +++ b/src/dawn_native/vulkan/VulkanInfo.cpp @@ -14,7 +14,6 @@ #include "dawn_native/vulkan/VulkanInfo.h" -#include "common/Log.h" #include "dawn_native/vulkan/AdapterVk.h" #include "dawn_native/vulkan/BackendVk.h" #include "dawn_native/vulkan/UtilsVulkan.h" @@ -25,32 +24,35 @@ namespace dawn_native { namespace vulkan { namespace { - bool IsLayerName(const VkLayerProperties& layer, const char* name) { - return strncmp(layer.layerName, name, VK_MAX_EXTENSION_NAME_SIZE) == 0; - } - - bool EnumerateInstanceExtensions(const char* layerName, - const dawn_native::vulkan::VulkanFunctions& vkFunctions, - std::vector* extensions) { + ResultOrError GatherInstanceExtensions( + const char* layerName, + const dawn_native::vulkan::VulkanFunctions& vkFunctions, + const std::unordered_map& knownExts) { uint32_t count = 0; - VkResult result = VkResult::WrapUnsafe( + VkResult vkResult = VkResult::WrapUnsafe( vkFunctions.EnumerateInstanceExtensionProperties(layerName, &count, nullptr)); - if (result != VK_SUCCESS && result != VK_INCOMPLETE) { - return false; + if (vkResult != VK_SUCCESS && vkResult != VK_INCOMPLETE) { + return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties"); } - extensions->resize(count); - result = VkResult::WrapUnsafe(vkFunctions.EnumerateInstanceExtensionProperties( - layerName, &count, extensions->data())); - return (result == VK_SUCCESS); + + std::vector extensions(count); + DAWN_TRY(CheckVkSuccess(vkFunctions.EnumerateInstanceExtensionProperties( + layerName, &count, extensions.data()), + "vkEnumerateInstanceExtensionProperties")); + + InstanceExtSet result; + for (const VkExtensionProperties& extension : extensions) { + auto it = knownExts.find(extension.extensionName); + if (it != knownExts.end()) { + result.set(it->second, true); + } + } + + return result; } } // namespace - const char kLayerNameKhronosValidation[] = "VK_LAYER_KHRONOS_validation"; - const char kLayerNameLunargVKTrace[] = "VK_LAYER_LUNARG_vktrace"; - const char kLayerNameRenderDocCapture[] = "VK_LAYER_RENDERDOC_Capture"; - const char kLayerNameFuchsiaImagePipeSwapchain[] = "VK_LAYER_FUCHSIA_imagepipe_swapchain"; - bool VulkanGlobalKnobs::HasExt(InstanceExt ext) const { return extensions[ext]; } @@ -88,26 +90,16 @@ namespace dawn_native { namespace vulkan { return DAWN_INTERNAL_ERROR("vkEnumerateInstanceLayerProperties"); } - info.layers.resize(count); + std::vector layersProperties(count); DAWN_TRY(CheckVkSuccess( - vkFunctions.EnumerateInstanceLayerProperties(&count, info.layers.data()), + vkFunctions.EnumerateInstanceLayerProperties(&count, layersProperties.data()), "vkEnumerateInstanceLayerProperties")); - for (const auto& layer : info.layers) { - if (IsLayerName(layer, kLayerNameKhronosValidation)) { - info.validation = true; - } - if (IsLayerName(layer, kLayerNameLunargVKTrace)) { - info.vktrace = true; - } - if (IsLayerName(layer, kLayerNameRenderDocCapture)) { - info.renderDocCapture = true; - } - // Technical note: Fuchsia implements the swapchain through - // a layer (VK_LAYER_FUCHSIA_image_pipe_swapchain), which adds - // an instance extensions (VK_FUCHSIA_image_surface) to all ICDs. - if (IsLayerName(layer, kLayerNameFuchsiaImagePipeSwapchain)) { - info.fuchsiaImagePipeSwapchain = true; + std::unordered_map knownLayers = CreateVulkanLayerNameMap(); + for (const VkLayerProperties& layer : layersProperties) { + auto it = knownLayers.find(layer.layerName); + if (it != knownLayers.end()) { + info.layers.set(it->second, true); } } } @@ -116,41 +108,19 @@ namespace dawn_native { namespace vulkan { { std::unordered_map knownExts = CreateInstanceExtNameMap(); - std::vector extensionsProperties; - if (!EnumerateInstanceExtensions(nullptr, vkFunctions, &extensionsProperties)) { - return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties"); - } - - 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.HasExt(InstanceExt::FuchsiaImagePipeSurface)) { - if (!EnumerateInstanceExtensions(kLayerNameFuchsiaImagePipeSwapchain, vkFunctions, - &extensionsProperties)) { - return DAWN_INTERNAL_ERROR("vkEnumerateInstanceExtensionProperties"); - } - - 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); - } - } - } - + DAWN_TRY_ASSIGN(info.extensions, + GatherInstanceExtensions(nullptr, vkFunctions, knownExts)); MarkPromotedExtensions(&info.extensions, info.apiVersion); info.extensions = EnsureDependencies(info.extensions); - } - // TODO(cwallez@chromium:org): Each layer can expose additional extensions, query them? + for (VulkanLayer layer : IterateBitSet(info.layers)) { + DAWN_TRY_ASSIGN(info.layerExtensions[layer], + GatherInstanceExtensions(GetVulkanLayerInfo(layer).name, + vkFunctions, knownExts)); + MarkPromotedExtensions(&info.layerExtensions[layer], info.apiVersion); + info.layerExtensions[layer] = EnsureDependencies(info.layerExtensions[layer]); + } + } return std::move(info); } diff --git a/src/dawn_native/vulkan/VulkanInfo.h b/src/dawn_native/vulkan/VulkanInfo.h index 0e0b717ec2..4e7990ed71 100644 --- a/src/dawn_native/vulkan/VulkanInfo.h +++ b/src/dawn_native/vulkan/VulkanInfo.h @@ -15,6 +15,7 @@ #ifndef DAWNNATIVE_VULKAN_VULKANINFO_H_ #define DAWNNATIVE_VULKAN_VULKANINFO_H_ +#include "common/ityp_array.h" #include "common/vulkan_platform.h" #include "dawn_native/Error.h" #include "dawn_native/vulkan/VulkanExtensions.h" @@ -26,27 +27,22 @@ namespace dawn_native { namespace vulkan { class Adapter; class Backend; - extern const char kLayerNameKhronosValidation[]; - extern const char kLayerNameLunargVKTrace[]; - extern const char kLayerNameRenderDocCapture[]; - extern const char kLayerNameFuchsiaImagePipeSwapchain[]; - // Global information - gathered before the instance is created struct VulkanGlobalKnobs { - // Layers - bool validation = false; - bool vktrace = false; - bool renderDocCapture = false; - bool fuchsiaImagePipeSwapchain = false; + bool HasLayer(VulkanLayer layer) const; + VulkanLayerSet layers; + ityp::array(VulkanLayer::EnumCount)> + layerExtensions; - bool HasExt(InstanceExt ext) const; + // During information gathering `extensions` only contains the instance's extensions but + // during the instance creation logic it becomes the OR of the instance's extensions and + // the selected layers' extensions. InstanceExtSet extensions; + bool HasExt(InstanceExt ext) const; }; struct VulkanGlobalInfo : VulkanGlobalKnobs { - std::vector layers; uint32_t apiVersion; - // TODO(cwallez@chromium.org): layer instance extensions }; // Device information - gathered before the device is created.