[PATCH 1/4] winevulkan: Implement VK_EXT_external_memory_win32.

Georg Lehmann dadschoorse at gmail.com
Mon May 3 16:44:20 CDT 2021


On 03.05.21 18:46, Derek Lesho wrote:
> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
> ---
> This commit had to be squashed in with the tests, as data structures for the extension are missing from
> the headers when the extension is blacklisted by make_vulkan.
> ---
>   dlls/vulkan-1/tests/vulkan.c     | 242 +++++++++++++++++--
>   dlls/winevulkan/loader_thunks.c  |  12 +
>   dlls/winevulkan/loader_thunks.h  |   2 +
>   dlls/winevulkan/make_vulkan      |  63 ++++-
>   dlls/winevulkan/vulkan.c         | 385 +++++++++++++++++++++++++++++--
>   dlls/winevulkan/vulkan_private.h |  22 ++
>   6 files changed, 679 insertions(+), 47 deletions(-)
> 

Hi,

I would prefer if you could split this up in to multiple patches, e.g. 
the host only functions and struct conversion changes in make_vulkan 
could each be in their own commits.

> diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c
> index 9061b2b6db8..c1350da70ee 100644
> --- a/dlls/vulkan-1/tests/vulkan.c
> +++ b/dlls/vulkan-1/tests/vulkan.c
> @@ -144,7 +144,7 @@ static void test_instance_version(void)
>               VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version));
>   }
>   
> -static void enumerate_physical_device(VkPhysicalDevice vk_physical_device)
> +static void enumerate_physical_device(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
>   {
>       VkPhysicalDeviceProperties properties;
>   
> @@ -224,7 +224,7 @@ static void test_enumerate_physical_device2(void)
>       vkDestroyInstance(vk_instance, NULL);
>   }
>   
> -static void enumerate_device_queues(VkPhysicalDevice vk_physical_device)
> +static void enumerate_device_queues(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
>   {
>       VkPhysicalDeviceProperties device_properties;
>       VkQueueFamilyProperties *properties;
> @@ -283,7 +283,7 @@ static void test_physical_device_groups(void)
>           trace("Group[%u] count %u, subset allocation %#x\n",
>                   i, properties[i].physicalDeviceCount, properties[i].subsetAllocation);
>           for (j = 0; j < properties[i].physicalDeviceCount; ++j)
> -            enumerate_physical_device(properties[i].physicalDevices[j]);
> +            enumerate_physical_device(vk_instance, properties[i].physicalDevices[j]);
>       }
>   
>       if ((vr = create_device(properties->physicalDevices[0], 0, NULL, NULL, &vk_device)) < 0)
> @@ -307,7 +307,7 @@ static void test_physical_device_groups(void)
>       vkDestroyInstance(vk_instance, NULL);
>   }
>   
> -static void test_destroy_command_pool(VkPhysicalDevice vk_physical_device)
> +static void test_destroy_command_pool(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
>   {
>       VkCommandBufferAllocateInfo allocate_info;
>       VkCommandPoolCreateInfo pool_info;
> @@ -366,7 +366,7 @@ static void test_unsupported_instance_extensions(void)
>       }
>   }
>   
> -static void test_unsupported_device_extensions(VkPhysicalDevice vk_physical_device)
> +static void test_unsupported_device_extensions(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
>   {
>       VkDevice vk_device;
>       unsigned int i;
> @@ -387,7 +387,7 @@ static void test_unsupported_device_extensions(VkPhysicalDevice vk_physical_devi
>       }
>   }
>   
> -static void test_private_data(VkPhysicalDevice vk_physical_device)
> +static void test_private_data(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
>   {
>       PFN_vkDestroyPrivateDataSlotEXT pfn_vkDestroyPrivateDataSlotEXT;
>       PFN_vkCreatePrivateDataSlotEXT pfn_vkCreatePrivateDataSlotEXT;
> @@ -437,7 +437,218 @@ static void test_private_data(VkPhysicalDevice vk_physical_device)
>       vkDestroyDevice(vk_device, NULL);
>   }
>   
> -static void for_each_device(void (*test_func)(VkPhysicalDevice))
> +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 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);
> +
> +        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);
> +
> +        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(void (*test_func)(VkInstance,VkPhysicalDevice), uint32_t extension_count,
> +        const char * const *enabled_extensions)
>   {
>       VkPhysicalDevice *vk_physical_devices;
>       VkInstance vk_instance;
> @@ -445,7 +656,7 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice))
>       uint32_t count;
>       VkResult vr;
>   
> -    if ((vr = create_instance_skip(0, NULL, &vk_instance)) < 0)
> +    if ((vr = create_instance_skip(extension_count, enabled_extensions, &vk_instance)) < 0)
>           return;
>       ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr);
>   
> @@ -463,7 +674,7 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice))
>       ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr);
>   
>       for (i = 0; i < count; ++i)
> -        test_func(vk_physical_devices[i]);
> +        test_func(vk_instance, vk_physical_devices[i]);
>   
>       heap_free(vk_physical_devices);
>   
> @@ -472,13 +683,16 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice))
>   
>   START_TEST(vulkan)
>   {
> +    static const char *external_memory_capabilities = "VK_KHR_external_memory_capabilities";
> +
>       test_instance_version();
> -    for_each_device(enumerate_physical_device);
> +    for_each_device(enumerate_physical_device, 0, NULL);
>       test_enumerate_physical_device2();
> -    for_each_device(enumerate_device_queues);
> +    for_each_device(enumerate_device_queues, 0, NULL);
>       test_physical_device_groups();
> -    for_each_device(test_destroy_command_pool);
> +    for_each_device(test_destroy_command_pool, 0, NULL);
>       test_unsupported_instance_extensions();
> -    for_each_device(test_unsupported_device_extensions);
> -    for_each_device(test_private_data);
> +    for_each_device(test_unsupported_device_extensions, 0, NULL);
> +    for_each_device(test_private_data, 0, NULL);
> +    for_each_device(test_external_memory, 1, &external_memory_capabilities);
>   }
> diff --git a/dlls/winevulkan/loader_thunks.c b/dlls/winevulkan/loader_thunks.c
> index 69fcd44160e..471999a3821 100644
> --- a/dlls/winevulkan/loader_thunks.c
> +++ b/dlls/winevulkan/loader_thunks.c
> @@ -1448,6 +1448,16 @@ VkResult WINAPI vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalM
>       return unix_funcs->p_vkGetMemoryHostPointerPropertiesEXT(device, handleType, pHostPointer, pMemoryHostPointerProperties);
>   }
>   
> +VkResult WINAPI vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo, HANDLE *pHandle)
> +{
> +    return unix_funcs->p_vkGetMemoryWin32HandleKHR(device, pGetWin32HandleInfo, pHandle);
> +}
> +
> +VkResult WINAPI vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *pMemoryWin32HandleProperties)
> +{
> +    return unix_funcs->p_vkGetMemoryWin32HandlePropertiesKHR(device, handleType, handle, pMemoryWin32HandleProperties);
> +}
> +
>   VkResult WINAPI vkGetPerformanceParameterINTEL(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL *pValue)
>   {
>       return unix_funcs->p_vkGetPerformanceParameterINTEL(device, parameter, pValue);
> @@ -2223,6 +2233,8 @@ static const struct vulkan_func vk_device_dispatch_table[] =
>       {"vkGetImageSparseMemoryRequirements2KHR", &vkGetImageSparseMemoryRequirements2KHR},
>       {"vkGetImageSubresourceLayout", &vkGetImageSubresourceLayout},
>       {"vkGetMemoryHostPointerPropertiesEXT", &vkGetMemoryHostPointerPropertiesEXT},
> +    {"vkGetMemoryWin32HandleKHR", &vkGetMemoryWin32HandleKHR},
> +    {"vkGetMemoryWin32HandlePropertiesKHR", &vkGetMemoryWin32HandlePropertiesKHR},
>       {"vkGetPerformanceParameterINTEL", &vkGetPerformanceParameterINTEL},
>       {"vkGetPipelineCacheData", &vkGetPipelineCacheData},
>       {"vkGetPipelineExecutableInternalRepresentationsKHR", &vkGetPipelineExecutableInternalRepresentationsKHR},
> diff --git a/dlls/winevulkan/loader_thunks.h b/dlls/winevulkan/loader_thunks.h
> index e7257cef508..031b7f5652b 100644
> --- a/dlls/winevulkan/loader_thunks.h
> +++ b/dlls/winevulkan/loader_thunks.h
> @@ -304,6 +304,8 @@ struct unix_funcs
>       void (WINAPI *p_vkGetImageSparseMemoryRequirements2KHR)(VkDevice, const VkImageSparseMemoryRequirementsInfo2 *, uint32_t *, VkSparseImageMemoryRequirements2 *);
>       void (WINAPI *p_vkGetImageSubresourceLayout)(VkDevice, VkImage, const VkImageSubresource *, VkSubresourceLayout *);
>       VkResult (WINAPI *p_vkGetMemoryHostPointerPropertiesEXT)(VkDevice, VkExternalMemoryHandleTypeFlagBits, const void *, VkMemoryHostPointerPropertiesEXT *);
> +    VkResult (WINAPI *p_vkGetMemoryWin32HandleKHR)(VkDevice, const VkMemoryGetWin32HandleInfoKHR *, HANDLE *);
> +    VkResult (WINAPI *p_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice, VkExternalMemoryHandleTypeFlagBits, HANDLE, VkMemoryWin32HandlePropertiesKHR *);
>       VkResult (WINAPI *p_vkGetPerformanceParameterINTEL)(VkDevice, VkPerformanceParameterTypeINTEL, VkPerformanceValueINTEL *);
>       VkResult (WINAPI *p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice, uint32_t *, VkTimeDomainEXT *);
>       VkResult (WINAPI *p_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice, uint32_t *, VkCooperativeMatrixPropertiesNV *);
> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
> index b1877acda17..0a0e3bac299 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
> @@ -154,6 +152,8 @@ class ThunkType(Enum):
>   #   - PRIVATE thunks can be used in custom implementations for
>   #     struct conversion.
>   # - loader_thunk sets whether to create a thunk for unix_funcs.
> +# - host_only sets whether to preclude the function from the
> +#   win32-facing dispatch table.
>   FUNCTION_OVERRIDES = {
>       # Global functions
>       "vkCreateInstance" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
> @@ -169,7 +169,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},
>       "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
> @@ -178,11 +178,13 @@ FUNCTION_OVERRIDES = {
>   
>       # Device functions
>       "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
> +    "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE},
>       "vkCreateCommandPool" : {"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},
> @@ -213,7 +215,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},
>       "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>   
>       # VK_KHR_external_semaphore_capabilities
> @@ -249,12 +251,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},
> +
> +    # VK_KHR_external_memory_fd
> +    "vkGetMemoryFdKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE,  "host_only" : True},
> +    "vkGetMemoryFdPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "host_only" : True},

Would it make sense to added a new value to ThunkType instead, e.g. 
ThunkType.NOT_EXPOSED?

>   }
>   
> -STRUCT_CHAIN_CONVERSIONS = [
> -    "VkDeviceCreateInfo",
> -    "VkInstanceCreateInfo",
> -]
> +STRUCT_CHAIN_CONVERSIONS = {
> +    "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
> +    "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
> +    "VkPhysicalDeviceImageFormatInfo2": [],
> +    "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"],
> +}
>   
>   
>   class Direction(Enum):
> @@ -532,6 +544,7 @@ class VkFunction(object):
>           self.driver = func_info["driver"] if func_info else False
>           self.thunk_type = func_info["thunk"] if func_info else ThunkType.PUBLIC
>           self.loader_thunk_type = func_info["loader_thunk"] if func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
> +        self.host_only = func_info["host_only"] if func_info and "host_only" in func_info else False
>   
>           # Required is set while parsing which APIs and types are required
>           # and is used by the code generation.
> @@ -651,6 +664,9 @@ class VkFunction(object):
>       def needs_private_thunk(self):
>           return self.thunk_type == ThunkType.PRIVATE
>   
> +    def needs_win_exclusion(self):
> +        return self.host_only
> +
>       def pfn(self, prefix="p", call_conv=None, conv=False):
>           """ Create function pointer. """
>   
> @@ -1028,6 +1044,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
>   
> @@ -2115,9 +2133,10 @@ class FreeFunction(object):
>   
>   
>   class StructChainConversionFunction(object):
> -    def __init__(self, direction, struct):
> +    def __init__(self, direction, struct, ignores):
>           self.direction = direction
>           self.struct = struct
> +        self.ignores = ignores
>           self.type = struct.name
>   
>           self.name = "convert_{0}_struct_chain".format(self.type)
> @@ -2143,8 +2162,8 @@ class StructChainConversionFunction(object):
>           body += "        {\n"
>   
>           # Ignore to not confuse host loader.

This comment is now misplaced.

> -        body += "        case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
> -        body += "        case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
> +        for i in self.ignores:
> +            body += "        case {0}:\n".format(i)
>           body += "            break;\n\n"
>   
>           for e in self.struct.struct_extensions:
> @@ -2153,6 +2172,9 @@ class StructChainConversionFunction(object):
>   
>               stype = next(x for x in e.members if x.name == "sType")
>   
> +            if stype.values in self.ignores:
> +                continue
> +
>               body += "        case {0}:\n".format(stype.values)
>               body += "        {\n"
>   
> @@ -2250,7 +2272,7 @@ class VkGenerator(object):
>   
>           for struct in self.registry.structs:
>               if struct.name in STRUCT_CHAIN_CONVERSIONS:
> -                self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct))
> +                self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
>                   self.struct_chain_conversions.append(FreeStructChainFunction(struct))
>   
>       def _generate_copyright(self, f, spec_file=False):
> @@ -2292,6 +2314,9 @@ class VkGenerator(object):
>               if not vk_func.is_required():
>                   continue
>   
> +            if vk_func.needs_win_exclusion():
> +                continue
> +
>               if vk_func.is_global_func():
>                   continue
>   
> @@ -2382,6 +2407,8 @@ class VkGenerator(object):
>           for vk_func in self.registry.funcs.values():
>               if not vk_func.is_required():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>               if vk_func.loader_thunk_type == ThunkType.NONE:
>                   continue
>   
> @@ -2403,6 +2430,8 @@ class VkGenerator(object):
>                   continue
>               if vk_func.needs_thunk() and not vk_func.needs_private_thunk():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>   
>               if vk_func.is_core_func():
>                   f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix=prefix)))
> @@ -2510,6 +2539,8 @@ class VkGenerator(object):
>           for vk_func in self.registry.funcs.values():
>               if not vk_func.is_required():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>               if vk_func.loader_thunk_type != ThunkType.PUBLIC:
>                   continue
>   
> @@ -2519,6 +2550,8 @@ class VkGenerator(object):
>           for vk_func in self.registry.device_funcs:
>               if not vk_func.is_required():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>   
>               f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
>           f.write("};\n\n")
> @@ -2527,6 +2560,8 @@ class VkGenerator(object):
>           for vk_func in self.registry.phys_dev_funcs:
>               if not vk_func.is_required():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>   
>               f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
>           f.write("};\n\n")
> @@ -2535,6 +2570,8 @@ class VkGenerator(object):
>           for vk_func in self.registry.instance_funcs:
>               if not vk_func.is_required():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>   
>               f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
>           f.write("};\n\n")
> @@ -2592,6 +2629,8 @@ class VkGenerator(object):
>           for vk_func in self.registry.funcs.values():
>               if not vk_func.is_required():
>                   continue
> +            if vk_func.needs_win_exclusion():
> +                continue
>               if vk_func.loader_thunk_type == ThunkType.NONE:
>                   continue
>   
> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
> index 45eda78e997..e95860cb3fa 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);
> @@ -265,6 +268,14 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc
>       {
>           if (wine_vk_device_extension_supported(host_properties[i].extensionName))
>           {
> +            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;
> +            }
>               TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
>               num_properties++;
>           }
> @@ -368,12 +379,16 @@ 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)
>   {
>       VkDeviceGroupDeviceCreateInfo *group_info;
> +    const char **enabled_extensions;
>       unsigned int i;
>       VkResult res;
>   
> @@ -406,6 +421,39 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src
>       dst->enabledLayerCount = 0;
>       dst->ppEnabledLayerNames = NULL;
>   
> +    if (src->enabledExtensionCount > 0)
> +    {
> +        enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
> +        if (!enabled_extensions)
> +        {
> +            if ((group_info = wine_vk_find_struct(dst, DEVICE_GROUP_DEVICE_CREATE_INFO)))
> +                free((void *)group_info->pPhysicalDevices);
> +            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_fd"))
> +            {
> +                if ((group_info = wine_vk_find_struct(dst, DEVICE_GROUP_DEVICE_CREATE_INFO)))
> +                    free((void *)group_info->pPhysicalDevices);
> +                free_VkDeviceCreateInfo_struct_chain(dst);
> +                free(enabled_extensions);
> +                return VK_ERROR_EXTENSION_NOT_PRESENT;
> +            }

Why do you check this? It shouldn't be exposed to the app in any way.

> +            else 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;
> +    }
> +
>       TRACE("Enabled %u extensions.\n", dst->enabledExtensionCount);
>       for (i = 0; i < dst->enabledExtensionCount; i++)
>       {
> @@ -1300,57 +1348,106 @@ 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)
> +        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)
>   {
> +    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 *),

vkGetPhysicalDeviceImageFormatProperties2KHR and 
vkGetPhysicalDeviceImageFormatProperties2 are equivalent, you should 
just always use thunk_vkGetPhysicalDeviceImageFormatProperties2.

>           const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
>   {
> +    VkPhysicalDeviceExternalImageFormatInfo *external_image_info_host = 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)
> +        {
> +            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;
> +            }
> +
> +            external_image_info_host = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
> +            external_image_info_host->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);
>   
> -    res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties);
> +    if (external_image_info_host)
> +        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_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_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 */
> @@ -1860,3 +1957,249 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu
>   
>       return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info);
>   }
> +
> +static HANDLE create_video_resource(int fd, LPCWSTR name)
> +{
> +    HANDLE ret = INVALID_HANDLE_VALUE;
> +
> +    if (name)
> +        FIXME("Naming video 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_out)
> +{
> +    const VkImportMemoryWin32HandleInfoKHR *handle_import_info = NULL;
> +    const VkExportMemoryWin32HandleInfoKHR *handle_export_info = NULL;
> +    VkMemoryAllocateInfo allocate_info_dup = *allocate_info;
> +    VkExportMemoryAllocateInfo *export_info = NULL;
> +    VkImportMemoryFdInfoKHR fd_import_info;
> +    const VkBaseOutStructure *header;
> +    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
> +
> +    TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory_out);
> +
> +    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 */
> +    for (header = allocate_info->pNext; header; header = header->pNext)
> +    {
> +        switch (header->sType)
> +        {
> +            case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
> +                handle_import_info = (const VkImportMemoryWin32HandleInfoKHR *)header;
> +                break;
> +            case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
> +                handle_export_info = (const VkExportMemoryWin32HandleInfoKHR *)header;
> +                if (handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor)
> +                    FIXME("Support for custom security descriptor not implemented.\n");
> +                break;
> +            default:
> +                break;
> +        }
> +    }

IMO you should just wine_vk_find_struct twice here.

> +
> +    for (header = allocate_info_dup.pNext; header; header = header->pNext)
> +    {
> +        if (header->sType == VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO)
> +        {
> +            export_info = (VkExportMemoryAllocateInfo *)header;
> +            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;

Why VK_ERROR_OUT_OF_HOST_MEMORY?

> +                goto done;
> +            }
> +            if (object->handle_types)
> +                export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
> +            break;
> +        }
> +    }
> +
> +    /* Important to note is that Vulkan does consume imported FDs, but it doesn't consume 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_video_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;
> +            }
> +        }
> +
> +        *memory_out = wine_dev_mem_to_handle(object);

You should call WINE_VK_ADD_NON_DISPATCHABLE_MAPPING here, and 
WINE_VK_REMOVE_HANDLE_MAPPING in vkFreeMemory.

> +    }
> +
> +    done:
> +
> +    if (res != VK_SUCCESS)
> +    {
> +        if (object->dev_mem != VK_NULL_HANDLE)
> +            device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL);

No need to check for VK_NULL_HANDLE here, vkFreeMemory already does that.

> +        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;
> +
> +    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");
> +
> +    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)
> +{
> +    VkMemoryFdPropertiesKHR fd_props;
> +    VkResult res;
> +    int fd = -1;
> +
> +    TRACE("%p %u %p %p\n", device, type, handle, properties);
> +
> +    if (type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)

VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666
handleType must not be one of the handle types defined as opaque

> +    {
> +        wine_server_handle_to_fd(handle, FILE_READ_DATA, &fd, NULL);
> +    }
> +
> +    if (fd == -1)
> +        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
> +
> +    res = device->funcs.p_vkGetMemoryFdPropertiesKHR(device->device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, fd, &fd_props);

VUID-vkGetMemoryFdPropertiesKHR-handleType-00674
handleType must not be VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR

And you have to init the sType and pNext of fd_props.

> +
> +    close(fd);
> +
> +    if (res != VK_SUCCESS)
> +        return res;
> +
> +    properties->sType = VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR;
> +    properties->pNext = NULL;

You shouldn't touch those two, the application will set them.

> +    properties->memoryTypeBits = fd_props.memoryTypeBits;
> +
> +    return res;
> +}
> diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
> index 83dc90ca15e..468ab890dab 100644
> --- a/dlls/winevulkan/vulkan_private.h
> +++ b/dlls/winevulkan/vulkan_private.h
> @@ -204,6 +204,28 @@ 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;
> +};
> +

Wrapping VkDeviceMemory is problematic, because generated thunks won't 
unwrap handles in struct parameters. With this code functions using 
these structs will be broken:

VkBindAccelerationStructureMemoryInfoNV, VkBindBufferMemoryInfo, 
VkBindImageMemoryInfo, VkDeviceMemoryOpaqueCaptureAddressInfo, 
VkMappedMemoryRange, VkSparseImageMemoryBind, VkSparseMemoryBind

So you either have to either:
1. Manually implement all those functions.
2. Handle it in make_vulkan.
3. Find another way to store data per VkDeviceMemory object, e.g with 
VK_EXT_private_data.

I'm against the first option because it's a lot of manually written 
functions and future spec updates might add new problematic functions. 
The provisional video extensions add VkVideoBindMemoryKHR for example.

The best option would be the second, if you can make it work, because we 
currently have some code in vulkan.c that should be generated but has 
the same problem.

Thanks,

Georg Lehmann

> +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