From 8ef70305f9e4c785331a9b7c0fc672dbf6f4430b Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Wed, 14 Mar 2018 23:39:37 -0700 Subject: [PATCH] winevulkan: Filter graphics driver reported instance extensions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Roderick Colenbrander Signed-off-by: Józef Kucia Signed-off-by: Alexandre Julliard --- 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 c835b997fce..a1d71f9aa0d 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 85475312479..c0fc810a14a 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 4b635c2645a..0e7b299b271 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 7ca41222681..9fb56707624 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 1d9bc606ebb..05860962545 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -21,6 +21,7 @@ #include "wine/port.h" #include +#include #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;