Vulkan: Properly handle Device extension dependencies

The checks for dependencies of Device extensions were incomplete, makes
sure the transitive dependencies of the extensions we care about are all
known so they can participate in the dependency check.

Also removes a workaround for surprising Vulkan behavior with instance
extensions getting promoted as device functions. This should be handled
correctly now as DeviceExt contains the physical device extensions as
well.

Bug: dawn:457

Change-Id: I4b79729d809c9edfedcb075a0e6aa5b4dd473ab3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22942
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez 2020-06-12 08:19:31 +00:00 committed by Commit Bot service account
parent 9435068a36
commit 5c9f7af77d
3 changed files with 68 additions and 39 deletions

View File

@ -210,22 +210,18 @@ namespace dawn_native { namespace vulkan {
// cases are removed. // cases are removed.
InstanceExtSet extensionsToRequest = mGlobalInfo.extensions; 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()) { if (!GetInstance()->IsBackendValidationEnabled()) {
extensionsToRequest.Set(InstanceExt::DebugReport, false); extensionsToRequest.Set(InstanceExt::DebugReport, false);
} }
usedKnobs.extensions = extensionsToRequest; usedKnobs.extensions = extensionsToRequest;
std::vector<const char*> extensionNames; std::vector<const char*> extensionNames;
for (uint32_t ext : IterateBitSet(extensionsToRequest.extensionBitSet)) { for (uint32_t ext : IterateBitSet(extensionsToRequest.extensionBitSet)) {
extensionNames.push_back(GetInstanceExtInfo(static_cast<InstanceExt>(ext)).name); const InstanceExtInfo& info = GetInstanceExtInfo(static_cast<InstanceExt>(ext));
if (info.versionPromoted > mGlobalInfo.apiVersion) {
extensionNames.push_back(info.name);
}
} }
VkApplicationInfo appInfo; VkApplicationInfo appInfo;

View File

@ -136,11 +136,23 @@ namespace dawn_native { namespace vulkan {
static constexpr size_t kDeviceExtCount = static_cast<size_t>(DeviceExt::EnumCount); static constexpr size_t kDeviceExtCount = static_cast<size_t>(DeviceExt::EnumCount);
static constexpr std::array<DeviceExtInfo, kDeviceExtCount> sDeviceExtInfos{{ static constexpr std::array<DeviceExtInfo, kDeviceExtCount> sDeviceExtInfos{{
// //
{DeviceExt::BindMemory2, "VK_KHR_bind_memory2", VulkanVersion_1_1},
{DeviceExt::Maintenance1, "VK_KHR_maintenance1", VulkanVersion_1_1}, {DeviceExt::Maintenance1, "VK_KHR_maintenance1", VulkanVersion_1_1},
{DeviceExt::StorageBufferStorageClass, "VK_KHR_storage_buffer_storage_class",
VulkanVersion_1_1},
{DeviceExt::GetPhysicalDeviceProperties2, "VK_KHR_get_physical_device_properties2",
VulkanVersion_1_1},
{DeviceExt::GetMemoryRequirements2, "VK_KHR_get_memory_requirements2", VulkanVersion_1_1},
{DeviceExt::ExternalMemoryCapabilities, "VK_KHR_external_memory_capabilities",
VulkanVersion_1_1},
{DeviceExt::ExternalSemaphoreCapabilities, "VK_KHR_external_semaphore_capabilities",
VulkanVersion_1_1},
{DeviceExt::ExternalMemory, "VK_KHR_external_memory", VulkanVersion_1_1}, {DeviceExt::ExternalMemory, "VK_KHR_external_memory", VulkanVersion_1_1},
{DeviceExt::ExternalSemaphore, "VK_KHR_external_semaphore", VulkanVersion_1_1}, {DeviceExt::ExternalSemaphore, "VK_KHR_external_semaphore", VulkanVersion_1_1},
{DeviceExt::_16BitStorage, "VK_KHR_16bit_storage", VulkanVersion_1_1}, {DeviceExt::_16BitStorage, "VK_KHR_16bit_storage", VulkanVersion_1_1},
{DeviceExt::SamplerYCbCrConversion, "VK_KHR_sampler_ycbcr_conversion", VulkanVersion_1_1},
{DeviceExt::ImageFormatList, "VK_KHR_image_format_list", VulkanVersion_1_2},
{DeviceExt::ShaderFloat16Int8, "VK_KHR_shader_float16_int8", VulkanVersion_1_2}, {DeviceExt::ShaderFloat16Int8, "VK_KHR_shader_float16_int8", VulkanVersion_1_2},
{DeviceExt::ExternalMemoryFD, "VK_KHR_external_memory_fd", NeverPromoted}, {DeviceExt::ExternalMemoryFD, "VK_KHR_external_memory_fd", NeverPromoted},
@ -195,6 +207,32 @@ namespace dawn_native { namespace vulkan {
bool hasDependencies = false; bool hasDependencies = false;
switch (ext) { switch (ext) {
// Happy extensions don't need anybody else!
case DeviceExt::BindMemory2:
case DeviceExt::GetMemoryRequirements2:
case DeviceExt::Maintenance1:
case DeviceExt::ImageFormatList:
case DeviceExt::StorageBufferStorageClass:
hasDependencies = true;
break;
// Physical device extensions technically don't require the instance to support
// them but VulkanFunctions only loads the function pointers if the instance
// advertises the extension. So if we didn't have this check, we'd risk a calling
// a nullptr.
case DeviceExt::GetPhysicalDeviceProperties2:
hasDependencies = instanceExts.Has(InstanceExt::GetPhysicalDeviceProperties2);
break;
case DeviceExt::ExternalMemoryCapabilities:
hasDependencies = instanceExts.Has(InstanceExt::ExternalMemoryCapabilities) &&
HasDep(DeviceExt::GetPhysicalDeviceProperties2);
break;
case DeviceExt::ExternalSemaphoreCapabilities:
hasDependencies =
instanceExts.Has(InstanceExt::ExternalSemaphoreCapabilities) &&
HasDep(DeviceExt::GetPhysicalDeviceProperties2);
break;
case DeviceExt::DebugMarker: case DeviceExt::DebugMarker:
// TODO(cwallez@chromium.org): VK_KHR_debug_report is deprecated, switch to // TODO(cwallez@chromium.org): VK_KHR_debug_report is deprecated, switch to
// using VK_KHR_debug_utils instead. // using VK_KHR_debug_utils instead.
@ -202,51 +240,33 @@ namespace dawn_native { namespace vulkan {
break; break;
case DeviceExt::ImageDrmFormatModifier: case DeviceExt::ImageDrmFormatModifier:
// TODO(cwallez@chromium.org): ImageDrmFormatModifier actually requires: hasDependencies = HasDep(DeviceExt::BindMemory2) &&
// - VK_KHR_bind_memory2 HasDep(DeviceExt::GetPhysicalDeviceProperties2) &&
// - VK_KHR_image_format_list HasDep(DeviceExt::ImageFormatList) &&
// - VK_KHR_sampler_ycbcr_conversion HasDep(DeviceExt::SamplerYCbCrConversion);
//
// Also switch to using DeviceExt::GetPhysicalDeviceProperties2 when we decouple
// Instance / Device physical device extensions.
hasDependencies = instanceExts.Has(InstanceExt::GetPhysicalDeviceProperties2);
break; break;
case DeviceExt::Swapchain: case DeviceExt::Swapchain:
hasDependencies = instanceExts.Has(InstanceExt::Surface); hasDependencies = instanceExts.Has(InstanceExt::Surface);
break; break;
case DeviceExt::Maintenance1: case DeviceExt::SamplerYCbCrConversion:
hasDependencies = true; hasDependencies = HasDep(DeviceExt::Maintenance1) &&
HasDep(DeviceExt::BindMemory2) &&
HasDep(DeviceExt::GetMemoryRequirements2) &&
HasDep(DeviceExt::GetPhysicalDeviceProperties2);
break; break;
case DeviceExt::ShaderFloat16Int8: case DeviceExt::ShaderFloat16Int8:
// TODO(cwallez@chromium.org): switch to using hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2);
// DeviceExt::GetPhysicalDeviceProperties2 when we decouple Instance / Device
// physical device extensions.
hasDependencies = instanceExts.Has(InstanceExt::GetPhysicalDeviceProperties2);
break; break;
case DeviceExt::ExternalMemory: case DeviceExt::ExternalMemory:
// TODO(cwallez@chromium.org): switch to using hasDependencies = HasDep(DeviceExt::ExternalMemoryCapabilities);
// DeviceExt::ExternalMemoryCapabilities when we decouple Instance / Device
// physical device extensions.
hasDependencies = instanceExts.Has(InstanceExt::ExternalMemoryCapabilities);
break; break;
case DeviceExt::ExternalSemaphore: case DeviceExt::ExternalSemaphore:
// TODO(cwallez@chromium.org): switch to using hasDependencies = HasDep(DeviceExt::ExternalSemaphoreCapabilities);
// DeviceExt::ExternalSemaphoreCapabilities when we decouple Instance / Device
// physical device extensions.
hasDependencies = instanceExts.Has(InstanceExt::ExternalSemaphoreCapabilities);
break;
case DeviceExt::_16BitStorage:
// TODO(cwallez@chromium.org): switch to using
// DeviceExt::GetPhysicalDeviceProperties2 when we decouple Instance / Device
// physical device extensions.
// Also depends on VK_KHR_storage_buffer_storage_class
hasDependencies = instanceExts.Has(InstanceExt::GetPhysicalDeviceProperties2);
break; break;
case DeviceExt::ExternalMemoryFD: case DeviceExt::ExternalMemoryFD:
@ -263,6 +283,11 @@ namespace dawn_native { namespace vulkan {
hasDependencies = HasDep(DeviceExt::ExternalSemaphore); hasDependencies = HasDep(DeviceExt::ExternalSemaphore);
break; break;
case DeviceExt::_16BitStorage:
hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2) &&
HasDep(DeviceExt::StorageBufferStorageClass);
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;

View File

@ -74,12 +74,20 @@ namespace dawn_native { namespace vulkan {
// inside EnsureDependencies) // inside EnsureDependencies)
enum class DeviceExt { enum class DeviceExt {
// Promoted to 1.1 // Promoted to 1.1
BindMemory2,
Maintenance1, Maintenance1,
StorageBufferStorageClass,
GetPhysicalDeviceProperties2,
GetMemoryRequirements2,
ExternalMemoryCapabilities,
ExternalSemaphoreCapabilities,
ExternalMemory, ExternalMemory,
ExternalSemaphore, ExternalSemaphore,
_16BitStorage, _16BitStorage,
SamplerYCbCrConversion,
// Promoted to 1.2 // Promoted to 1.2
ImageFormatList,
ShaderFloat16Int8, ShaderFloat16Int8,
// External* extensions // External* extensions