[PATCH 4/7] winevulkan: Filter graphics driver reported instance extensions.

Roderick Colenbrander thunderbird2k at gmail.com
Thu Mar 15 01:39:37 CDT 2018


Signed-off-by: Roderick Colenbrander <thunderbird2k at gmail.com>
---
 dlls/winevulkan/make_vulkan     | 23 +++++++++++++-
 dlls/winevulkan/vulkan.c        | 67 ++++++++++++++++++++++++++++++++++++++++-
 dlls/winevulkan/vulkan_thunks.c | 17 +++++++++++
 dlls/winevulkan/vulkan_thunks.h |  1 +
 dlls/winex11.drv/vulkan.c       | 60 ++++++++++++++++++++++++++++--------
 5 files changed, 153 insertions(+), 15 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index c835b997fc..a1d71f9aa0 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -1796,6 +1796,15 @@ class VkGenerator(object):
             f.write("    \"{0}\",\n".format(ext["name"]))
         f.write("};\n\n")
 
+        # Create array of instance extensions.
+        f.write("static const char *vk_instance_extensions[] =\n{\n")
+        for ext in self.registry.extensions:
+            if ext["type"] != "instance":
+                continue
+
+            f.write("    \"{0}\",\n".format(ext["name"]))
+        f.write("};\n\n")
+
         f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
         f.write("{\n")
         f.write("    unsigned int i;\n")
@@ -1805,6 +1814,17 @@ class VkGenerator(object):
         f.write("            return TRUE;\n")
         f.write("    }\n")
         f.write("    return FALSE;\n")
+        f.write("}\n\n")
+
+        f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
+        f.write("{\n")
+        f.write("    unsigned int i;\n")
+        f.write("    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)\n")
+        f.write("    {\n")
+        f.write("        if (strcmp(vk_instance_extensions[i], name) == 0)\n")
+        f.write("            return TRUE;\n")
+        f.write("    }\n")
+        f.write("    return FALSE;\n")
         f.write("}\n")
 
     def generate_thunks_h(self, f, prefix):
@@ -1822,7 +1842,8 @@ class VkGenerator(object):
         f.write("void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;\n")
         f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
 
-        f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
+        f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n")
+        f.write("BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
 
         # Generate prototypes for device and instance functions requiring a custom implementation.
         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index 8547531247..c0fc810a14 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -769,8 +769,73 @@ VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_
 static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name,
         uint32_t *count, VkExtensionProperties *properties)
 {
+    VkResult res;
+    uint32_t num_properties = 0, num_host_properties = 0;
+    VkExtensionProperties *host_properties = NULL;
+    unsigned int i, j;
+
     TRACE("%p %p %p\n", layer_name, count, properties);
-    return vk_funcs->p_vkEnumerateInstanceExtensionProperties(layer_name, count, properties);
+
+    /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
+    if (layer_name)
+    {
+        ERR("Layer enumeration not supported from ICD.\n");
+        return VK_ERROR_LAYER_NOT_PRESENT;
+    }
+
+    res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, NULL);
+    if (res != VK_SUCCESS)
+        return res;
+
+    host_properties = heap_calloc(num_host_properties, sizeof(*host_properties));
+    if (!host_properties)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, host_properties);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to retrieve host properties, res=%d\n", res);
+        heap_free(host_properties);
+        return res;
+    }
+
+    /* The Wine graphics driver provides us with all extensions supported by the host side
+     * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is
+     * up to us here to filter the list down to extensions for which we have thunks.
+     */
+    for (i = 0; i < num_host_properties; i++)
+    {
+        if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
+            num_properties++;
+    }
+
+    /* We only have to count. */
+    if (!properties)
+    {
+        TRACE("Returning %u extensions\n", num_properties);
+        *count = num_properties;
+        heap_free(host_properties);
+        return VK_SUCCESS;
+    }
+
+    for (i = 0, j = 0; i < num_host_properties && j < *count; i++)
+    {
+        if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
+        {
+            TRACE("Enabling extension '%s'\n", host_properties[i].extensionName);
+            memcpy(&properties[j], &host_properties[i], sizeof(*properties));
+            j++;
+        }
+    }
+
+    /* Return incomplete if the buffer is smaller than the number of supported extensions. */
+    if (*count < num_properties)
+        res = VK_INCOMPLETE;
+    else
+        res = VK_SUCCESS;
+
+    heap_free(host_properties);
+    return res;
 }
 
 VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *device_count,
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index 4b635c2645..0e7b299b27 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -2102,6 +2102,12 @@ static const char * const vk_device_extensions[] =
     "VK_KHR_swapchain",
 };
 
+static const char *vk_instance_extensions[] =
+{
+    "VK_KHR_surface",
+    "VK_KHR_win32_surface",
+};
+
 BOOL wine_vk_device_extension_supported(const char *name)
 {
     unsigned int i;
@@ -2112,3 +2118,14 @@ BOOL wine_vk_device_extension_supported(const char *name)
     }
     return FALSE;
 }
+
+BOOL wine_vk_instance_extension_supported(const char *name)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++)
+    {
+        if (strcmp(vk_instance_extensions[i], name) == 0)
+            return TRUE;
+    }
+    return FALSE;
+}
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
index 7ca4122268..9fb5670762 100644
--- a/dlls/winevulkan/vulkan_thunks.h
+++ b/dlls/winevulkan/vulkan_thunks.h
@@ -13,6 +13,7 @@ void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;
 void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
 
 BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;
+BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
 
 /* Functions for which we have custom implementations outside of the thunks. */
 VkResult WINAPI wine_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c
index 1d9bc606eb..0586096254 100644
--- a/dlls/winex11.drv/vulkan.c
+++ b/dlls/winex11.drv/vulkan.c
@@ -21,6 +21,7 @@
 #include "wine/port.h"
 
 #include <stdarg.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -40,10 +41,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
-#endif
-
 typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
 #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
 
@@ -69,6 +66,7 @@ static VkResult (*pvkCreateXlibSurfaceKHR)(VkInstance, const VkXlibSurfaceCreate
 static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *);
 static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *);
 static void (*pvkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *);
+static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *);
 static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *);
 static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *);
 static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *);
@@ -79,12 +77,45 @@ static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevi
 static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *);
 static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
 
-/* TODO: dynamically generate based on host driver capabilities. */
-static const struct VkExtensionProperties winex11_vk_instance_extensions[] =
+static struct VkExtensionProperties *winex11_vk_instance_extensions = NULL;
+static unsigned int winex11_vk_instance_extensions_count = 0;
+
+static void wine_vk_load_instance_extensions(void)
 {
-    { "VK_KHR_surface", 1 },
-    { "VK_KHR_win32_surface", 1},
-};
+    uint32_t num_properties;
+    VkExtensionProperties *properties;
+    unsigned int i;
+
+    pvkEnumerateInstanceExtensionProperties(NULL, &num_properties, NULL);
+
+    properties = heap_calloc(num_properties, sizeof(*properties));
+    if (!properties)
+        return;
+
+    /* We will return the same number of instance extensions reported by the host back to
+     * winevulkan. Along the way we may replace xlib extensions with their win32 equivalents.
+     * Winevulkan will perform more detailed filtering as it knows whether it has thunks
+     * for a particular extension.
+     */
+    pvkEnumerateInstanceExtensionProperties(NULL, &num_properties, properties);
+    for (i = 0; i < num_properties; i++)
+    {
+        /* For now the only x11 extension we need to fixup. Long-term we may need an array. */
+        if (!strcmp(properties[i].extensionName, "VK_KHR_xlib_surface"))
+        {
+            TRACE("Substituting VK_KHR_xlib_surface for VK_KHR_win32_surface\n");
+
+            memset(properties[i].extensionName, 0, sizeof(properties[i].extensionName));
+            snprintf(properties[i].extensionName, sizeof(properties[i].extensionName), "VK_KHR_win32_surface");
+            properties[i].specVersion = 6; /* Revision as of 4/24/2017 */
+        }
+
+        TRACE("Loaded extension: %s\n", properties[i].extensionName);
+    }
+
+    winex11_vk_instance_extensions = properties;
+    winex11_vk_instance_extensions_count = num_properties;
+}
 
 /* Helper function to convert VkSurfaceKHR (uint64_t) to a surface pointer. */
 static inline struct wine_vk_surface * surface_from_handle(VkSurfaceKHR handle)
@@ -110,6 +141,7 @@ LOAD_FUNCPTR(vkCreateXlibSurfaceKHR)
 LOAD_FUNCPTR(vkDestroyInstance)
 LOAD_FUNCPTR(vkDestroySurfaceKHR)
 LOAD_FUNCPTR(vkDestroySwapchainKHR)
+LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties)
 LOAD_FUNCPTR(vkGetDeviceProcAddr)
 LOAD_FUNCPTR(vkGetInstanceProcAddr)
 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
@@ -121,6 +153,8 @@ LOAD_FUNCPTR(vkGetSwapchainImagesKHR)
 LOAD_FUNCPTR(vkQueuePresentKHR)
 #undef LOAD_FUNCPTR
 
+    wine_vk_load_instance_extensions();
+
     return TRUE;
 }
 
@@ -353,11 +387,11 @@ static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_
          * VK_KHR_win32_surface. Long-term this needs to be an intersection
          * between what the native library supports and what thunks we have.
          */
-        *count = ARRAY_SIZE(winex11_vk_instance_extensions);
+        *count = winex11_vk_instance_extensions_count;
         return VK_SUCCESS;
     }
 
-    if (*count < ARRAY_SIZE(winex11_vk_instance_extensions))
+    if (*count < winex11_vk_instance_extensions_count)
     {
         /* Incomplete is a type of success used to signal the application
          * that not all devices got copied.
@@ -367,13 +401,13 @@ static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_
     }
     else
     {
-        num_copies = ARRAY_SIZE(winex11_vk_instance_extensions);
+        num_copies = winex11_vk_instance_extensions_count;
         res = VK_SUCCESS;
     }
 
     for (i = 0; i < num_copies; i++)
     {
-        memcpy(&properties[i], &winex11_vk_instance_extensions[i], sizeof(winex11_vk_instance_extensions[i]));
+        memcpy(&properties[i], &winex11_vk_instance_extensions[i], sizeof(*properties));
     }
     *count = num_copies;
 
-- 
2.14.3




More information about the wine-devel mailing list