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

Derek Lesho dlesho at codeweavers.com
Tue May 18 09:11:06 CDT 2021


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