Vulkan: Load promoted extensions or core entrypoint as needed

Previously we would always assume that if the driver supported a Vulkan
version it would also support extensions that were promoted in that
version. This is not a spec requirement, so instead try to load the core
entrypoints, and only if the version is not available, load the
extension entrypoints.

Also renames VulkanFunction members that are from promoted extension to
not have a vendor prefix.

Also tag the promoted extensions that are the same in a core version as
available when that core version is available. This simplifies checking
for features in the Vulkan backend.

Bug:
Change-Id: I0817c01b8838ba26070858abb0cbed030e3291df
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16040
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: David Turner <digit@google.com>
diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp
index 004ba23..14c5b27 100644
--- a/src/dawn_native/vulkan/AdapterVk.cpp
+++ b/src/dawn_native/vulkan/AdapterVk.cpp
@@ -39,8 +39,7 @@
 
     MaybeError Adapter::Initialize() {
         DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this));
-        if (!mDeviceInfo.maintenance1 &&
-            mDeviceInfo.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
+        if (!mDeviceInfo.maintenance1) {
             return DAWN_DEVICE_LOST_ERROR(
                 "Dawn requires Vulkan 1.1 or Vulkan 1.0 with KHR_Maintenance1 in order to support "
                 "viewport flipY");
diff --git a/src/dawn_native/vulkan/BackendVk.cpp b/src/dawn_native/vulkan/BackendVk.cpp
index d2745cb..ab797df 100644
--- a/src/dawn_native/vulkan/BackendVk.cpp
+++ b/src/dawn_native/vulkan/BackendVk.cpp
@@ -190,29 +190,16 @@
             }
         }
 
+        // 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;
         }
-
-        // 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.macosSurface) {
             extensionsToRequest.push_back(kExtensionNameMvkMacosSurface);
             usedKnobs.macosSurface = true;
         }
-        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;
-        }
         if (mGlobalInfo.surface) {
             extensionsToRequest.push_back(kExtensionNameKhrSurface);
             usedKnobs.surface = true;
@@ -238,6 +225,28 @@
             usedKnobs.fuchsiaImagePipeSurface = true;
         }
 
+        // 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;
+        } else {
+            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;
+            }
+        }
+
         VkApplicationInfo appInfo;
         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
         appInfo.pNext = nullptr;
diff --git a/src/dawn_native/vulkan/VulkanFunctions.cpp b/src/dawn_native/vulkan/VulkanFunctions.cpp
index 5cec83a..5d17fae 100644
--- a/src/dawn_native/vulkan/VulkanFunctions.cpp
+++ b/src/dawn_native/vulkan/VulkanFunctions.cpp
@@ -41,12 +41,15 @@
         return {};
     }
 
-#define GET_INSTANCE_PROC(name)                                                         \
-    name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(instance, "vk" #name)); \
-    if (name == nullptr) {                                                              \
-        return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't get proc vk") + #name);     \
+#define GET_INSTANCE_PROC_BASE(name, procName)                                              \
+    name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(instance, "vk" #procName)); \
+    if (name == nullptr) {                                                                  \
+        return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't get proc vk") + #procName);     \
     }
 
+#define GET_INSTANCE_PROC(name) GET_INSTANCE_PROC_BASE(name, name)
+#define GET_INSTANCE_PROC_VENDOR(name, vendor) GET_INSTANCE_PROC_BASE(name, name##vendor)
+
     MaybeError VulkanFunctions::LoadInstanceProcs(VkInstance instance,
                                                   const VulkanGlobalInfo& globalInfo) {
         // Load this proc first so that we can destroy the instance even if some other
@@ -73,26 +76,36 @@
             GET_INSTANCE_PROC(DestroyDebugReportCallbackEXT);
         }
 
-        // Vulkan 1.1 is not required to report promoted extensions from 1.0
-        if (globalInfo.externalMemoryCapabilities ||
-            globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
-            GET_INSTANCE_PROC(GetPhysicalDeviceExternalBufferPropertiesKHR);
+        // Vulkan 1.1 is not required to report promoted extensions from 1.0 and is not required to
+        // support the vendor entrypoint in GetProcAddress.
+        if (globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+            GET_INSTANCE_PROC(GetPhysicalDeviceExternalBufferProperties);
+        } else if (globalInfo.externalMemoryCapabilities) {
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceExternalBufferProperties, KHR);
         }
 
-        if (globalInfo.externalSemaphoreCapabilities ||
-            globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
-            GET_INSTANCE_PROC(GetPhysicalDeviceExternalSemaphorePropertiesKHR);
+        if (globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+            GET_INSTANCE_PROC(GetPhysicalDeviceExternalSemaphoreProperties);
+        } else if (globalInfo.externalSemaphoreCapabilities) {
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceExternalSemaphoreProperties, KHR);
         }
 
-        if (globalInfo.getPhysicalDeviceProperties2 ||
-            globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
-            GET_INSTANCE_PROC(GetPhysicalDeviceFeatures2KHR);
-            GET_INSTANCE_PROC(GetPhysicalDeviceProperties2KHR);
-            GET_INSTANCE_PROC(GetPhysicalDeviceFormatProperties2KHR);
-            GET_INSTANCE_PROC(GetPhysicalDeviceImageFormatProperties2KHR);
-            GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties2KHR);
-            GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties2KHR);
-            GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties2KHR);
+        if (globalInfo.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+            GET_INSTANCE_PROC(GetPhysicalDeviceFeatures2);
+            GET_INSTANCE_PROC(GetPhysicalDeviceProperties2);
+            GET_INSTANCE_PROC(GetPhysicalDeviceFormatProperties2);
+            GET_INSTANCE_PROC(GetPhysicalDeviceImageFormatProperties2);
+            GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties2);
+            GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties2);
+            GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties2);
+        } else if (globalInfo.getPhysicalDeviceProperties2) {
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceFeatures2, KHR);
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceProperties2, KHR);
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceFormatProperties2, KHR);
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceImageFormatProperties2, KHR);
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceQueueFamilyProperties2, KHR);
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceMemoryProperties2, KHR);
+            GET_INSTANCE_PROC_VENDOR(GetPhysicalDeviceSparseImageFormatProperties2, KHR);
         }
 
         if (globalInfo.surface) {
diff --git a/src/dawn_native/vulkan/VulkanFunctions.h b/src/dawn_native/vulkan/VulkanFunctions.h
index cb6960c..e59ac09 100644
--- a/src/dawn_native/vulkan/VulkanFunctions.h
+++ b/src/dawn_native/vulkan/VulkanFunctions.h
@@ -84,27 +84,28 @@
         PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR =
             nullptr;
 
-        // Core Vulkan 1.1 promoted extensions
+        // Core Vulkan 1.1 promoted extensions, set if either the core version or the extension is
+        // present.
 
         // VK_KHR_external_memory_capabilities
-        PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR
-            GetPhysicalDeviceExternalBufferPropertiesKHR = nullptr;
+        PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties =
+            nullptr;
 
         // VK_KHR_external_semaphore_capabilities
-        PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR
-            GetPhysicalDeviceExternalSemaphorePropertiesKHR = nullptr;
+        PFN_vkGetPhysicalDeviceExternalSemaphoreProperties
+            GetPhysicalDeviceExternalSemaphoreProperties = nullptr;
 
         // VK_KHR_get_physical_device_properties2
-        PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR = nullptr;
-        PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR = nullptr;
-        PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysicalDeviceFormatProperties2KHR = nullptr;
-        PFN_vkGetPhysicalDeviceImageFormatProperties2KHR
-            GetPhysicalDeviceImageFormatProperties2KHR = nullptr;
-        PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR
-            GetPhysicalDeviceQueueFamilyProperties2KHR = nullptr;
-        PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysicalDeviceMemoryProperties2KHR = nullptr;
-        PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR
-            GetPhysicalDeviceSparseImageFormatProperties2KHR = nullptr;
+        PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2 = nullptr;
+        PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2 = nullptr;
+        PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2 = nullptr;
+        PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysicalDeviceImageFormatProperties2 =
+            nullptr;
+        PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysicalDeviceQueueFamilyProperties2 =
+            nullptr;
+        PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2 = nullptr;
+        PFN_vkGetPhysicalDeviceSparseImageFormatProperties2
+            GetPhysicalDeviceSparseImageFormatProperties2 = nullptr;
 
 #ifdef VK_USE_PLATFORM_FUCHSIA
         // FUCHSIA_image_pipe_surface
diff --git a/src/dawn_native/vulkan/VulkanInfo.cpp b/src/dawn_native/vulkan/VulkanInfo.cpp
index 0ac5514..9bc68ee 100644
--- a/src/dawn_native/vulkan/VulkanInfo.cpp
+++ b/src/dawn_native/vulkan/VulkanInfo.cpp
@@ -14,6 +14,7 @@
 
 #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/VulkanError.h"
@@ -313,6 +314,11 @@
             }
         }
 
+        // Mark the extensions promoted to Vulkan 1.1 as available.
+        if (info.properties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+            info.maintenance1 = true;
+        }
+
         // TODO(cwallez@chromium.org): gather info about formats
 
         return info;
diff --git a/src/dawn_native/vulkan/VulkanInfo.h b/src/dawn_native/vulkan/VulkanInfo.h
index ac64af0..13a0fdd 100644
--- a/src/dawn_native/vulkan/VulkanInfo.h
+++ b/src/dawn_native/vulkan/VulkanInfo.h
@@ -86,7 +86,7 @@
     struct VulkanDeviceKnobs {
         VkPhysicalDeviceFeatures features;
 
-        // Extensions
+        // Extensions, promoted extensions are set to true if their core version is supported.
         bool debugMarker = false;
         bool externalMemory = false;
         bool externalMemoryFD = false;
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
index ea84d5e..7c5c82d 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
@@ -41,13 +41,13 @@
             formatProps.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
             formatProps.pNext = &formatModifierPropsList;
 
-            fn.GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format, &formatProps);
+            fn.GetPhysicalDeviceFormatProperties2(physicalDevice, format, &formatProps);
 
             uint32_t modifierCount = formatModifierPropsList.drmFormatModifierCount;
             std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProps(modifierCount);
             formatModifierPropsList.pDrmFormatModifierProperties = formatModifierProps.data();
 
-            fn.GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format, &formatProps);
+            fn.GetPhysicalDeviceFormatProperties2(physicalDevice, format, &formatProps);
             for (const auto& props : formatModifierProps) {
                 if (props.drmFormatModifier == modifier) {
                     uint32_t count = props.drmFormatModifierPlaneCount;
@@ -141,9 +141,8 @@
         imageFormatProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
         imageFormatProps.pNext = &externalImageFormatProps;
 
-        VkResult result =
-            VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2KHR(
-                physicalDevice, &imageFormatInfo, &imageFormatProps));
+        VkResult result = VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2(
+            physicalDevice, &imageFormatInfo, &imageFormatProps));
         if (result != VK_SUCCESS) {
             return false;
         }
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
index a8bc181..8724324 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
@@ -66,10 +66,8 @@
         formatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
         formatProperties.pNext = &externalFormatProperties;
 
-        VkResult result =
-            VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2KHR(
-                ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &formatInfo,
-                &formatProperties));
+        VkResult result = VkResult::WrapUnsafe(mDevice->fn.GetPhysicalDeviceImageFormatProperties2(
+            ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &formatInfo, &formatProperties));
 
         // If handle not supported, result == VK_ERROR_FORMAT_NOT_SUPPORTED
         if (result != VK_SUCCESS) {
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp
index 09a5b71..10b9955 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp
@@ -66,7 +66,7 @@
         formatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
         formatProperties.pNext = &externalFormatProperties;
 
-        VkResult result = mDevice->fn.GetPhysicalDeviceImageFormatProperties2KHR(
+        VkResult result = mDevice->fn.GetPhysicalDeviceImageFormatProperties2(
             ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &formatInfo, &formatProperties);
 
         // If handle not supported, result == VK_ERROR_FORMAT_NOT_SUPPORTED
diff --git a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp
index 3e1d3f0..e79288a 100644
--- a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp
+++ b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp
@@ -43,7 +43,7 @@
         semaphoreProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR;
         semaphoreProperties.pNext = nullptr;
 
-        mDevice->fn.GetPhysicalDeviceExternalSemaphorePropertiesKHR(
+        mDevice->fn.GetPhysicalDeviceExternalSemaphoreProperties(
             ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &semaphoreInfo,
             &semaphoreProperties);
 
diff --git a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp
index 5ea53f7..fd10076 100644
--- a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp
+++ b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceZirconHandle.cpp
@@ -43,7 +43,7 @@
         semaphoreProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR;
         semaphoreProperties.pNext = nullptr;
 
-        mDevice->fn.GetPhysicalDeviceExternalSemaphorePropertiesKHR(
+        mDevice->fn.GetPhysicalDeviceExternalSemaphoreProperties(
             ToBackend(mDevice->GetAdapter())->GetPhysicalDevice(), &semaphoreInfo,
             &semaphoreProperties);