On 5/18/21 7:11 AM, Derek Lesho wrote:
On 5/18/21 3:35 AM, Liam Middlebrook wrote:
On 5/17/21 1:01 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v2: Addressed comments from mailing list and discord.
You should be encouraging people giving feedback on Discord to reply to your patches here on wine-devel.
dlls/vulkan-1/tests/vulkan.c | 216 ++++++++++++++++
This patch is very large. Would it make sense to split off the test to a separate commit to make review easier? (although I guess there's no overlap between the test code and the winevulkan code)
The VK_KHR_external_memory_win32 extension has to leave UNSUPPORTED_EXTENSIONS for the tests to compile, as otherwise the necessary definitions aren't present in vulkan.h. Doing this would cause the situation that you indicated you want to avoid, where a extension would be exposed but the functions would all have to be stubs. Alternatively, we could add VK_KHR_external_memory_win32 to WINEVULKAN_INTERNAL_EXTENSIONS in the test commit, to allow the tests to compile and run on windows, then remove in the commit where we actually support it. If we do that, maybe it'd even make more sense to group the tests commit together with the internal extension commit so we don't have dead/unused code, although it might be a bit confusing if we add a new list with the name WINEVULKAN_INTERNAL_EXTENSIONS and have the first extension we add to that be an extension not supported on the host.
I'm more confused by your description than I was before. Given that the tests stuff is in a separate file/"module" I think it's fine to just leave it in the same commit, nevermind on my feedback on it from before.
dlls/winevulkan/make_vulkan | 26 +- dlls/winevulkan/vulkan.c | 406 +++++++++++++++++++++++++++++--
From skimming through this patch I think you could split off the code that handles buffer/image/memory creation/allocation into a separate patch that goes before support for VK_EXT_external_memory_win32. Having more granular commits here would make it easier to review, and also lower the surface area for regressions in each commit, making it easier to fix/revert if/when bugs do sneak in.
Sounds good, although these will be more "unused helper code" commits in that case.
Will they be? It looks to me like they replace the auto-generated thunks? There's a difference between changes you expect to be a no-op and changes which introduce unused code. As far as I can tell the changes for buffer/image/memory creation/allocation would be used, but are expected to be a no-op.
Thanks,
Liam Middlebrook
I haven't reviewed the changes below in-detail yet and have no comments for them at this time, sorry I'll see if I have more time to look at this (or a later revision) later in the week.
Thanks,
Liam Middlebrook
dlls/winevulkan/vulkan_private.h | 24 ++ 4 files changed, 645 insertions(+), 27 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 1d23c4112cf..718937e2222 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -546,6 +546,221 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); } +uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags) +{ + VkPhysicalDeviceMemoryProperties properties = {0}; + unsigned int i;
+ vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties);
+ for(i = 0; i < properties.memoryTypeCount; i++) + { + if (properties.memoryTypes[i].propertyFlags & flags) + return i; + } + return -1; +}
+static const char *test_external_memory_extensions[] = +{ + "VK_KHR_external_memory_capabilities", +};
+static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR; + PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR; + VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info; + VkExternalBufferPropertiesKHR external_buffer_properties; + VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info; + VkExportMemoryWin32HandleInfoKHR export_handle_info; + VkImportMemoryWin32HandleInfoKHR import_handle_info; + VkExportMemoryAllocateInfoKHR export_memory_info; + VkMemoryGetWin32HandleInfoKHR get_handle_info; + VkBufferCreateInfo buffer_create_info; + VkMemoryAllocateInfo alloc_info; + uint32_t queue_family_index; + HANDLE nt_handle, kmt_handle; + VkDeviceMemory vk_memory, vk_memory_import; + VkBuffer vk_buffer; + VkDevice vk_device; + VkResult vr;
+ static const char *extensions[] = + { + "VK_KHR_dedicated_allocation", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + };
+ pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR = + (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
+ if ((vr = create_device(vk_physical_device, ARRAY_SIZE(extensions), extensions, NULL, &vk_device))) + { + skip("Failed to create device with external memory extensions, VkResult %d.\n", vr); + return; + }
+ pfn_vkGetMemoryWin32HandleKHR = (void *) vkGetDeviceProcAddr(vk_device, "vkGetMemoryWin32HandleKHR");
+ find_queue_family(vk_physical_device, VK_QUEUE_GRAPHICS_BIT, &queue_family_index);
+ /* Most implementations only support exporting dedicated allocations */
+ buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = NULL; + buffer_create_info.flags = 0; + buffer_create_info.size = 1; + buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + buffer_create_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_create_info.queueFamilyIndexCount = 1; + buffer_create_info.pQueueFamilyIndices = &queue_family_index; + if ((vr = vkCreateBuffer(vk_device, &buffer_create_info, NULL, &vk_buffer))) + { + skip("Failed to create generic buffer, VkResult %d.\n", vr); + vkDestroyDevice(vk_device, NULL); + return; + }
+ dedicated_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + dedicated_alloc_info.pNext = NULL; + dedicated_alloc_info.image = VK_NULL_HANDLE; + dedicated_alloc_info.buffer = vk_buffer;
+ external_buffer_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR; + external_buffer_info.pNext = NULL; + external_buffer_info.flags = 0; + external_buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
+ if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
+ skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n"); + else + {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
+ export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ export_handle_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + export_handle_info.pNext = &export_memory_info; + export_handle_info.name = L"wine_test_buffer_export_name"; + export_handle_info.dwAccess = GENERIC_ALL; + export_handle_info.pAttributes = NULL;
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_handle_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
+ get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
+ vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &nt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
+ import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + import_handle_info.handle = nt_handle; + import_handle_info.name = NULL;
+ alloc_info.pNext = &import_handle_info;
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
+ vkFreeMemory(vk_device, vk_memory_import, NULL);
+ import_handle_info.handle = NULL; + import_handle_info.name = L"wine_test_buffer_export_name";
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + todo_wine + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + if (vr == VK_SUCCESS) + { + ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + vkFreeMemory(vk_device, vk_memory_import, NULL); + } + vkFreeMemory(vk_device, vk_memory, NULL); + CloseHandle(nt_handle); + }
+ external_buffer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ memset(&external_buffer_properties, 0, sizeof(external_buffer_properties)); + external_buffer_properties.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR;
pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR(vk_physical_device, &external_buffer_info, &external_buffer_properties);
+ if (!(external_buffer_properties.externalMemoryProperties.externalMemoryFeatures &
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)))
+ skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n"); + else + {
ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes);
+ export_memory_info.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + export_memory_info.pNext = &dedicated_alloc_info; + export_memory_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &export_memory_info; + alloc_info.allocationSize = 1; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ ok(alloc_info.memoryTypeIndex != -1, "Device local memory type index was not found.\n");
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
+ get_handle_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + get_handle_info.pNext = NULL; + get_handle_info.memory = vk_memory; + get_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
+ vr = pfn_vkGetMemoryWin32HandleKHR(vk_device, &get_handle_info, &kmt_handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr);
+ import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + import_handle_info.handle = kmt_handle; + import_handle_info.name = NULL;
+ alloc_info.pNext = &import_handle_info;
+ vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory_import); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + ok(vk_memory_import != vk_memory, "Expected new memory object.\n");
+ vkFreeMemory(vk_device, vk_memory_import, NULL); + vkFreeMemory(vk_device, vk_memory, NULL); + }
+ vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); +}
static void for_each_device_instance(uint32_t extension_count, const char * const *enabled_extensions, void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) { @@ -602,4 +817,5 @@ START_TEST(vulkan) for_each_device(test_unsupported_device_extensions); for_each_device(test_private_data); for_each_device_instance(ARRAY_SIZE(test_null_hwnd_extensions), test_null_hwnd_extensions, test_null_hwnd, NULL);
for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); } diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7e1d7c0f043..b36275ba75f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_pipeline_creation_feedback", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_external_memory_win32", "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. @@ -109,7 +108,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_external_memory_dma_buf", "VK_EXT_image_drm_format_modifier", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd", # Extensions which require callback handling @@ -121,7 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ ] # Extensions which aren't present on the win32 platform, but which winevulkan may use. -UNEXPOSED_EXTENSIONS = [] +UNEXPOSED_EXTENSIONS = [ + "VK_KHR_external_memory_fd", +] # The Vulkan loader provides entry-points for core functionality and important # extensions. Based on vulkan-1.def this amounts to WSI extensions on 1.0.51. @@ -179,7 +179,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -188,10 +188,14 @@ FUNCTION_OVERRIDES = { # Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -221,7 +225,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, # VK_KHR_external_memory_capabilities - "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_external_semaphore_capabilities @@ -257,12 +261,22 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_marker "vkDebugMarkerSetObjectNameEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkDebugMarkerSetObjectTagEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.PRIVATE},
+ # VK_KHR_external_memory_win32 + "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, } STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"],
+ # Structs which require pNext chain modification + "VkBufferCreateInfo": [], + "VkImageCreateInfo": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], + "VkPhysicalDeviceImageFormatInfo2": [], } @@ -1052,6 +1066,8 @@ class VkHandle(object): return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name)
if self.name == "VkSurfaceKHR": return "wine_surface_from_handle({0})->surface".format(name) + if self.name == "VkDeviceMemory": + return "wine_dev_mem_from_handle({0})->dev_mem".format(name) native_handle_name = None diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9f181d92bc5..c2069b77ef2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include <time.h> #include <stdarg.h> #include <stdlib.h> +#include <unistd.h> #include "ntstatus.h" #define WIN32_NO_STATUS @@ -34,6 +35,8 @@ #include "winuser.h" #include "winternl.h" +#include "wine/server.h"
#include "vulkan_private.h" WINE_DEFAULT_DEBUG_CHANNEL(vulkan); @@ -263,6 +266,15 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc */ for (i = 0; i < num_host_properties; i++) { + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd")) + { + TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n");
+ snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName),
- VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
+ host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + }
if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); @@ -361,11 +373,15 @@ static void wine_vk_device_get_queues(struct VkDevice_T *device, static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) { free_VkDeviceCreateInfo_struct_chain(create_info);
+ if (create_info->enabledExtensionCount) + free((void *)create_info->ppEnabledExtensionNames); } static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { + const char **enabled_extensions; unsigned int i; VkResult res; @@ -389,11 +405,34 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src if (!wine_vk_device_extension_supported(extension_name)) { WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - wine_vk_device_free_create_info(dst); + free_VkDeviceCreateInfo_struct_chain(dst); return VK_ERROR_EXTENSION_NOT_PRESENT; } } + if (src->enabledExtensionCount > 0) + { + enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) + { + free_VkDeviceCreateInfo_struct_chain(dst); + return VK_ERROR_OUT_OF_HOST_MEMORY; + }
+ for (i = 0; i < src->enabledExtensionCount; i++) + { + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + { + enabled_extensions[i] = "VK_KHR_external_memory_fd"; + } + else + { + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + } + dst->ppEnabledExtensionNames = enabled_extensions; + }
return VK_SUCCESS; } @@ -1190,57 +1229,100 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
+ if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ thunk_vkGetPhysicalDeviceExternalBufferProperties(phys_dev, &buffer_info_dup, properties);
+ if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.exportFromImportedHandleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info;
TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
+ if (buffer_info_dup.handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
- thunk_vkGetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev,
&buffer_info_dup, properties);
+ if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.exportFromImportedHandleTypes
= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
- properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, +static VkResult wine_vk_get_physical_device_image_format_properties_2(VkPhysicalDevice phys_dev,
+ VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { + VkPhysicalDeviceExternalImageFormatInfo *external_image_info_dup = NULL; + const VkPhysicalDeviceExternalImageFormatInfo *external_image_info; + VkPhysicalDeviceImageFormatInfo2 format_info_host = *format_info; VkExternalImageFormatProperties *external_image_properties; VkResult res; - TRACE("%p, %p, %p\n", phys_dev, format_info, properties); + if ((external_image_info = wine_vk_find_struct(format_info, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO))) + { + if (external_image_info->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + if ((res = convert_VkPhysicalDeviceImageFormatInfo2_struct_chain(format_info->pNext, &format_info_host)) < 0) + { + WARN("Failed to convert VkPhysicalDeviceImageFormatInfo2 pNext chain, res=%d.\n", res); + return res; + } - res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties); + external_image_info_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO); + external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + } + if (external_image_info->handleType &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + WARN("Unsupported handle type %#x.\n", external_image_info->handleType); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + }
+ res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, &format_info_host, properties);
+ if (external_image_info_dup)
- free_VkPhysicalDeviceImageFormatInfo2_struct_chain(&format_info_host);
if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; + if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; } return res; } -VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { - VkExternalImageFormatProperties *external_image_properties; - VkResult res;
TRACE("%p, %p, %p\n", phys_dev, format_info, properties); - res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties); + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2, format_info, properties); +} - if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES))) - { - VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; - } +VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev, + const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) +{ + TRACE("%p, %p, %p\n", phys_dev, format_info, properties); - return res; + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, thunk_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); } /* From ntdll/unix/sync.c */ @@ -1720,3 +1802,283 @@ VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebu return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info); }
+static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{ + HANDLE ret = INVALID_HANDLE_VALUE;
+ if (name) + FIXME("Naming gpu resources not supported.\n");
+ wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret);
+ return ret; +}
+VkResult WINAPI wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *allocate_info, + const VkAllocationCallbacks *allocator, VkDeviceMemory *memory) +{ + const VkImportMemoryWin32HandleInfoKHR *handle_import_info; + const VkExportMemoryWin32HandleInfoKHR *handle_export_info; + VkMemoryAllocateInfo allocate_info_dup = *allocate_info; + VkExportMemoryAllocateInfo *export_info; + VkImportMemoryFdInfoKHR fd_import_info; + struct wine_dev_mem *object; + VkResult res; + int fd;
+#if defined(USE_STRUCT_CONVERSION) + VkMemoryAllocateInfo_host allocate_info_host; + VkMemoryGetFdInfoKHR_host get_fd_info; +#else + VkMemoryAllocateInfo allocate_info_host; + VkMemoryGetFdInfoKHR get_fd_info; +#endif
+ TRACE("%p %p %p %p\n", device, allocate_info, allocator, memory);
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkMemoryAllocateInfo_struct_chain(allocate_info->pNext, &allocate_info_dup)) < 0) + { + WARN("Failed to convert VkMemoryAllocateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if (!(object = calloc(1, sizeof(*object)))) + {
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
+ return VK_ERROR_OUT_OF_HOST_MEMORY; + }
+ object->dev_mem = VK_NULL_HANDLE; + object->handle = INVALID_HANDLE_VALUE; + fd_import_info.fd = -1; + fd_import_info.pNext = NULL;
+ /* find and process handle import/export info and grab it */ + handle_import_info = wine_vk_find_struct(allocate_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + handle_export_info = wine_vk_find_struct(allocate_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor) + FIXME("Support for custom security descriptor not implemented.\n");
+ if ((export_info = wine_vk_find_struct(&allocate_info_dup, EXPORT_MEMORY_ALLOCATE_INFO))) + { + object->handle_types = export_info->handleTypes; + if (object->handle_types &~ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + if (object->handle_types) + export_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + }
+ /* Vulkan consumes imported FDs, but not imported HANDLEs */ + if (handle_import_info) + { + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + fd_import_info.pNext = allocate_info_dup.pNext; + fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ switch (handle_import_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (handle_import_info->handle) + NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &object->handle, 0, 0, DUPLICATE_SAME_ACCESS ); + else if (handle_import_info->name) + FIXME("Importing device memory by resource name not supported.\n"); + break; + default: + WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + }
+ if (object->handle != INVALID_HANDLE_VALUE) + wine_server_handle_to_fd(object->handle, FILE_READ_DATA, &fd_import_info.fd, NULL);
+ if (fd_import_info.fd == -1) + { + TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle, + handle_import_info->name ? debugstr_w(handle_import_info->name) : ""); + res = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + }
+ allocate_info_host.sType = allocate_info_dup.sType; + allocate_info_host.pNext = fd_import_info.fd == -1 ? allocate_info_dup.pNext : &fd_import_info; + allocate_info_host.allocationSize = allocate_info_dup.allocationSize; + allocate_info_host.memoryTypeIndex = allocate_info_dup.memoryTypeIndex;
+ if ((res = device->funcs.p_vkAllocateMemory(device->device, &allocate_info_host, NULL, &object->dev_mem)) == VK_SUCCESS) + { + if (object->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes) + { + get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + get_fd_info.pNext = NULL; + get_fd_info.memory = object->dev_mem; + get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS) + { + object->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL); + object->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL; + if (handle_export_info && handle_export_info->pAttributes) + object->inherit = handle_export_info->pAttributes->bInheritHandle; + else + object->inherit = FALSE; + close(fd); + }
+ if (object->handle == INVALID_HANDLE_VALUE) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + }
- WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance,
object, object->dev_mem); + *memory = wine_dev_mem_to_handle(object); + }
+ done:
+ if (res != VK_SUCCESS) + { + device->funcs.p_vkFreeMemory(device->device, object->dev_mem, NULL); + if (fd_import_info.fd != -1) + close(fd_import_info.fd); + if (object->handle != INVALID_HANDLE_VALUE) + NtClose(object->handle); + free(object); + }
- free_VkMemoryAllocateInfo_struct_chain(&allocate_info_dup);
+ return res; +}
+VkResult WINAPI wine_vkGetMemoryWin32HandleKHR(VkDevice device, + const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle_info->memory); + const VkBaseInStructure *chain;
+ TRACE("%p, %p %p\n", device, handle_info, handle);
+ if (!(dev_mem->handle_types & handle_info->handleType)) + return VK_ERROR_OUT_OF_HOST_MEMORY;
+ if ((chain = handle_info->pNext)) + FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
+ switch(handle_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? + VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + default: + return VK_ERROR_UNKNOWN; + } +}
+void WINAPI wine_vkFreeMemory(VkDevice device, VkDeviceMemory handle, const VkAllocationCallbacks *allocator) +{ + struct wine_dev_mem *dev_mem = wine_dev_mem_from_handle(handle);
+ TRACE("%p 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if (!handle) + return;
- WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, dev_mem);
+ device->funcs.p_vkFreeMemory(device->device, dev_mem->dev_mem, NULL); + if (dev_mem->handle != INVALID_HANDLE_VALUE) + NtClose(dev_mem->handle); + free(dev_mem); +}
+VkResult WINAPI wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, + VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +{ + TRACE("%p %u %p %p\n", device, type, handle, properties);
+ /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666 + handleType must not be one of the handle types defined as opaque */ + return VK_ERROR_INVALID_EXTERNAL_HANDLE; +}
+VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + VkExternalMemoryBufferCreateInfo *external_memory_info; + VkBufferCreateInfo create_info_dup; + VkResult res;
+#if defined(USE_STRUCT_CONVERSION) + VkBufferCreateInfo_host create_info_host; +#else + VkBufferCreateInfo create_info_host; +#endif
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, &create_info_dup))) + { + WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if ((external_memory_info = wine_vk_find_struct(&create_info_dup, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ create_info_host.pNext = create_info_dup.pNext; + create_info_host.sType = create_info->sType; + create_info_host.flags = create_info->flags; + create_info_host.size = create_info->size; + create_info_host.usage = create_info->usage; + create_info_host.sharingMode = create_info->sharingMode; + create_info_host.queueFamilyIndexCount = create_info->queueFamilyIndexCount; + create_info_host.pQueueFamilyIndices = create_info->pQueueFamilyIndices;
+ res = device->funcs.p_vkCreateBuffer(device->device, &create_info_host, NULL, buffer);
+ free_VkBufferCreateInfo_struct_chain(&create_info_dup);
+ return res; +}
+VkResult WINAPI wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkBuffer *image) +{ + VkExternalMemoryImageCreateInfo *external_memory_info; + VkImageCreateInfo create_info_host; + VkResult res;
+ if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n");
+ if ((res = convert_VkImageCreateInfo_struct_chain(create_info->pNext, &create_info_host))) + { + WARN("Failed to convert VkImageCreateInfo pNext chain, res=%d.\n", res); + return res; + }
+ if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) && + external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + external_memory_info->handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image);
+ free_VkImageCreateInfo_struct_chain(&create_info_host);
+ return res; +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 83dc90ca15e..4a20702d43b 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -204,6 +204,30 @@ static inline VkSurfaceKHR wine_surface_to_handle(struct wine_surface *surface) return (VkSurfaceKHR)(uintptr_t)surface; } +struct wine_dev_mem +{ + VkDeviceMemory dev_mem;
+ VkExternalMemoryHandleTypeFlagBits handle_types;
+ BOOL inherit; + DWORD access;
+ HANDLE handle;
+ struct wine_vk_mapping mapping; +};
+static inline struct wine_dev_mem *wine_dev_mem_from_handle(VkDeviceMemory handle) +{ + return (struct wine_dev_mem *)(uintptr_t)handle; +}
+static inline VkDeviceMemory wine_dev_mem_to_handle(struct wine_dev_mem *dev_mem) +{ + return (VkDeviceMemory)(uintptr_t)dev_mem; +}
BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN; BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;