Signed-off-by: Derek Lesho dlesho@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;