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

Liam Middlebrook lmiddlebrook at nvidia.com
Tue May 18 11:03:27 CDT 2021



On 5/18/21 7:11 AM, Derek Lesho wrote:
> 
> On 5/18/21 3:35 AM, Liam Middlebrook wrote:
>>
>>
>> On 5/17/21 1:01 PM, Derek Lesho wrote:
>>> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
>>> ---
>>> v2: Addressed comments from mailing list and discord.
>>
>> You should be encouraging people giving feedback on Discord to reply 
>> to your patches here on wine-devel.
>>
>>> ---
>>>   dlls/vulkan-1/tests/vulkan.c     | 216 ++++++++++++++++
>>
>> This patch is very large. Would it make sense to split off the test to 
>> a separate commit to make review easier? (although I guess there's no 
>> overlap between the test code and the winevulkan code)
> The VK_KHR_external_memory_win32 extension has to leave 
> UNSUPPORTED_EXTENSIONS for the tests to compile, as otherwise the 
> necessary definitions aren't present in vulkan.h.  Doing this would 
> cause the situation that you indicated you want to avoid, where a 
> extension would be exposed but the functions would all have to be 
> stubs.  Alternatively, we could add VK_KHR_external_memory_win32 to 
> WINEVULKAN_INTERNAL_EXTENSIONS in the test commit, to allow the tests to 
> compile and run on windows, then remove in the commit where we actually 
> support it.  If we do that, maybe it'd even make more sense to group the 
> tests commit together with the internal extension commit so we don't 
> have dead/unused code, although it might be a bit confusing if we add a 
> new list with the name WINEVULKAN_INTERNAL_EXTENSIONS and have the first 
> extension we add to that be an extension not supported on the host.

I'm more confused by your description than I was before. Given that the 
tests stuff is in a separate file/"module" I think it's fine to just 
leave it in the same commit, nevermind on my feedback on it from before.

>>
>>>   dlls/winevulkan/make_vulkan      |  26 +-
>>>   dlls/winevulkan/vulkan.c         | 406 +++++++++++++++++++++++++++++--
>>
>> From skimming through this patch I think you could split off the code 
>> that handles buffer/image/memory creation/allocation into a separate 
>> patch that goes before support for VK_EXT_external_memory_win32. 
>> Having more granular commits here would make it easier to review, and 
>> also lower the surface area for regressions in each commit, making it 
>> easier to fix/revert if/when bugs do sneak in.
> Sounds good, although these will be more "unused helper code" commits in 
> that case.

Will they be? It looks to me like they replace the auto-generated 
thunks? There's a difference between changes you expect to be a no-op 
and changes which introduce unused code. As far as I can tell the 
changes for buffer/image/memory creation/allocation would be used, but 
are expected to be a no-op.


Thanks,

Liam Middlebrook

>>
>> I haven't reviewed the changes below in-detail yet and have no 
>> comments for them at this time, sorry I'll see if I have more time to 
>> look at this (or a later revision) later in the week.
>>
>>
>> Thanks,
>>
>> Liam Middlebrook
>>
>>>   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);
>>> +
>>> +        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_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},
>>>       "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},
>>>       "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)
>>> +        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 *),
>>>           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)
>>> +        {
>>> +            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
>>> +
>>> +    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;
>>> +            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;
>>> +
>>> +    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;
>>> +    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;
>>> +    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)) &&
>>> +        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