[PATCH v2 3/3] winevulkan: Implement VK_EXT_external_memory_win32.

Georg Lehmann dadschoorse at gmail.com
Tue May 18 11:21:15 CDT 2021


On 17.05.21 22:01, Derek Lesho wrote:
> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
> ---
> v2: Addressed comments from mailing list and discord.
> ---
>   dlls/vulkan-1/tests/vulkan.c     | 216 ++++++++++++++++

I think putting the test into a prior patch using the unexposed 
extension mechanism is a good idea.

>   dlls/winevulkan/make_vulkan      |  26 +-
>   dlls/winevulkan/vulkan.c         | 406 +++++++++++++++++++++++++++++--
>   dlls/winevulkan/vulkan_private.h |  24 ++
>   4 files changed, 645 insertions(+), 27 deletions(-)
> 
> diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c
> index 1d23c4112cf..718937e2222 100644
> --- a/dlls/vulkan-1/tests/vulkan.c
> +++ b/dlls/vulkan-1/tests/vulkan.c
> @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_
>       vkDestroySurfaceKHR(vk_instance, surface, NULL);
>   }
>   
> +uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags)
> +{
> +    VkPhysicalDeviceMemoryProperties properties = {0};
> +    unsigned int i;
> +
> +    vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties);
> +
> +    for(i = 0; i < properties.memoryTypeCount; i++)
> +    {
> +        if (properties.memoryTypes[i].propertyFlags & flags)
> +            return i;
> +    }
> +    return -1;
> +}
> +
> +static const char *test_external_memory_extensions[] =
> +{
> +    "VK_KHR_external_memory_capabilities",
> +};
> +
> +static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
> +{
> +    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR;
> +    PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR;
> +    VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info;
> +    VkExternalBufferPropertiesKHR external_buffer_properties;
> +    VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info;
> +    VkExportMemoryWin32HandleInfoKHR export_handle_info;
> +    VkImportMemoryWin32HandleInfoKHR import_handle_info;
> +    VkExportMemoryAllocateInfoKHR export_memory_info;
> +    VkMemoryGetWin32HandleInfoKHR get_handle_info;
> +    VkBufferCreateInfo buffer_create_info;
> +    VkMemoryAllocateInfo alloc_info;
> +    uint32_t queue_family_index;
> +    HANDLE nt_handle, kmt_handle;
> +    VkDeviceMemory vk_memory, vk_memory_import;
> +    VkBuffer vk_buffer;
> +    VkDevice vk_device;
> +    VkResult vr;
> +
> +    static const char *extensions[] =
> +    {
> +        "VK_KHR_dedicated_allocation",
> +        "VK_KHR_external_memory",
> +        "VK_KHR_external_memory_win32",
> +    };
> +
> +    pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR =
> +        (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
> +
> +    if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device)))
> +    {
> +        skip("Failed to create device with external memory extensions, VkResult %d.\n", vr);
> +        return;
> +    }
> +
> +    pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
> +
> +    find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index);
> +
> +    /* Most implementations only support exporting dedicated allocations */
> +
> +    buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
> +    buffer_create_info.pNext = NULL;
> +    buffer_create_info.flags = 0;
> +    buffer_create_info.size = 1;
> +    buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
> +    buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
> +    buffer_create_info.queueFamilyIndexCount = 1;
> +    buffer_create_info.pQueueFamilyIndices = &queue_family_index;
> +    if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer)))
> +    {
> +        skip("Failed to create generic buffer, VkResult %d.\n", vr);
> +        vkDestroyDevice(vk_device, NULL);
> +        return;
> +    }
> +
> +    dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
> +    dedicated_alloc_info.pNext = NULL;
> +    dedicated_alloc_info.image = VK_NULL_HANDLE;
> +    dedicated_alloc_info.buffer = vk_buffer;
> +
> +    external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR;
> +    external_buffer_info.pNext = NULL;
> +    external_buffer_info.flags = 0;
> +    external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
> +    external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
> +
> +    memset(&external_buffer_properties, 0, sizeof(external_buffer_properties));
> +    external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
> +
> +    pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
> +
> +    if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
> +            (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
> +        skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n");
> +    else
> +    {
> +        ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR,
> +            "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
> +
> +        export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
> +        export_memory_info.pNext = &dedicated_alloc_info;
> +        export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
> +
> +        export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
> +        export_handle_info.pNext = &export_memory_info;
> +        export_handle_info.name = L"wine_test_buffer_export_name";
> +        export_handle_info.dwAccess = GENERIC_ALL;
> +        export_handle_info.pAttributes = NULL;
> +
> +        alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
> +        alloc_info.pNext = &export_handle_info;
> +        alloc_info.allocationSize = 1;
> +        alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

You should filter out types which are not in the mask returned by 
vkGetBufferMemoryRequirements.

> +
> +        ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
> +
> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
> +
> +        get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
> +        get_handle_info.pNext = NULL;
> +        get_handle_info.memory = vk_memory;
> +        get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
> +
> +        vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle);
> +        ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
> +
> +        import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
> +        import_handle_info.pNext = &dedicated_alloc_info;
> +        import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
> +        import_handle_info.handle = nt_handle;
> +        import_handle_info.name = NULL;
> +
> +        alloc_info.pNext = &import_handle_info;
> +
> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
> +        ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
> +
> +        vkFreeMemory(vk_device, vk_memory_import, NULL);
> +
> +        import_handle_info.handle = NULL;
> +        import_handle_info.name = L"wine_test_buffer_export_name";
> +
> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
> +    todo_wine
> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
> +        if (vr == VK_SUCCESS)
> +        {
> +            ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
> +            vkFreeMemory(vk_device, vk_memory_import, NULL);
> +        }
> +        vkFreeMemory(vk_device, vk_memory, NULL);
> +        CloseHandle(nt_handle);
> +    }
> +
> +    external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
> +
> +    memset(&external_buffer_properties, 0, sizeof(external_buffer_properties));
> +    external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
> +
> +    pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
> +
> +    if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
> +            (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
> +        skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n");
> +    else
> +    {
> +        ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR,
> +            "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
> +
> +        export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
> +        export_memory_info.pNext = &dedicated_alloc_info;
> +        export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
> +
> +        alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
> +        alloc_info.pNext = &export_memory_info;
> +        alloc_info.allocationSize = 1;
> +        alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

again, filter out the types.

> +
> +        ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
> +
> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
> +
> +        get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
> +        get_handle_info.pNext = NULL;
> +        get_handle_info.memory = vk_memory;
> +        get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
> +
> +        vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle);
> +        ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
> +
> +        import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
> +        import_handle_info.pNext = &dedicated_alloc_info;
> +        import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
> +        import_handle_info.handle = kmt_handle;
> +        import_handle_info.name = NULL;
> +
> +        alloc_info.pNext = &import_handle_info;
> +
> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import);
> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
> +        ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
> +
> +        vkFreeMemory(vk_device, vk_memory_import, NULL);
> +        vkFreeMemory(vk_device, vk_memory, NULL);
> +    }
> +
> +    vkDestroyBuffer(vk_device, vk_buffer, NULL);
> +    vkDestroyDevice(vk_device, NULL);
> +}
> +
>   static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions,
>           void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice))
>   {
> @@ -602,4 +817,5 @@ START_TEST(vulkan)
>       for_each_device(test_unsupported_device_extensions);
>       for_each_device(test_private_data);
>       for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL);
> +    for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL);
>   }
> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
> index 7e1d7c0f043..b36275ba75f 100755
> --- a/dlls/winevulkan/make_vulkan
> +++ b/dlls/winevulkan/make_vulkan
> @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [
>       "VK_EXT_pipeline_creation_feedback",
>       "VK_GOOGLE_display_timing",
>       "VK_KHR_external_fence_win32",
> -    "VK_KHR_external_memory_win32",
>       "VK_KHR_external_semaphore_win32",
>       # Relates to external_semaphore and needs type conversions in bitflags.
>       "VK_KHR_shared_presentable_image", # Needs WSI work.
> @@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [
>       "VK_EXT_external_memory_dma_buf",
>       "VK_EXT_image_drm_format_modifier",
>       "VK_KHR_external_fence_fd",
> -    "VK_KHR_external_memory_fd",
>       "VK_KHR_external_semaphore_fd",
>   
>       # Extensions which require callback handling
> @@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [
>   ]
>   
>   # Extensions which aren't present on the win32 platform, but which winevulkan may use.
> -UNEXPOSED_EXTENSIONS = []
> +UNEXPOSED_EXTENSIONS = [
> +    "VK_KHR_external_memory_fd",
> +]
>   
>   # The Vulkan loader provides entry-points for core functionality and important
>   # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51.
> @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = {
>       "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE},
>       "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> -    "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},

Why do you need a private thunk, it's just a function call that you can 
do directly.

>       "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
> @@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = {
>   
>       # Device functions
>       "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
>       "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
> @@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = {
>       "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
>   
>       # VK_KHR_external_memory_capabilities
> -    "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},

Again, why do you need a private thunk?

>       "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>   
>       # VK_KHR_external_semaphore_capabilities
> @@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = {
>       # VK_EXT_debug_marker
>       "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>       "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
> +
> +    # VK_KHR_external_memory_win32
> +    "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>   }
>   
>   STRUCT_CHAIN_CONVERSIONS = {
>       # Ignore to not confuse host loader.
>       "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
>       "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
> +
> +    # Structs which require pNext chain modification
> +    "VkBufferCreateInfo": [],
> +    "VkImageCreateInfo": [],
> +    "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"],
> +    "VkPhysicalDeviceImageFormatInfo2": [],
>   }
>   
>   
> @@ -1052,6 +1066,8 @@ class VkHandle(object):
>               return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
>           if self.name == "VkSurfaceKHR":
>               return "wine_surface_from_handle({0})->surface".format(name)
> +        if self.name == "VkDeviceMemory":
> +            return "wine_dev_mem_from_handle({0})->dev_mem".format(name)
>   
>           native_handle_name = None
>   
> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
> index 9f181d92bc5..c2069b77ef2 100644
> --- a/dlls/winevulkan/vulkan.c
> +++ b/dlls/winevulkan/vulkan.c
> @@ -25,6 +25,7 @@
>   #include <time.h>
>   #include <stdarg.h>
>   #include <stdlib.h>
> +#include <unistd.h>
>   
>   #include "ntstatus.h"
>   #define WIN32_NO_STATUS
> @@ -34,6 +35,8 @@
>   #include "winuser.h"
>   #include "winternl.h"
>   
> +#include "wine/server.h"
> +
>   #include "vulkan_private.h"
>   
>   WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
> @@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc
>        */
>       for (i = 0; i < num_host_properties; i++)
>       {
> +        if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd"))
> +        {
> +            TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n");
> +
> +            snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName),
> +                    VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
> +            host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION;
> +        }
> +
>           if (wine_vk_device_extension_supported(host_properties[i].extensionName))
>           {
>               TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
> @@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device,
>   static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info)
>   {
>       free_VkDeviceCreateInfo_struct_chain(create_info);
> +
> +    if (create_info->enabledExtensionCount)
> +        free((void *)create_info->ppEnabledExtensionNames);
>   }
>   
>   static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src,
>           VkDeviceCreateInfo *dst)
>   {
> +    const char **enabled_extensions;
>       unsigned int i;
>       VkResult res;
>   
> @@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src
>           if (!wine_vk_device_extension_supported(extension_name))
>           {
>               WARN("Extension %s is not supported.\n", debugstr_a(extension_name));
> -            wine_vk_device_free_create_info(dst);
> +            free_VkDeviceCreateInfo_struct_chain(dst);
>               return VK_ERROR_EXTENSION_NOT_PRESENT;
>           }
>       }
>   
> +    if (src->enabledExtensionCount > 0)
> +    {
> +        enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
> +        if (!enabled_extensions)
> +        {
> +            free_VkDeviceCreateInfo_struct_chain(dst);
> +            return VK_ERROR_OUT_OF_HOST_MEMORY;
> +        }
> +
> +        for (i = 0; i < src->enabledExtensionCount; i++)
> +        {
> +            if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32"))
> +            {
> +                enabled_extensions[i] = "VK_KHR_external_memory_fd";
> +            }
> +            else
> +            {
> +                enabled_extensions[i] = src->ppEnabledExtensionNames[i];
> +            }
> +        }
> +        dst->ppEnabledExtensionNames = enabled_extensions;
> +    }
> +
>       return VK_SUCCESS;
>   }
>   
> @@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice
>   void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev,
>           const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties)
>   {
> +    VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
> +
>       TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
> -    memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
> +
> +    if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)

This is not a bit mask, it's a single bit. So you should use == here.

> +        buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +
> +    thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties);
> +
> +    if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
> +        properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
> +    if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
> +        properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>   }
>   
>   void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev,
>           const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties)

This is an alias of vkGetPhysicalDeviceExternalBufferProperties, unify 
them in the same way as you did with 
vkGetPhysicalDeviceImageFormatProperties2.

>   {
> +    VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
> +
>       TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
> -    memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
> +
> +    if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
> +        buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +
> +    thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev, &buffer_info_dup, properties);
> +
> +    if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
> +        properties->externalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
> +    if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
> +        properties->externalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>   }
>   
> -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev,
> +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev,
> +        VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *),
>           const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
>   {
> +    VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL;
> +    const VkPhysicalDeviceExternalImageFormatInfo *external_image_info;
> +    VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info;
>       VkExternalImageFormatProperties *external_image_properties;
>       VkResult res;
>   
> -    TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
> +    if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO)))
> +    {
> +        if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)

This is not a bit mask, it's a single bit.

> +        {
> +            if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0)
> +            {
> +                WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res);
> +                return res;
> +            }
>   
> -    res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties);
> +            external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
> +            external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +        }
> +        if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
> +        {
> +            WARN("Unsupported handle type %#x.\n", external_image_info->handleType);
> +            return VK_ERROR_FORMAT_NOT_SUPPORTED;
> +        }
> +    }
> +
> +    res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties);
> +
> +    if (external_image_info_dup)
> +        free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host);
>   
>       if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
>       {
>           VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
> -        p->externalMemoryFeatures = 0;
> -        p->exportFromImportedHandleTypes = 0;
> -        p->compatibleHandleTypes = 0;
> +        if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
> +            p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
> +        if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
> +            p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>       }
>   
>       return res;
>   }
>   
> -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev,
> +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev,
>           const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
>   {
> -    VkExternalImageFormatProperties *external_image_properties;
> -    VkResult res;
> -
>       TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
>   
> -    res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties);
> +    return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties);
> +}
>   
> -    if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
> -    {
> -        VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
> -        p->externalMemoryFeatures = 0;
> -        p->exportFromImportedHandleTypes = 0;
> -        p->compatibleHandleTypes = 0;
> -    }
> +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev,
> +        const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
> +{
> +    TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
>   
> -    return res;
> +    return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties);
>   }
>   
>   /* From ntdll/unix/sync.c */
> @@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu
>   
>       return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info);
>   }
> +
> +static HANDLE create_gpu_resource(int fd, LPCWSTR name)
> +{
> +    HANDLE ret = INVALID_HANDLE_VALUE;
> +
> +    if (name)
> +        FIXME("Naming gpu resources not supported.\n");
> +
> +    wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
> +
> +    return ret;
> +}
> +
> +VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info,
> +    const VkAllocationCallbacks *allocator, VkDeviceMemory *memory)
> +{
> +    const VkImportMemoryWin32HandleInfoKHR *handle_import_info;
> +    const VkExportMemoryWin32HandleInfoKHR *handle_export_info;
> +    VkMemoryAllocateInfo allocate_info_dup = *allocate_info;
> +    VkExportMemoryAllocateInfo *export_info;
> +    VkImportMemoryFdInfoKHR fd_import_info;
> +    struct wine_dev_mem *object;
> +    VkResult res;
> +    int fd;
> +
> +#if defined(USE_STRUCT_CONVERSION)
> +        VkMemoryAllocateInfo_host allocate_info_host;
> +        VkMemoryGetFdInfoKHR_host get_fd_info;
> +#else
> +        VkMemoryAllocateInfo allocate_info_host;
> +        VkMemoryGetFdInfoKHR get_fd_info;
> +#endif

This indention is wrong.

> +
> +    TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory);
> +
> +    if (allocator)
> +        FIXME("Support for allocation callbacks not implemented yet\n");
> +
> +    if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0)
> +    {
> +        WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res);
> +        return res;
> +    }
> +
> +    if (!(object = calloc(1, sizeof(*object))))
> +    {
> +        free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
> +        return VK_ERROR_OUT_OF_HOST_MEMORY;
> +    }
> +
> +    object->dev_mem = VK_NULL_HANDLE;
> +    object->handle = INVALID_HANDLE_VALUE;
> +    fd_import_info.fd = -1;
> +    fd_import_info.pNext = NULL;
> +
> +    /* find and process handle import/export info and grab it */
> +    handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR);
> +    handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR);
> +    if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor)
> +        FIXME("Support for custom security descriptor not implemented.\n");
> +
> +    if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO)))
> +    {
> +        object->handle_types = export_info->handleTypes;
> +        if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
> +        {
> +            res = VK_ERROR_OUT_OF_HOST_MEMORY;

VK_ERROR_UNKNOWN sounds like a better idea.

> +            goto done;
> +        }
> +        if (object->handle_types)
> +            export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +    }
> +
> +    /* Vulkan consumes imported FDs, but not imported HANDLEs */
> +    if (handle_import_info)
> +    {
> +        fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
> +        fd_import_info.pNext = allocate_info_dup.pNext;
> +        fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +
> +        switch (handle_import_info->handleType)
> +        {
> +            case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
> +                if (handle_import_info->handle)
> +                    NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS );
> +                else if (handle_import_info->name)
> +                    FIXME("Importing device memory by resource name not supported.\n");
> +                break;
> +            default:
> +                WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType);
> +                res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
> +                goto done;
> +        }
> +
> +        if (object->handle != INVALID_HANDLE_VALUE)
> +            wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL);
> +
> +        if (fd_import_info.fd == -1)
> +        {
> +            TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle,
> +                    handle_import_info->name ? debugstr_w(handle_import_info->name) : "");
> +            res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
> +            goto done;
> +        }
> +    }
> +
> +    allocate_info_host.sType = allocate_info_dup.sType;
> +    allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info;
> +    allocate_info_host.allocationSize = allocate_info_dup.allocationSize;
> +    allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex;
> +
> +    if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS)
> +    {
> +        if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes)
> +        {
> +            get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
> +            get_fd_info.pNext = NULL;
> +            get_fd_info.memory = object->dev_mem;
> +            get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +
> +            if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS)
> +            {
> +                object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL);
> +                object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL;
> +                if (handle_export_info && handle_export_info->pAttributes)
> +                    object->inherit = handle_export_info->pAttributes->bInheritHandle;
> +                else
> +                    object->inherit = FALSE;
> +                close(fd);
> +            }
> +
> +            if (object->handle == INVALID_HANDLE_VALUE)
> +            {
> +                res = VK_ERROR_OUT_OF_HOST_MEMORY;
> +                goto done;
> +            }
> +        }
> +
> +        WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->dev_mem);
> +        *memory = wine_dev_mem_to_handle(object);
> +    }
> +
> +    done:
> +
> +    if (res != VK_SUCCESS)
> +    {
> +        device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL);
> +        if (fd_import_info.fd != -1)
> +            close(fd_import_info.fd);
> +        if (object->handle != INVALID_HANDLE_VALUE)
> +            NtClose(object->handle);
> +        free(object);
> +    }
> +
> +    free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
> +
> +    return res;
> +}
> +
> +VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device,
> +    const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle)
> +{
> +    struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory);
> +    const VkBaseInStructure *chain;
> +
> +    TRACE("%p, %p %p\n", device, handle_info, handle);
> +
> +    if (!(dev_mem->handle_types & handle_info->handleType))
> +        return VK_ERROR_OUT_OF_HOST_MEMORY;

VK_ERROR_UNKNOWN is probably better here as well.

> +
> +    if ((chain = handle_info->pNext))
> +        FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
> +
> +    switch(handle_info->handleType)
> +    {
> +        case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
> +            return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ?
> +                VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
> +        default:
> +            return VK_ERROR_UNKNOWN;
> +    }
> +}
> +
> +void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator)
> +{
> +    struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
> +
> +    TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
> +
> +    if (allocator)
> +        FIXME("Support for allocation callbacks not implemented yet\n");
> +
> +    if (!handle)
> +        return;
> +
> +    WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem);
> +    device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL);
> +    if (dev_mem->handle != INVALID_HANDLE_VALUE)
> +        NtClose(dev_mem->handle);
> +    free(dev_mem);
> +}
> +
> +VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device,
> +        VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties)
> +{
> +    TRACE("%p %u %p %p\n", device, type, handle, properties);
> +
> +    /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666
> +       handleType must not be one of the handle types defined as opaque */
> +    return VK_ERROR_INVALID_EXTERNAL_HANDLE;
> +}
> +
> +VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info,
> +    const VkAllocationCallbacks *allocator, VkBuffer *buffer)
> +{
> +    VkExternalMemoryBufferCreateInfo *external_memory_info;
> +    VkBufferCreateInfo create_info_dup;

Why do we need this? Couldn't you just call 
convert_VkBufferCreateInfo_struct_chain on create_info_host directly?

> +    VkResult res;
> +
> +#if defined(USE_STRUCT_CONVERSION)
> +    VkBufferCreateInfo_host create_info_host;
> +#else
> +    VkBufferCreateInfo create_info_host;
> +#endif
> +
> +    if (allocator)
> +        FIXME("Support for allocation callbacks not implemented yet\n");
> +
> +    if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup)))
> +    {
> +        WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res);
> +        return res;
> +    }
> +
> +    if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) &&
> +        external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)
> +            external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
> +
> +    create_info_host.pNext = create_info_dup.pNext;
> +    create_info_host.sType = create_info->sType;
> +    create_info_host.flags = create_info->flags;
> +    create_info_host.size = create_info->size;
> +    create_info_host.usage = create_info->usage;
> +    create_info_host.sharingMode = create_info->sharingMode;
> +    create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount;
> +    create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices;
> +
> +    res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer);
> +
> +    free_VkBufferCreateInfo_struct_chain(&create_info_dup);
> +
> +    return res;
> +}
> +
> +VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info,
> +    const VkAllocationCallbacks *allocator, VkBuffer *image)
> +{
> +    VkExternalMemoryImageCreateInfo *external_memory_info;
> +    VkImageCreateInfo create_info_host;

This is never initialized.

> +    VkResult res;
> +
> +    if (allocator)
> +        FIXME("Support for allocation callbacks not implemented yet\n");
> +
> +    if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host)))
> +    {
> +        WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res);
> +        return res;
> +    }
> +
> +    if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) &&

wrong sType

> +        external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)
> +            external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
> +
> +    res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image);
> +
> +    free_VkImageCreateInfo_struct_chain(&create_info_host);
> +
> +    return res;
> +}
> diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
> index 83dc90ca15e..4a20702d43b 100644
> --- a/dlls/winevulkan/vulkan_private.h
> +++ b/dlls/winevulkan/vulkan_private.h
> @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface)
>       return (VkSurfaceKHR)(uintptr_t)surface;
>   }
>   
> +struct wine_dev_mem
> +{
> +    VkDeviceMemory dev_mem;
> +
> +    VkExternalMemoryHandleTypeFlagBits handle_types;
> +
> +    BOOL inherit;
> +    DWORD access;
> +
> +    HANDLE handle;
> +
> +    struct wine_vk_mapping mapping;
> +};
> +
> +static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle)
> +{
> +    return (struct wine_dev_mem *)(uintptr_t)handle;
> +}
> +
> +static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem)
> +{
> +    return (VkDeviceMemory)(uintptr_t)dev_mem;
> +}
> +
>   BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;
>   BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
>   
> 



More information about the wine-devel mailing list