Vulkan: Add support for layer extensions.

This commit generalizes the way layers are handled to be more like
extensions, and adds support for gathering and enabling layer
extensions.

This is in preparation for using the VK_EXT_validation_features
extension to enable barrier validation.

Also adds logic to use the Fuchsia swapchain layer when it is available.
It seems to have been removed by mistake some time ago.

Bug: dawn:635

Change-Id: I8e5776d546ddd7940238465c7b0f187d8dd3c5bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38104
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez 2021-01-21 13:47:19 +00:00 committed by Commit Bot service account
parent e10e6b0db8
commit 2231fcda56
5 changed files with 120 additions and 97 deletions

View File

@ -206,37 +206,39 @@ namespace dawn_native { namespace vulkan {
ResultOrError<VulkanGlobalKnobs> Backend::CreateInstance() {
VulkanGlobalKnobs usedKnobs = {};
std::vector<const char*> 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<const char*> 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 |

View File

@ -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<size_t>(VulkanLayer::EnumCount);
static constexpr std::array<VulkanLayerInfo, kVulkanLayerCount> 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<uint32_t>(layer);
ASSERT(index < sVulkanLayerInfos.size());
ASSERT(sVulkanLayerInfos[index].layer == layer);
return sVulkanLayerInfos[index];
}
std::unordered_map<std::string, VulkanLayer> CreateVulkanLayerNameMap() {
std::unordered_map<std::string, VulkanLayer> result;
for (const VulkanLayerInfo& info : sVulkanLayerInfos) {
result[info.name] = info.layer;
}
return result;
}
}} // namespace dawn_native::vulkan

View File

@ -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, static_cast<uint32_t>(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<std::string, VulkanLayer> CreateVulkanLayerNameMap();
}} // namespace dawn_native::vulkan
#endif // DAWNNATIVE_VULKAN_VULKANEXTENSIONS_H_

View File

@ -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<VkExtensionProperties>* extensions) {
ResultOrError<InstanceExtSet> GatherInstanceExtensions(
const char* layerName,
const dawn_native::vulkan::VulkanFunctions& vkFunctions,
const std::unordered_map<std::string, InstanceExt>& 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<VkExtensionProperties> 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<VkLayerProperties> 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<std::string, VulkanLayer> 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<std::string, InstanceExt> knownExts = CreateInstanceExtNameMap();
std::vector<VkExtensionProperties> 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);
}

View File

@ -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, InstanceExtSet, static_cast<uint32_t>(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<VkLayerProperties> layers;
uint32_t apiVersion;
// TODO(cwallez@chromium.org): layer instance extensions
};
// Device information - gathered before the device is created.