[PATCH 1/4] winevulkan: Implement VK_EXT_external_memory_win32.

Georg Lehmann dadschoorse at gmail.com
Mon May 3 16:54:01 CDT 2021



On 03.05.21 23:44, Georg Lehmann wrote:
> 
> On 03.05.21 18:46, Derek Lesho wrote:
>> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
>> ---
>> This commit had to be squashed in with the tests, as data structures 
>> for the extension are missing from
>> the headers when the extension is blacklisted by make_vulkan.
>> ---
>>   dlls/vulkan-1/tests/vulkan.c     | 242 +++++++++++++++++--
>>   dlls/winevulkan/loader_thunks.c  |  12 +
>>   dlls/winevulkan/loader_thunks.h  |   2 +
>>   dlls/winevulkan/make_vulkan      |  63 ++++-
>>   dlls/winevulkan/vulkan.c         | 385 +++++++++++++++++++++++++++++--
>>   dlls/winevulkan/vulkan_private.h |  22 ++
>>   6 files changed, 679 insertions(+), 47 deletions(-)
>>
> 
> Hi,
> 
> I would prefer if you could split this up in to multiple patches, e.g. 
> the host only functions and struct conversion changes in make_vulkan 
> could each be in their own commits.
> 
>> diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c
>> index 9061b2b6db8..c1350da70ee 100644
>> --- a/dlls/vulkan-1/tests/vulkan.c
>> +++ b/dlls/vulkan-1/tests/vulkan.c
>> @@ -144,7 +144,7 @@ static void test_instance_version(void)
>>               VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), 
>> VK_VERSION_PATCH(version));
>>   }
>> -static void enumerate_physical_device(VkPhysicalDevice 
>> vk_physical_device)
>> +static void enumerate_physical_device(VkInstance vk_instance, 
>> VkPhysicalDevice vk_physical_device)
>>   {
>>       VkPhysicalDeviceProperties properties;
>> @@ -224,7 +224,7 @@ static void test_enumerate_physical_device2(void)
>>       vkDestroyInstance(vk_instance, NULL);
>>   }
>> -static void enumerate_device_queues(VkPhysicalDevice vk_physical_device)
>> +static void enumerate_device_queues(VkInstance vk_instance, 
>> VkPhysicalDevice vk_physical_device)
>>   {
>>       VkPhysicalDeviceProperties device_properties;
>>       VkQueueFamilyProperties *properties;
>> @@ -283,7 +283,7 @@ static void test_physical_device_groups(void)
>>           trace("Group[%u] count %u, subset allocation %#x\n",
>>                   i, properties[i].physicalDeviceCount, 
>> properties[i].subsetAllocation);
>>           for (j = 0; j < properties[i].physicalDeviceCount; ++j)
>> -            enumerate_physical_device(properties[i].physicalDevices[j]);
>> +            enumerate_physical_device(vk_instance, 
>> properties[i].physicalDevices[j]);
>>       }
>>       if ((vr = create_device(properties->physicalDevices[0], 0, NULL, 
>> NULL, &vk_device)) < 0)
>> @@ -307,7 +307,7 @@ static void test_physical_device_groups(void)
>>       vkDestroyInstance(vk_instance, NULL);
>>   }
>> -static void test_destroy_command_pool(VkPhysicalDevice 
>> vk_physical_device)
>> +static void test_destroy_command_pool(VkInstance vk_instance, 
>> VkPhysicalDevice vk_physical_device)
>>   {
>>       VkCommandBufferAllocateInfo allocate_info;
>>       VkCommandPoolCreateInfo pool_info;
>> @@ -366,7 +366,7 @@ static void 
>> test_unsupported_instance_extensions(void)
>>       }
>>   }
>> -static void test_unsupported_device_extensions(VkPhysicalDevice 
>> vk_physical_device)
>> +static void test_unsupported_device_extensions(VkInstance 
>> vk_instance, VkPhysicalDevice vk_physical_device)
>>   {
>>       VkDevice vk_device;
>>       unsigned int i;
>> @@ -387,7 +387,7 @@ static void 
>> test_unsupported_device_extensions(VkPhysicalDevice vk_physical_devi
>>       }
>>   }
>> -static void test_private_data(VkPhysicalDevice vk_physical_device)
>> +static void test_private_data(VkInstance vk_instance, 
>> VkPhysicalDevice vk_physical_device)
>>   {
>>       PFN_vkDestroyPrivateDataSlotEXT pfn_vkDestroyPrivateDataSlotEXT;
>>       PFN_vkCreatePrivateDataSlotEXT pfn_vkCreatePrivateDataSlotEXT;
>> @@ -437,7 +437,218 @@ static void test_private_data(VkPhysicalDevice 
>> vk_physical_device)
>>       vkDestroyDevice(vk_device, NULL);
>>   }
>> -static void for_each_device(void (*test_func)(VkPhysicalDevice))
>> +uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, 
>> VkMemoryPropertyFlagBits flags)
>> +{
>> +    VkPhysicalDeviceMemoryProperties properties = {0};
>> +    unsigned int i;
>> +
>> +    vkGetPhysicalDeviceMemoryProperties(vk_physical_device, 
>> &properties);
>> +
>> +    for(i = 0; i < properties.memoryTypeCount; i++)
>> +    {
>> +        if (properties.memoryTypes[i].propertyFlags & flags)
>> +            return i;
>> +    }
>> +    return -1;
>> +}
>> +
>> +static void test_external_memory(VkInstance vk_instance, 
>> VkPhysicalDevice vk_physical_device)
>> +{
>> +    PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR 
>> pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR;
>> +    PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR;
>> +    VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info;
>> +    VkExternalBufferPropertiesKHR external_buffer_properties;
>> +    VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info;
>> +    VkExportMemoryWin32HandleInfoKHR export_handle_info;
>> +    VkImportMemoryWin32HandleInfoKHR import_handle_info;
>> +    VkExportMemoryAllocateInfoKHR export_memory_info;
>> +    VkMemoryGetWin32HandleInfoKHR get_handle_info;
>> +    VkBufferCreateInfo buffer_create_info;
>> +    VkMemoryAllocateInfo alloc_info;
>> +    uint32_t queue_family_index;
>> +    HANDLE nt_handle, kmt_handle;
>> +    VkDeviceMemory vk_memory, vk_memory_import;
>> +    VkBuffer vk_buffer;
>> +    VkDevice vk_device;
>> +    VkResult vr;
>> +
>> +    static const char *extensions[] =
>> +    {
>> +        "VK_KHR_dedicated_allocation",
>> +        "VK_KHR_external_memory",
>> +        "VK_KHR_external_memory_win32",
>> +    };
>> +
>> +    pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR =
>> +        (void*) vkGetInstanceProcAddr(vk_instance, 
>> "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
>> +
>> +    if ((vr = create_device(vk_physical_device, 
>> ARRAY_SIZE(extensions), extensions, NULL, &vk_device)))
>> +    {
>> +        skip("Failed to create device with external memory 
>> extensions, VkResult %d.\n", vr);
>> +        return;
>> +    }
>> +
>> +    pfn_vkGetMemoryWin32HandleKHR = (void *) 
>> vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
>> +
>> +    find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, 
>> &queue_family_index);
>> +
>> +    /* Most implementations only support exporting dedicated 
>> allocations */
>> +
>> +    buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
>> +    buffer_create_info.pNext = NULL;
>> +    buffer_create_info.flags = 0;
>> +    buffer_create_info.size = 1;
>> +    buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | 
>> VK_BUFFER_USAGE_TRANSFER_DST_BIT;
>> +    buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
>> +    buffer_create_info.queueFamilyIndexCount = 1;
>> +    buffer_create_info.pQueueFamilyIndices = &queue_family_index;
>> +    if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, 
>> &vk_buffer)))
>> +    {
>> +        skip("Failed to create generic buffer, VkResult %d.\n", vr);
>> +        vkDestroyDevice(vk_device, NULL);
>> +        return;
>> +    }
>> +
>> +    dedicated_alloc_info.sType = 
>> VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
>> +    dedicated_alloc_info.pNext = NULL;
>> +    dedicated_alloc_info.image = VK_NULL_HANDLE;
>> +    dedicated_alloc_info.buffer = vk_buffer;
>> +
>> +    external_buffer_info.sType = 
>> VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR;
>> +    external_buffer_info.pNext = NULL;
>> +    external_buffer_info.flags = 0;
>> +    external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | 
>> VK_BUFFER_USAGE_TRANSFER_DST_BIT;
>> +    external_buffer_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
>> +
>> +    memset(&external_buffer_properties, 0, 
>> sizeof(external_buffer_properties));
>> +    external_buffer_properties.sType = 
>> VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
>> +
>> +    
>> pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, 
>> &external_buffer_info, &external_buffer_properties);
>> +
>> +    if 
>> (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures 
>> &
>> +            
>> (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))) 
>>
>> +        skip("With desired parameters, buffers are not exportable to 
>> and importable from an NT handle.\n");
>> +    else
>> +    {
>> +        
>> ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes 
>> & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR,
>> +            "Unexpected compatibleHandleTypes %#x.\n", 
>> external_buffer_properties.externalMemoryProperties.compatibleHandleTypes); 
>>
>> +
>> +        export_memory_info.sType = 
>> VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
>> +        export_memory_info.pNext = &dedicated_alloc_info;
>> +        export_memory_info.handleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
>> +
>> +        export_handle_info.sType = 
>> VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
>> +        export_handle_info.pNext = &export_memory_info;
>> +        export_handle_info.name = L"wine_test_buffer_export_name";
>> +        export_handle_info.dwAccess = GENERIC_ALL;
>> +        export_handle_info.pAttributes = NULL;
>> +
>> +        alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
>> +        alloc_info.pNext = &export_handle_info;
>> +        alloc_info.allocationSize = 1;
>> +        alloc_info.memoryTypeIndex = 
>> find_memory_type(vk_physical_device, 
>> VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
>> +
>> +        ok(alloc_info.memoryTypeIndex != -1, "Device local memory 
>> type index was not found.\n");
>> +
>> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
>> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult 
>> %d.\n", vr);
>> +
>> +        get_handle_info.sType = 
>> VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
>> +        get_handle_info.pNext = NULL;
>> +        get_handle_info.memory = vk_memory;
>> +        get_handle_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
>> +
>> +        vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, 
>> &get_handle_info, &nt_handle);
>> +        ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, 
>> VkResult %d.\n", vr);
>> +
>> +        import_handle_info.sType = 
>> VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
>> +        import_handle_info.pNext = &dedicated_alloc_info;
>> +        import_handle_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
>> +        import_handle_info.handle = nt_handle;
>> +        import_handle_info.name = NULL;
>> +
>> +        alloc_info.pNext = &import_handle_info;
>> +
>> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, 
>> &vk_memory_import);
>> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult 
>> %d.\n", vr);
>> +        ok(vk_memory_import != vk_memory, "Expected new memory 
>> object.\n");
>> +
>> +        vkFreeMemory(vk_device, vk_memory_import, NULL);
>> +
>> +        import_handle_info.handle = NULL;
>> +        import_handle_info.name = L"wine_test_buffer_export_name";
>> +
>> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, 
>> &vk_memory_import);
>> +    todo_wine
>> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult 
>> %d.\n", vr);
>> +        if (vr == VK_SUCCESS)
>> +        {
>> +            ok(vk_memory_import != vk_memory, "Expected new memory 
>> object.\n");
>> +            vkFreeMemory(vk_device, vk_memory_import, NULL);
>> +        }
>> +        vkFreeMemory(vk_device, vk_memory, NULL);
>> +        CloseHandle(nt_handle);
>> +    }
>> +
>> +    external_buffer_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
>> +
>> +    memset(&external_buffer_properties, 0, 
>> sizeof(external_buffer_properties));
>> +    external_buffer_properties.sType = 
>> VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
>> +
>> +    
>> pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, 
>> &external_buffer_info, &external_buffer_properties);
>> +
>> +    if 
>> (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures 
>> &
>> +            
>> (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR))) 
>>
>> +        skip("With desired parameters, buffers are not exportable to 
>> and importable from a KMT handle.\n");
>> +    else
>> +    {
>> +        
>> ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes 
>> & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR,
>> +            "Unexpected compatibleHandleTypes %#x.\n", 
>> external_buffer_properties.externalMemoryProperties.compatibleHandleTypes); 
>>
>> +
>> +        export_memory_info.sType = 
>> VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
>> +        export_memory_info.pNext = &dedicated_alloc_info;
>> +        export_memory_info.handleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
>> +
>> +        alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
>> +        alloc_info.pNext = &export_memory_info;
>> +        alloc_info.allocationSize = 1;
>> +        alloc_info.memoryTypeIndex = 
>> find_memory_type(vk_physical_device, 
>> VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
>> +
>> +        ok(alloc_info.memoryTypeIndex != -1, "Device local memory 
>> type index was not found.\n");
>> +
>> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
>> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult 
>> %d.\n", vr);
>> +
>> +        get_handle_info.sType = 
>> VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
>> +        get_handle_info.pNext = NULL;
>> +        get_handle_info.memory = vk_memory;
>> +        get_handle_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
>> +
>> +        vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, 
>> &get_handle_info, &kmt_handle);
>> +        ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, 
>> VkResult %d.\n", vr);
>> +
>> +        import_handle_info.sType = 
>> VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
>> +        import_handle_info.pNext = &dedicated_alloc_info;
>> +        import_handle_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
>> +        import_handle_info.handle = kmt_handle;
>> +        import_handle_info.name = NULL;
>> +
>> +        alloc_info.pNext = &import_handle_info;
>> +
>> +        vr = vkAllocateMemory(vk_device, &alloc_info, NULL, 
>> &vk_memory_import);
>> +        ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult 
>> %d.\n", vr);
>> +        ok(vk_memory_import != vk_memory, "Expected new memory 
>> object.\n");
>> +
>> +        vkFreeMemory(vk_device, vk_memory_import, NULL);
>> +        vkFreeMemory(vk_device, vk_memory, NULL);
>> +    }
>> +
>> +    vkDestroyBuffer(vk_device, vk_buffer, NULL);
>> +    vkDestroyDevice(vk_device, NULL);
>> +}
>> +
>> +static void for_each_device(void 
>> (*test_func)(VkInstance,VkPhysicalDevice), uint32_t extension_count,
>> +        const char * const *enabled_extensions)
>>   {
>>       VkPhysicalDevice *vk_physical_devices;
>>       VkInstance vk_instance;
>> @@ -445,7 +656,7 @@ static void for_each_device(void 
>> (*test_func)(VkPhysicalDevice))
>>       uint32_t count;
>>       VkResult vr;
>> -    if ((vr = create_instance_skip(0, NULL, &vk_instance)) < 0)
>> +    if ((vr = create_instance_skip(extension_count, 
>> enabled_extensions, &vk_instance)) < 0)
>>           return;
>>       ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr);
>> @@ -463,7 +674,7 @@ static void for_each_device(void 
>> (*test_func)(VkPhysicalDevice))
>>       ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr);
>>       for (i = 0; i < count; ++i)
>> -        test_func(vk_physical_devices[i]);
>> +        test_func(vk_instance, vk_physical_devices[i]);
>>       heap_free(vk_physical_devices);
>> @@ -472,13 +683,16 @@ static void for_each_device(void 
>> (*test_func)(VkPhysicalDevice))
>>   START_TEST(vulkan)
>>   {
>> +    static const char *external_memory_capabilities = 
>> "VK_KHR_external_memory_capabilities";
>> +
>>       test_instance_version();
>> -    for_each_device(enumerate_physical_device);
>> +    for_each_device(enumerate_physical_device, 0, NULL);
>>       test_enumerate_physical_device2();
>> -    for_each_device(enumerate_device_queues);
>> +    for_each_device(enumerate_device_queues, 0, NULL);
>>       test_physical_device_groups();
>> -    for_each_device(test_destroy_command_pool);
>> +    for_each_device(test_destroy_command_pool, 0, NULL);
>>       test_unsupported_instance_extensions();
>> -    for_each_device(test_unsupported_device_extensions);
>> -    for_each_device(test_private_data);
>> +    for_each_device(test_unsupported_device_extensions, 0, NULL);
>> +    for_each_device(test_private_data, 0, NULL);
>> +    for_each_device(test_external_memory, 1, 
>> &external_memory_capabilities);
>>   }
>> diff --git a/dlls/winevulkan/loader_thunks.c 
>> b/dlls/winevulkan/loader_thunks.c
>> index 69fcd44160e..471999a3821 100644
>> --- a/dlls/winevulkan/loader_thunks.c
>> +++ b/dlls/winevulkan/loader_thunks.c
>> @@ -1448,6 +1448,16 @@ VkResult WINAPI 
>> vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalM
>>       return unix_funcs->p_vkGetMemoryHostPointerPropertiesEXT(device, 
>> handleType, pHostPointer, pMemoryHostPointerProperties);
>>   }
>> +VkResult WINAPI vkGetMemoryWin32HandleKHR(VkDevice device, const 
>> VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo, HANDLE *pHandle)
>> +{
>> +    return unix_funcs->p_vkGetMemoryWin32HandleKHR(device, 
>> pGetWin32HandleInfo, pHandle);
>> +}
>> +
>> +VkResult WINAPI vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, 
>> VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, 
>> VkMemoryWin32HandlePropertiesKHR *pMemoryWin32HandleProperties)
>> +{
>> +    return unix_funcs->p_vkGetMemoryWin32HandlePropertiesKHR(device, 
>> handleType, handle, pMemoryWin32HandleProperties);
>> +}
>> +
>>   VkResult WINAPI vkGetPerformanceParameterINTEL(VkDevice device, 
>> VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL 
>> *pValue)
>>   {
>>       return unix_funcs->p_vkGetPerformanceParameterINTEL(device, 
>> parameter, pValue);
>> @@ -2223,6 +2233,8 @@ static const struct vulkan_func 
>> vk_device_dispatch_table[] =
>>       {"vkGetImageSparseMemoryRequirements2KHR", 
>> &vkGetImageSparseMemoryRequirements2KHR},
>>       {"vkGetImageSubresourceLayout", &vkGetImageSubresourceLayout},
>>       {"vkGetMemoryHostPointerPropertiesEXT", 
>> &vkGetMemoryHostPointerPropertiesEXT},
>> +    {"vkGetMemoryWin32HandleKHR", &vkGetMemoryWin32HandleKHR},
>> +    {"vkGetMemoryWin32HandlePropertiesKHR", 
>> &vkGetMemoryWin32HandlePropertiesKHR},
>>       {"vkGetPerformanceParameterINTEL", 
>> &vkGetPerformanceParameterINTEL},
>>       {"vkGetPipelineCacheData", &vkGetPipelineCacheData},
>>       {"vkGetPipelineExecutableInternalRepresentationsKHR", 
>> &vkGetPipelineExecutableInternalRepresentationsKHR},
>> diff --git a/dlls/winevulkan/loader_thunks.h 
>> b/dlls/winevulkan/loader_thunks.h
>> index e7257cef508..031b7f5652b 100644
>> --- a/dlls/winevulkan/loader_thunks.h
>> +++ b/dlls/winevulkan/loader_thunks.h
>> @@ -304,6 +304,8 @@ struct unix_funcs
>>       void (WINAPI 
>> *p_vkGetImageSparseMemoryRequirements2KHR)(VkDevice, const 
>> VkImageSparseMemoryRequirementsInfo2 *, uint32_t *, 
>> VkSparseImageMemoryRequirements2 *);
>>       void (WINAPI *p_vkGetImageSubresourceLayout)(VkDevice, VkImage, 
>> const VkImageSubresource *, VkSubresourceLayout *);
>>       VkResult (WINAPI 
>> *p_vkGetMemoryHostPointerPropertiesEXT)(VkDevice, 
>> VkExternalMemoryHandleTypeFlagBits, const void *, 
>> VkMemoryHostPointerPropertiesEXT *);
>> +    VkResult (WINAPI *p_vkGetMemoryWin32HandleKHR)(VkDevice, const 
>> VkMemoryGetWin32HandleInfoKHR *, HANDLE *);
>> +    VkResult (WINAPI 
>> *p_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice, 
>> VkExternalMemoryHandleTypeFlagBits, HANDLE, 
>> VkMemoryWin32HandlePropertiesKHR *);
>>       VkResult (WINAPI *p_vkGetPerformanceParameterINTEL)(VkDevice, 
>> VkPerformanceParameterTypeINTEL, VkPerformanceValueINTEL *);
>>       VkResult (WINAPI 
>> *p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice, 
>> uint32_t *, VkTimeDomainEXT *);
>>       VkResult (WINAPI 
>> *p_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice, 
>> uint32_t *, VkCooperativeMatrixPropertiesNV *);
>> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
>> index b1877acda17..0a0e3bac299 100755
>> --- a/dlls/winevulkan/make_vulkan
>> +++ b/dlls/winevulkan/make_vulkan
>> @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [
>>       "VK_EXT_pipeline_creation_feedback",
>>       "VK_GOOGLE_display_timing",
>>       "VK_KHR_external_fence_win32",
>> -    "VK_KHR_external_memory_win32",
>>       "VK_KHR_external_semaphore_win32",
>>       # Relates to external_semaphore and needs type conversions in 
>> bitflags.
>>       "VK_KHR_shared_presentable_image", # Needs WSI work.
>> @@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [
>>       "VK_EXT_external_memory_dma_buf",
>>       "VK_EXT_image_drm_format_modifier",
>>       "VK_KHR_external_fence_fd",
>> -    "VK_KHR_external_memory_fd",
>>       "VK_KHR_external_semaphore_fd",
>>       # Extensions which require callback handling
>> @@ -154,6 +152,8 @@ class ThunkType(Enum):
>>   #   - PRIVATE thunks can be used in custom implementations for
>>   #     struct conversion.
>>   # - loader_thunk sets whether to create a thunk for unix_funcs.
>> +# - host_only sets whether to preclude the function from the
>> +#   win32-facing dispatch table.
>>   FUNCTION_OVERRIDES = {
>>       # Global functions
>>       "vkCreateInstance" : {"dispatch" : False, "driver" : True, 
>> "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE},
>> @@ -169,7 +169,7 @@ FUNCTION_OVERRIDES = {
>>       "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": 
>> False, "thunk": ThunkType.NONE},
>>       "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" 
>> : False, "thunk" : ThunkType.NONE},
>>       "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : 
>> False, "thunk" : ThunkType.NONE},
>> -    "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : 
>> False, "driver" : False, "thunk" : ThunkType.NONE},
>> +    "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : 
>> True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>>       "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : 
>> False, "driver" : False, "thunk" : ThunkType.NONE},
>>       "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : 
>> False, "driver" : False, "thunk" : ThunkType.NONE},
>>       "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : 
>> True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>> @@ -178,11 +178,13 @@ FUNCTION_OVERRIDES = {
>>       # Device functions
>>       "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : 
>> False, "thunk" : ThunkType.NONE},
>> +    "vkAllocateMemory" : {"dispatch" : True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>>       "vkCmdExecuteCommands" : {"dispatch" : True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>>       "vkCreateCommandPool" : {"dispatch": True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>>       "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>>       "vkDestroyDevice" : {"dispatch" : True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>>       "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>> +    "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : 
>> ThunkType.NONE},
>>       "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, 
>> "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE},
>>       "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>>       "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, 
>> "thunk" : ThunkType.NONE},
>> @@ -213,7 +215,7 @@ FUNCTION_OVERRIDES = {
>>       "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : 
>> False, "driver" : False, "thunk" : ThunkType.NONE},
>>       # VK_KHR_external_memory_capabilities
>> -    "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : 
>> False, "driver" : False, "thunk" : ThunkType.NONE},
>> +    "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : 
>> True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>>       "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : 
>> True, "driver" : False, "thunk" : ThunkType.PRIVATE},
>>       # VK_KHR_external_semaphore_capabilities
>> @@ -249,12 +251,22 @@ FUNCTION_OVERRIDES = {
>>       # VK_EXT_debug_marker
>>       "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : 
>> False, "thunk" : ThunkType.PRIVATE},
>>       "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : 
>> False, "thunk" : ThunkType.PRIVATE},
>> +
>> +    # VK_KHR_external_memory_win32
>> +    "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : 
>> False, "thunk" : ThunkType.NONE},
>> +    "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, 
>> "driver" : False, "thunk" : ThunkType.NONE},
>> +
>> +    # VK_KHR_external_memory_fd
>> +    "vkGetMemoryFdKHR" : {"dispatch" : True, "driver" : False, 
>> "thunk" : ThunkType.NONE,  "host_only" : True},
>> +    "vkGetMemoryFdPropertiesKHR" : {"dispatch" : True, "driver" : 
>> False, "thunk" : ThunkType.NONE, "host_only" : True},
> 
> Would it make sense to added a new value to ThunkType instead, e.g. 
> ThunkType.NOT_EXPOSED?
> 
>>   }
>> -STRUCT_CHAIN_CONVERSIONS = [
>> -    "VkDeviceCreateInfo",
>> -    "VkInstanceCreateInfo",
>> -]
>> +STRUCT_CHAIN_CONVERSIONS = {
>> +    "VkDeviceCreateInfo": 
>> ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"],
>> +    "VkInstanceCreateInfo": 
>> ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
>> +    "VkPhysicalDeviceImageFormatInfo2": [],
>> +    "VkMemoryAllocateInfo": 
>> ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", 
>> "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"],
>> +}
>>   class Direction(Enum):
>> @@ -532,6 +544,7 @@ class VkFunction(object):
>>           self.driver = func_info["driver"] if func_info else False
>>           self.thunk_type = func_info["thunk"] if func_info else 
>> ThunkType.PUBLIC
>>           self.loader_thunk_type = func_info["loader_thunk"] if 
>> func_info and "loader_thunk" in func_info else ThunkType.PUBLIC
>> +        self.host_only = func_info["host_only"] if func_info and 
>> "host_only" in func_info else False
>>           # Required is set while parsing which APIs and types are 
>> required
>>           # and is used by the code generation.
>> @@ -651,6 +664,9 @@ class VkFunction(object):
>>       def needs_private_thunk(self):
>>           return self.thunk_type == ThunkType.PRIVATE
>> +    def needs_win_exclusion(self):
>> +        return self.host_only
>> +
>>       def pfn(self, prefix="p", call_conv=None, conv=False):
>>           """ Create function pointer. """
>> @@ -1028,6 +1044,8 @@ class VkHandle(object):
>>               return 
>> "wine_debug_report_callback_from_handle({0})->debug_callback".format(name) 
>>
>>           if self.name == "VkSurfaceKHR":
>>               return 
>> "wine_surface_from_handle({0})->surface".format(name)
>> +        if self.name == "VkDeviceMemory":
>> +            return "wine_dev_mem_from_handle({0})->dev_mem".format(name)
>>           native_handle_name = None
>> @@ -2115,9 +2133,10 @@ class FreeFunction(object):
>>   class StructChainConversionFunction(object):
>> -    def __init__(self, direction, struct):
>> +    def __init__(self, direction, struct, ignores):
>>           self.direction = direction
>>           self.struct = struct
>> +        self.ignores = ignores
>>           self.type = struct.name
>>           self.name = "convert_{0}_struct_chain".format(self.type)
>> @@ -2143,8 +2162,8 @@ class StructChainConversionFunction(object):
>>           body += "        {\n"
>>           # Ignore to not confuse host loader.
> 
> This comment is now misplaced.
> 
>> -        body += "        case 
>> VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:\n"
>> -        body += "        case 
>> VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:\n"
>> +        for i in self.ignores:
>> +            body += "        case {0}:\n".format(i)
>>           body += "            break;\n\n"
>>           for e in self.struct.struct_extensions:
>> @@ -2153,6 +2172,9 @@ class StructChainConversionFunction(object):
>>               stype = next(x for x in e.members if x.name == "sType")
>> +            if stype.values in self.ignores:
>> +                continue
>> +
>>               body += "        case {0}:\n".format(stype.values)
>>               body += "        {\n"
>> @@ -2250,7 +2272,7 @@ class VkGenerator(object):
>>           for struct in self.registry.structs:
>>               if struct.name in STRUCT_CHAIN_CONVERSIONS:
>> -                
>> self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, 
>> struct))
>> +                
>> self.struct_chain_conversions.append(StructChainConversionFunction(Direction.INPUT, 
>> struct, STRUCT_CHAIN_CONVERSIONS[struct.name]))
>>                   
>> self.struct_chain_conversions.append(FreeStructChainFunction(struct))
>>       def _generate_copyright(self, f, spec_file=False):
>> @@ -2292,6 +2314,9 @@ class VkGenerator(object):
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>> +
>>               if vk_func.is_global_func():
>>                   continue
>> @@ -2382,6 +2407,8 @@ class VkGenerator(object):
>>           for vk_func in self.registry.funcs.values():
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               if vk_func.loader_thunk_type == ThunkType.NONE:
>>                   continue
>> @@ -2403,6 +2430,8 @@ class VkGenerator(object):
>>                   continue
>>               if vk_func.needs_thunk() and not 
>> vk_func.needs_private_thunk():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               if vk_func.is_core_func():
>>                   f.write("{0};\n".format(vk_func.prototype("WINAPI", 
>> prefix=prefix)))
>> @@ -2510,6 +2539,8 @@ class VkGenerator(object):
>>           for vk_func in self.registry.funcs.values():
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               if vk_func.loader_thunk_type != ThunkType.PUBLIC:
>>                   continue
>> @@ -2519,6 +2550,8 @@ class VkGenerator(object):
>>           for vk_func in self.registry.device_funcs:
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
>>           f.write("};\n\n")
>> @@ -2527,6 +2560,8 @@ class VkGenerator(object):
>>           for vk_func in self.registry.phys_dev_funcs:
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
>>           f.write("};\n\n")
>> @@ -2535,6 +2570,8 @@ class VkGenerator(object):
>>           for vk_func in self.registry.instance_funcs:
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               f.write("    {{\"{0}\", &{0}}},\n".format(vk_func.name))
>>           f.write("};\n\n")
>> @@ -2592,6 +2629,8 @@ class VkGenerator(object):
>>           for vk_func in self.registry.funcs.values():
>>               if not vk_func.is_required():
>>                   continue
>> +            if vk_func.needs_win_exclusion():
>> +                continue
>>               if vk_func.loader_thunk_type == ThunkType.NONE:
>>                   continue
>> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
>> index 45eda78e997..e95860cb3fa 100644
>> --- a/dlls/winevulkan/vulkan.c
>> +++ b/dlls/winevulkan/vulkan.c
>> @@ -25,6 +25,7 @@
>>   #include <time.h>
>>   #include <stdarg.h>
>>   #include <stdlib.h>
>> +#include <unistd.h>
>>   #include "ntstatus.h"
>>   #define WIN32_NO_STATUS
>> @@ -34,6 +35,8 @@
>>   #include "winuser.h"
>>   #include "winternl.h"
>> +#include "wine/server.h"
>> +
>>   #include "vulkan_private.h"
>>   WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
>> @@ -265,6 +268,14 @@ static struct VkPhysicalDevice_T 
>> *wine_vk_physical_device_alloc(struct VkInstanc
>>       {
>>           if 
>> (wine_vk_device_extension_supported(host_properties[i].extensionName))
>>           {
>> +            if (!strcmp(host_properties[i].extensionName, 
>> "VK_KHR_external_memory_fd"))
>> +            {
>> +                TRACE("Substituting VK_KHR_external_memory_fd for 
>> VK_KHR_external_memory_win32\n");
>> +
>> +                snprintf(host_properties[i].extensionName, 
>> sizeof(host_properties[i].extensionName),
>> +                        VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
>> +                host_properties[i].specVersion = 
>> VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION;
>> +            }
>>               TRACE("Enabling extension '%s' for physical device 
>> %p\n", host_properties[i].extensionName, object);
>>               num_properties++;
>>           }
>> @@ -368,12 +379,16 @@ static void 
>> wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info)
>>       }
>>       free_VkDeviceCreateInfo_struct_chain(create_info);
>> +
>> +    if (create_info->enabledExtensionCount)
>> +        free((void *)create_info->ppEnabledExtensionNames);
>>   }
>>   static VkResult wine_vk_device_convert_create_info(const 
>> VkDeviceCreateInfo *src,
>>           VkDeviceCreateInfo *dst)
>>   {
>>       VkDeviceGroupDeviceCreateInfo *group_info;
>> +    const char **enabled_extensions;
>>       unsigned int i;
>>       VkResult res;
>> @@ -406,6 +421,39 @@ static VkResult 
>> wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src
>>       dst->enabledLayerCount = 0;
>>       dst->ppEnabledLayerNames = NULL;
>> +    if (src->enabledExtensionCount > 0)
>> +    {
>> +        enabled_extensions = calloc(src->enabledExtensionCount, 
>> sizeof(*src->ppEnabledExtensionNames));
>> +        if (!enabled_extensions)
>> +        {
>> +            if ((group_info = wine_vk_find_struct(dst, 
>> DEVICE_GROUP_DEVICE_CREATE_INFO)))
>> +                free((void *)group_info->pPhysicalDevices);
>> +            free_VkDeviceCreateInfo_struct_chain(dst);
>> +            return VK_ERROR_OUT_OF_HOST_MEMORY;
>> +        }
>> +
>> +        for (i = 0; i < src->enabledExtensionCount; i++)
>> +        {
>> +            if (!strcmp(src->ppEnabledExtensionNames[i], 
>> "VK_KHR_external_memory_fd"))
>> +            {
>> +                if ((group_info = wine_vk_find_struct(dst, 
>> DEVICE_GROUP_DEVICE_CREATE_INFO)))
>> +                    free((void *)group_info->pPhysicalDevices);
>> +                free_VkDeviceCreateInfo_struct_chain(dst);
>> +                free(enabled_extensions);
>> +                return VK_ERROR_EXTENSION_NOT_PRESENT;
>> +            }
> 
> Why do you check this? It shouldn't be exposed to the app in any way.
> 
>> +            else if (!strcmp(src->ppEnabledExtensionNames[i], 
>> "VK_KHR_external_memory_win32"))
>> +            {
>> +                enabled_extensions[i] = "VK_KHR_external_memory_fd";
>> +            }
>> +            else
>> +            {
>> +                enabled_extensions[i] = src->ppEnabledExtensionNames[i];
>> +            }
>> +        }
>> +        dst->ppEnabledExtensionNames = enabled_extensions;
>> +    }
>> +
>>       TRACE("Enabled %u extensions.\n", dst->enabledExtensionCount);
>>       for (i = 0; i < dst->enabledExtensionCount; i++)
>>       {
>> @@ -1300,57 +1348,106 @@ void WINAPI 
>> wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice
>>   void WINAPI 
>> wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice 
>> phys_dev,
>>           const VkPhysicalDeviceExternalBufferInfo *buffer_info, 
>> VkExternalBufferProperties *properties)
>>   {
>> +    VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
>> +
>>       TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
>> -    memset(&properties->externalMemoryProperties, 0, 
>> sizeof(properties->externalMemoryProperties));
>> +
>> +    if (buffer_info_dup.handleType & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
>> +        buffer_info_dup.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +
>> +    thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, 
>> &buffer_info_dup, properties);
>> +
>> +    if 
>> (properties->externalMemoryProperties.exportFromImportedHandleTypes & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
>> +        
>> properties->externalMemoryProperties.exportFromImportedHandleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>> +    if (properties->externalMemoryProperties.compatibleHandleTypes & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
>> +        properties->externalMemoryProperties.compatibleHandleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>>   }
>>   void WINAPI 
>> wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice 
>> phys_dev,
>>           const VkPhysicalDeviceExternalBufferInfo *buffer_info, 
>> VkExternalBufferProperties *properties)
>>   {
>> +    VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
>> +
>>       TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
>> -    memset(&properties->externalMemoryProperties, 0, 
>> sizeof(properties->externalMemoryProperties));
>> +
>> +    if (buffer_info_dup.handleType & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
>> +        buffer_info_dup.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +
>> +    thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev, 
>> &buffer_info_dup, properties);
>> +
>> +    if 
>> (properties->externalMemoryProperties.exportFromImportedHandleTypes & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
>> +        
>> properties->externalMemoryProperties.exportFromImportedHandleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>> +    if (properties->externalMemoryProperties.compatibleHandleTypes & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
>> +        properties->externalMemoryProperties.compatibleHandleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>>   }
>> -VkResult WINAPI 
>> wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev,
>> +static VkResult 
>> wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice 
>> phys_dev,
>> +        VkResult 
>> (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const 
>> VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *),
> 
> vkGetPhysicalDeviceImageFormatProperties2KHR and 
> vkGetPhysicalDeviceImageFormatProperties2 are equivalent, you should 
> just always use thunk_vkGetPhysicalDeviceImageFormatProperties2.
> 

Ignore this part, I see why it's needed, one might not be exposed on the 
host.

>>           const VkPhysicalDeviceImageFormatInfo2 *format_info, 
>> VkImageFormatProperties2 *properties)
>>   {
>> +    VkPhysicalDeviceExternalImageFormatInfo *external_image_info_host 
>> = NULL;
>> +    const VkPhysicalDeviceExternalImageFormatInfo *external_image_info;
>> +    VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info;
>>       VkExternalImageFormatProperties *external_image_properties;
>>       VkResult res;
>> -    TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
>> +    if ((external_image_info = wine_vk_find_struct(format_info, 
>> PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO)))
>> +    {
>> +        if (external_image_info->handleType & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
>> +        {
>> +            if ((res = 
>> convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, 
>> &format_info_host)) < 0)
>> +            {
>> +                WARN("Failed to convert 
>> VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res);
>> +                return res;
>> +            }
>> +
>> +            external_image_info_host = 
>> wine_vk_find_struct(&format_info_host, 
>> PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
>> +            external_image_info_host->handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +        }
>> +        if (external_image_info->handleType &~ 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
>> +        {
>> +            WARN("Unsupported handle type %#x.\n", 
>> external_image_info->handleType);
>> +            return VK_ERROR_FORMAT_NOT_SUPPORTED;
>> +        }
>> +    }
>> +
>> +    res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, 
>> &format_info_host, properties);
>> -    res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, 
>> format_info, properties);
>> +    if (external_image_info_host)
>> +        
>> free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host);
>>       if ((external_image_properties = wine_vk_find_struct(properties, 
>> EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
>>       {
>>           VkExternalMemoryProperties *p = 
>> &external_image_properties->externalMemoryProperties;
>> -        p->externalMemoryFeatures = 0;
>> -        p->exportFromImportedHandleTypes = 0;
>> -        p->compatibleHandleTypes = 0;
>> +        if (p->exportFromImportedHandleTypes & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
>> +        {
>> +            p->exportFromImportedHandleTypes &= 
>> ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +            p->exportFromImportedHandleTypes |= 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>> +        }
>> +        if (p->compatibleHandleTypes & 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
>> +        {
>> +            p->compatibleHandleTypes &= 
>> ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +            p->compatibleHandleTypes |= 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
>> +        } >       }
>>       return res;
>>   }
>> -VkResult WINAPI 
>> wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice 
>> phys_dev,
>> +VkResult WINAPI 
>> wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev,
>>           const VkPhysicalDeviceImageFormatInfo2 *format_info, 
>> VkImageFormatProperties2 *properties)
>>   {
>> -    VkExternalImageFormatProperties *external_image_properties;
>> -    VkResult res;
>> -
>>       TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
>> -    res = 
>> thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, 
>> format_info, properties);
>> +    return 
>> wine_vk_get_physical_device_image_format_properties_2(phys_dev, 
>> thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, 
>> properties);
>> +}
>> -    if ((external_image_properties = wine_vk_find_struct(properties, 
>> EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
>> -    {
>> -        VkExternalMemoryProperties *p = 
>> &external_image_properties->externalMemoryProperties;
>> -        p->externalMemoryFeatures = 0;
>> -        p->exportFromImportedHandleTypes = 0;
>> -        p->compatibleHandleTypes = 0;
>> -    }
>> +VkResult WINAPI 
>> wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice 
>> phys_dev,
>> +        const VkPhysicalDeviceImageFormatInfo2 *format_info, 
>> VkImageFormatProperties2 *properties)
>> +{
>> +    TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
>> -    return res;
>> +    return 
>> wine_vk_get_physical_device_image_format_properties_2(phys_dev, 
>> thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, 
>> properties);
>>   }
>>   /* From ntdll/unix/sync.c */
>> @@ -1860,3 +1957,249 @@ VkResult WINAPI 
>> wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu
>>       return thunk_vkDebugMarkerSetObjectNameEXT(device, 
>> &wine_name_info);
>>   }
>> +
>> +static HANDLE create_video_resource(int fd, LPCWSTR name)
>> +{
>> +    HANDLE ret = INVALID_HANDLE_VALUE;
>> +
>> +    if (name)
>> +        FIXME("Naming video resources not supported.\n");
>> +
>> +    wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
>> +
>> +    return ret;
>> +}
>> +
>> +VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const 
>> VkMemoryAllocateInfo *allocate_info,
>> +    const VkAllocationCallbacks *allocator, VkDeviceMemory *memory_out)
>> +{
>> +    const VkImportMemoryWin32HandleInfoKHR *handle_import_info = NULL;
>> +    const VkExportMemoryWin32HandleInfoKHR *handle_export_info = NULL;
>> +    VkMemoryAllocateInfo allocate_info_dup = *allocate_info;
>> +    VkExportMemoryAllocateInfo *export_info = NULL;
>> +    VkImportMemoryFdInfoKHR fd_import_info;
>> +    const VkBaseOutStructure *header;
>> +    struct wine_dev_mem *object;
>> +    VkResult res;
>> +    int fd;
>> +
>> +#if defined(USE_STRUCT_CONVERSION)
>> +        VkMemoryAllocateInfo_host allocate_info_host;
>> +        VkMemoryGetFdInfoKHR_host get_fd_info;
>> +#else
>> +        VkMemoryAllocateInfo allocate_info_host;
>> +        VkMemoryGetFdInfoKHR get_fd_info;
>> +#endif
>> +
>> +    TRACE("%p %p %p %p\n", device, allocate_info, allocator, 
>> memory_out);
>> +
>> +    if (allocator)
>> +        FIXME("Support for allocation callbacks not implemented yet\n");
>> +
>> +    if ((res = 
>> convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, 
>> &allocate_info_dup)) < 0)
>> +    {
>> +        WARN("Failed to convert VkMemoryAllocateInfo pNext chain, 
>> res=%d.\n", res);
>> +        return res;
>> +    }
>> +
>> +    if (!(object = calloc(1, sizeof(*object))))
>> +    {
>> +        free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
>> +        return VK_ERROR_OUT_OF_HOST_MEMORY;
>> +    }
>> +
>> +    object->dev_mem = VK_NULL_HANDLE;
>> +    object->handle = INVALID_HANDLE_VALUE;
>> +    fd_import_info.fd = -1;
>> +    fd_import_info.pNext = NULL;
>> +
>> +    /* find and process handle import/export info and grab it */
>> +    for (header = allocate_info->pNext; header; header = header->pNext)
>> +    {
>> +        switch (header->sType)
>> +        {
>> +            case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
>> +                handle_import_info = (const 
>> VkImportMemoryWin32HandleInfoKHR *)header;
>> +                break;
>> +            case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
>> +                handle_export_info = (const 
>> VkExportMemoryWin32HandleInfoKHR *)header;
>> +                if (handle_export_info->pAttributes && 
>> handle_export_info->pAttributes->lpSecurityDescriptor)
>> +                    FIXME("Support for custom security descriptor not 
>> implemented.\n");
>> +                break;
>> +            default:
>> +                break;
>> +        }
>> +    }
> 
> IMO you should just wine_vk_find_struct twice here.
> 
>> +
>> +    for (header = allocate_info_dup.pNext; header; header = 
>> header->pNext)
>> +    {
>> +        if (header->sType == 
>> VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO)
>> +        {
>> +            export_info = (VkExportMemoryAllocateInfo *)header;
>> +            object->handle_types = export_info->handleTypes;
>> +            if (object->handle_types &~ 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
>> +            {
>> +                res = VK_ERROR_OUT_OF_HOST_MEMORY;
> 
> Why VK_ERROR_OUT_OF_HOST_MEMORY?
> 
>> +                goto done;
>> +            }
>> +            if (object->handle_types)
>> +                export_info->handleTypes = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +            break;
>> +        }
>> +    }
>> +
>> +    /* Important to note is that Vulkan does consume imported FDs, 
>> but it doesn't consume imported HANDLEs */
>> +    if (handle_import_info)
>> +    {
>> +        fd_import_info.sType = 
>> VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
>> +        fd_import_info.pNext = allocate_info_dup.pNext;
>> +        fd_import_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +
>> +        switch (handle_import_info->handleType)
>> +        {
>> +            case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
>> +                if (handle_import_info->handle)
>> +                    NtDuplicateObject( NtCurrentProcess(), 
>> handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, 
>> DUPLICATE_SAME_ACCESS );
>> +                else if (handle_import_info->name)
>> +                    FIXME("Importing device memory by resource name 
>> not supported.\n");
>> +                break;
>> +            default:
>> +                WARN("Invalid handle type %08x passed in.\n", 
>> handle_import_info->handleType);
>> +                res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
>> +                goto done;
>> +        }
>> +
>> +        if (object->handle != INVALID_HANDLE_VALUE)
>> +            wine_server_handle_to_fd(object->handle, FILE_READ_DATA, 
>> &fd_import_info.fd, NULL);
>> +
>> +        if (fd_import_info.fd == -1)
>> +        {
>> +            TRACE("Couldn't access resource handle or name. type=%08x 
>> handle=%p name=%s\n", handle_import_info->handleType, 
>> handle_import_info->handle,
>> +                    handle_import_info->name ? 
>> debugstr_w(handle_import_info->name) : "");
>> +            res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
>> +            goto done;
>> +        }
>> +    }
>> +
>> +    allocate_info_host.sType = allocate_info_dup.sType;
>> +    allocate_info_host.pNext = fd_import_info.fd == -1 ? 
>> allocate_info_dup.pNext : &fd_import_info;
>> +    allocate_info_host.allocationSize = 
>> allocate_info_dup.allocationSize;
>> +    allocate_info_host.memoryTypeIndex = 
>> allocate_info_dup.memoryTypeIndex;
>> +
>> +    if ((res = device->funcs.p_vkAllocateMemory(device->device, 
>> &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS)
>> +    {
>> +        if (object->handle == INVALID_HANDLE_VALUE && export_info && 
>> export_info->handleTypes)
>> +        {
>> +            get_fd_info.sType = 
>> VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
>> +            get_fd_info.pNext = NULL;
>> +            get_fd_info.memory = object->dev_mem;
>> +            get_fd_info.handleType = 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
>> +
>> +            if (device->funcs.p_vkGetMemoryFdKHR(device->device, 
>> &get_fd_info, &fd) == VK_SUCCESS)
>> +            {
>> +                object->handle = create_video_resource(fd, 
>> handle_export_info ? handle_export_info->name : NULL);
>> +                object->access = handle_export_info ? 
>> handle_export_info->dwAccess : GENERIC_ALL;
>> +                if (handle_export_info && 
>> handle_export_info->pAttributes)
>> +                    object->inherit = 
>> handle_export_info->pAttributes->bInheritHandle;
>> +                else
>> +                    object->inherit = FALSE;
>> +                close(fd);
>> +            }
>> +
>> +            if (object->handle == INVALID_HANDLE_VALUE)
>> +            {
>> +                res = VK_ERROR_OUT_OF_HOST_MEMORY;
>> +                goto done;
>> +            }
>> +        }
>> +
>> +        *memory_out = wine_dev_mem_to_handle(object);
> 
> You should call WINE_VK_ADD_NON_DISPATCHABLE_MAPPING here, and 
> WINE_VK_REMOVE_HANDLE_MAPPING in vkFreeMemory.
> 
>> +    }
>> +
>> +    done:
>> +
>> +    if (res != VK_SUCCESS)
>> +    {
>> +        if (object->dev_mem != VK_NULL_HANDLE)
>> +            device->funcs.p_vkFreeMemory(device->device, 
>> object->dev_mem, NULL);
> 
> No need to check for VK_NULL_HANDLE here, vkFreeMemory already does that.
> 
>> +        if (fd_import_info.fd != -1)
>> +            close(fd_import_info.fd);
>> +        if (object->handle != INVALID_HANDLE_VALUE)
>> +            NtClose(object->handle);
>> +        free(object);
>> +    }
>> +
>> +    free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
>> +
>> +    return res;
>> +}
>> +
>> +VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device,
>> +    const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle)
>> +{
>> +    struct wine_dev_mem *dev_mem = 
>> wine_dev_mem_from_handle(handle_info->memory);
>> +    const VkBaseInStructure *chain;
>> +
>> +    TRACE("%p, %p %p\n", device, handle_info, handle);
>> +
>> +    if (!(dev_mem->handle_types & handle_info->handleType))
>> +        return VK_ERROR_OUT_OF_HOST_MEMORY;
>> +
>> +    if ((chain = handle_info->pNext))
>> +        FIXME("Ignoring a linked structure of type %u.\n", 
>> chain->sType);
>> +
>> +    switch(handle_info->handleType)
>> +    {
>> +        case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
>> +            return !NtDuplicateObject( NtCurrentProcess(), 
>> dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, 
>> dev_mem->inherit ? OBJ_INHERIT : 0, 0) ?
>> +                VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY;
>> +        default:
>> +            return VK_ERROR_UNKNOWN;
>> +    }
>> +}
>> +
>> +void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, 
>> const VkAllocationCallbacks *allocator)
>> +{
>> +    struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
>> +
>> +    TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), 
>> allocator);
>> +
>> +    if (allocator)
>> +        FIXME("Support for allocation callbacks not implemented yet\n");
>> +
>> +    device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, 
>> NULL);
>> +    if (dev_mem->handle != INVALID_HANDLE_VALUE)
>> +        NtClose(dev_mem->handle);
>> +    free(dev_mem);
>> +}
>> +
>> +VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice 
>> device,
>> +        VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, 
>> VkMemoryWin32HandlePropertiesKHR *properties)
>> +{
>> +    VkMemoryFdPropertiesKHR fd_props;
>> +    VkResult res;
>> +    int fd = -1;
>> +
>> +    TRACE("%p %u %p %p\n", device, type, handle, properties);
>> +
>> +    if (type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT)
> 
> VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666
> handleType must not be one of the handle types defined as opaque
> 
>> +    {
>> +        wine_server_handle_to_fd(handle, FILE_READ_DATA, &fd, NULL);
>> +    }
>> +
>> +    if (fd == -1)
>> +        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
>> +
>> +    res = device->funcs.p_vkGetMemoryFdPropertiesKHR(device->device, 
>> VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, fd, &fd_props);
> 
> VUID-vkGetMemoryFdPropertiesKHR-handleType-00674
> handleType must not be VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
> 
> And you have to init the sType and pNext of fd_props.
> 
>> +
>> +    close(fd);
>> +
>> +    if (res != VK_SUCCESS)
>> +        return res;
>> +
>> +    properties->sType = 
>> VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR;
>> +    properties->pNext = NULL;
> 
> You shouldn't touch those two, the application will set them.
> 
>> +    properties->memoryTypeBits = fd_props.memoryTypeBits;
>> +
>> +    return res;
>> +}
>> diff --git a/dlls/winevulkan/vulkan_private.h 
>> b/dlls/winevulkan/vulkan_private.h
>> index 83dc90ca15e..468ab890dab 100644
>> --- a/dlls/winevulkan/vulkan_private.h
>> +++ b/dlls/winevulkan/vulkan_private.h
>> @@ -204,6 +204,28 @@ static inline VkSurfaceKHR 
>> wine_surface_to_handle(struct wine_surface *surface)
>>       return (VkSurfaceKHR)(uintptr_t)surface;
>>   }
>> +struct wine_dev_mem
>> +{
>> +    VkDeviceMemory dev_mem;
>> +
>> +    VkExternalMemoryHandleTypeFlagBits handle_types;
>> +
>> +    BOOL inherit;
>> +    DWORD access;
>> +
>> +    HANDLE handle;
>> +};
>> +
> 
> Wrapping VkDeviceMemory is problematic, because generated thunks won't 
> unwrap handles in struct parameters. With this code functions using 
> these structs will be broken:
> 
> VkBindAccelerationStructureMemoryInfoNV, VkBindBufferMemoryInfo, 
> VkBindImageMemoryInfo, VkDeviceMemoryOpaqueCaptureAddressInfo, 
> VkMappedMemoryRange, VkSparseImageMemoryBind, VkSparseMemoryBind
> 
> So you either have to either:
> 1. Manually implement all those functions.
> 2. Handle it in make_vulkan.
> 3. Find another way to store data per VkDeviceMemory object, e.g with 
> VK_EXT_private_data.
> 
> I'm against the first option because it's a lot of manually written 
> functions and future spec updates might add new problematic functions. 
> The provisional video extensions add VkVideoBindMemoryKHR for example.
> 
> The best option would be the second, if you can make it work, because we 
> currently have some code in vulkan.c that should be generated but has 
> the same problem.
> 
> Thanks,
> 
> Georg Lehmann
> 
>> +static inline struct wine_dev_mem 
>> *wine_dev_mem_from_handle(VkDeviceMemory handle)
>> +{
>> +    return (struct wine_dev_mem *)(uintptr_t)handle;
>> +}
>> +
>> +static inline VkDeviceMemory wine_dev_mem_to_handle(struct 
>> wine_dev_mem *dev_mem)
>> +{
>> +    return (VkDeviceMemory)(uintptr_t)dev_mem;
>> +}
>> +
>>   BOOL wine_vk_device_extension_supported(const char *name) 
>> DECLSPEC_HIDDEN;
>>   BOOL wine_vk_instance_extension_supported(const char *name) 
>> DECLSPEC_HIDDEN;
>>



More information about the wine-devel mailing list