Signed-off-by: Derek Lesho <dlesho(a)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(-)
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},
}
-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.
- 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;
+ }
+ 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 *),
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;
+ }
+ }
+
+ 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;
+ 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);
+ }
+
+ done:
+
+ if (res != VK_SUCCESS)
+ {
+ if (object->dev_mem != VK_NULL_HANDLE)
+ 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");
+
+ 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)
+ {
+ 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);
+
+ close(fd);
+
+ if (res != VK_SUCCESS)
+ return res;
+
+ properties->sType = VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR;
+ properties->pNext = NULL;
+ 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;
+};
+
+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;
--
2.31.1