Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winevulkan/make_vulkan | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index e8534cbd5f5..c46ef02dcb9 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -124,6 +124,11 @@ UNSUPPORTED_EXTENSIONS = [ "VK_NV_external_memory_win32", ]
+# Either internal extensions which aren't present on the win32 platform which +# winevulkan may nonetheless use, or extensions we want to generate headers for +# but not expose to applications (useful for test commits) +UNEXPOSED_EXTENSIONS = {} + # 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. CORE_EXTENSIONS = [ @@ -513,8 +518,8 @@ class VkEnumValue(object):
class VkFunction(object): - def __init__(self, _type=None, name=None, params=[], extensions=[], alias=None): - self.extensions = [] + def __init__(self, _type=None, name=None, params=[], alias=None): + self.extensions = set() self.name = name self.type = _type self.params = params @@ -657,6 +662,10 @@ class VkFunction(object): def needs_private_thunk(self): return self.thunk_type == ThunkType.PRIVATE
+ def needs_exposing(self): + # The function needs exposed if at-least one extension isn't both UNSUPPORTED and UNEXPOSED + return self.is_required() and (not self.extensions or not self.extensions.issubset(UNEXPOSED_EXTENSIONS)) + def pfn(self, prefix="p", call_conv=None, conv=False): """ Create function pointer. """
@@ -2682,7 +2691,7 @@ class VkGenerator(object): # Create thunks for instance and device functions. # Global functions don't go through the thunks. for vk_func in self.registry.funcs.values(): - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue
if vk_func.is_global_func(): @@ -2702,6 +2711,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "device": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue
f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2711,6 +2722,8 @@ class VkGenerator(object): for ext in self.registry.extensions: if ext["type"] != "instance": continue + if ext["name"] in UNEXPOSED_EXTENSIONS: + continue
f.write(" "{0}",\n".format(ext["name"])) f.write("};\n\n") @@ -2770,7 +2783,7 @@ class VkGenerator(object): f.write("const struct unix_funcs loader_funcs =\n") f.write("{\n") for vk_func in self.registry.funcs.values(): - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue if vk_func.loader_thunk_type == ThunkType.NONE: continue @@ -2789,7 +2802,7 @@ class VkGenerator(object): # Generate prototypes for device and instance functions requiring a custom implementation. f.write("/* Functions for which we have custom implementations outside of the thunks. */\n") for vk_func in self.registry.funcs.values(): - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue if vk_func.needs_thunk() and not vk_func.needs_private_thunk(): continue @@ -2888,7 +2901,7 @@ class VkGenerator(object): f.write("WINE_DEFAULT_DEBUG_CHANNEL(vulkan);\n\n")
for vk_func in self.registry.funcs.values(): - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue if vk_func.loader_thunk_type != ThunkType.PUBLIC: continue @@ -2897,7 +2910,7 @@ class VkGenerator(object):
f.write("static const struct vulkan_func vk_device_dispatch_table[] =\n{\n") for vk_func in self.registry.device_funcs: - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue
f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) @@ -2905,7 +2918,7 @@ class VkGenerator(object):
f.write("static const struct vulkan_func vk_phys_dev_dispatch_table[] =\n{\n") for vk_func in self.registry.phys_dev_funcs: - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue
f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) @@ -2913,7 +2926,7 @@ class VkGenerator(object):
f.write("static const struct vulkan_func vk_instance_dispatch_table[] =\n{\n") for vk_func in self.registry.instance_funcs: - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue
f.write(" {{"{0}", &{0}}},\n".format(vk_func.name)) @@ -2970,7 +2983,7 @@ class VkGenerator(object): f.write("struct unix_funcs\n") f.write("{\n") for vk_func in self.registry.funcs.values(): - if not vk_func.is_required(): + if not vk_func.needs_exposing(): continue if vk_func.loader_thunk_type == ThunkType.NONE: continue @@ -3464,7 +3477,7 @@ class VkRegistry(object): # the XML file to handle this, but because of the manner in which we parse the XML # file we pre-populate from <commands> before we check if a command is enabled. if cmd_name in self.funcs: - self.funcs[cmd_name].extensions.append(ext_name) + self.funcs[cmd_name].extensions.add(ext_name)
# Some extensions are not ready or have numbers reserved as a place holder. if ext.attrib["supported"] == "disabled":
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v13: - Factor memory import into helper function. - Enable VK_KHR_get_memory_requirements2, dependency of VK_KHR_dedicated_allocation. --- dlls/vulkan-1/tests/vulkan.c | 341 +++++++++++++++++++++++++++++++++++ dlls/winevulkan/make_vulkan | 5 +- 2 files changed, 344 insertions(+), 2 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index f222c631232..75e48bfc9d1 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -548,6 +548,334 @@ static void test_null_hwnd(VkInstance vk_instance, VkPhysicalDevice vk_physical_ vkDestroySurfaceKHR(vk_instance, surface, NULL); }
+static uint32_t find_memory_type(VkPhysicalDevice vk_physical_device, VkMemoryPropertyFlagBits flags, uint32_t mask) +{ + VkPhysicalDeviceMemoryProperties properties = {0}; + unsigned int i; + + vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &properties); + + for(i = 0; i < properties.memoryTypeCount; i++) + { + if ((1u << i) & mask && properties.memoryTypes[i].propertyFlags & flags) + return i; + } + return -1; +} + +static void test_cross_process_resource(VkPhysicalDeviceIDPropertiesKHR *device_id_properties, BOOL kmt, HANDLE handle) +{ + char driver_uuid[VK_UUID_SIZE * 2 + 1], device_uuid[VK_UUID_SIZE * 2 + 1]; + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char **argv, buf[MAX_PATH]; + unsigned int i; + BOOL res; + + for (i = 0; i < VK_UUID_SIZE; i++) + { + sprintf(&driver_uuid[i * 2], "%02X", device_id_properties->driverUUID[i]); + sprintf(&device_uuid[i * 2], "%02X", device_id_properties->deviceUUID[i]); + } + driver_uuid[i * 2] = 0; + device_uuid[i * 2] = 0; + + winetest_get_mainargs(&argv); + sprintf(buf, ""%s" vulkan resource %s %s %s %p", argv[0], driver_uuid, device_uuid, + kmt ? "kmt" : "nt", handle); + res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0L, NULL, NULL, &si, &info); + ok(res, "CreateProcess failed: %u\n", GetLastError()); + CloseHandle(info.hThread); + + wait_child_process(info.hProcess); +} + +static void import_memory(VkDevice vk_device, VkMemoryAllocateInfo alloc_info, VkExternalMemoryHandleTypeFlagBits handle_type, HANDLE handle) +{ + VkImportMemoryWin32HandleInfoKHR import_handle_info; + VkDeviceMemory memory; + VkResult vr; + + import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = alloc_info.pNext; + import_handle_info.handleType = handle_type; + import_handle_info.handle = handle; + import_handle_info.name = NULL; + + alloc_info.pNext = &import_handle_info; + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d. type=%#x\n", vr, handle_type); + vkFreeMemory(vk_device, memory, NULL); + + /* KMT-exportable objects can't be named */ + if (handle_type != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR) + { + import_handle_info.handle = NULL; + import_handle_info.name = L"wine_test_buffer_export_name"; + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + vkFreeMemory(vk_device, memory, NULL); + } +} + +static const char *test_external_memory_extensions[] = +{ + "VK_KHR_external_memory_capabilities", + "VK_KHR_get_physical_device_properties2", +}; + +static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_physical_device) +{ + PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR; + PFN_vkGetPhysicalDeviceProperties2 pfn_vkGetPhysicalDeviceProperties2; + VkExternalMemoryBufferCreateInfoKHR buffer_external_memory_info; + PFN_vkGetMemoryWin32HandleKHR pfn_vkGetMemoryWin32HandleKHR; + VkPhysicalDeviceExternalBufferInfoKHR external_buffer_info; + VkExternalBufferPropertiesKHR external_buffer_properties; + VkMemoryDedicatedAllocateInfoKHR dedicated_alloc_info; + VkPhysicalDeviceIDPropertiesKHR device_id_properties; + VkExportMemoryWin32HandleInfoKHR export_handle_info; + VkPhysicalDeviceProperties2KHR device_properties; + VkExportMemoryAllocateInfoKHR export_memory_info; + VkMemoryGetWin32HandleInfoKHR get_handle_info; + VkExternalMemoryHandleTypeFlagBits handle_type; + VkMemoryRequirements memory_requirements; + VkBufferCreateInfo buffer_create_info; + VkMemoryAllocateInfo alloc_info; + VkDeviceMemory vk_memory; + SECURITY_ATTRIBUTES sa; + unsigned int val, i; + VkBuffer vk_buffer; + VkDevice vk_device; + HANDLE handle; + VkResult vr; + char **argv; + int argc; + + static const char *extensions[] = + { + "VK_KHR_get_memory_requirements2", + "VK_KHR_dedicated_allocation", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + }; + + pfn_vkGetPhysicalDeviceExternalBufferPropertiesKHR = + (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR"); + + pfn_vkGetPhysicalDeviceProperties2 = + (void*) vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2KHR"); + + if (pfn_vkGetPhysicalDeviceProperties2) + { + device_id_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR; + device_id_properties.pNext = NULL; + + device_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + device_properties.pNext = &device_id_properties; + + pfn_vkGetPhysicalDeviceProperties2(vk_physical_device, &device_properties); + } + + argc = winetest_get_mainargs(&argv); + if (argc > 3 && !strcmp(argv[2], "resource")) + { + for (i = 0; i < VK_UUID_SIZE; i++) + { + sscanf(&argv[3][i * 2], "%02X", &val); + if (val != device_id_properties.driverUUID[i]) + break; + + sscanf(&argv[4][i * 2], "%02X", &val); + if (val != device_id_properties.deviceUUID[i]) + break; + } + + if (i != VK_UUID_SIZE) + return; + } + + 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"); + + buffer_external_memory_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR; + buffer_external_memory_info.pNext = NULL; + buffer_external_memory_info.handleTypes = 0; + + 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))) + { + ok(external_buffer_properties.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, + "Unexpected compatibleHandleTypes %#x.\n", external_buffer_properties.externalMemoryProperties.compatibleHandleTypes); + + buffer_external_memory_info.handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + } + + 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))) + { + 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); + + buffer_external_memory_info.handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + } + + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = &buffer_external_memory_info; + 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_EXCLUSIVE; + buffer_create_info.queueFamilyIndexCount = 0; + buffer_create_info.pQueueFamilyIndices = NULL; + 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; + } + + vkGetBufferMemoryRequirements(vk_device, vk_buffer, &memory_requirements); + + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = memory_requirements.size; + alloc_info.memoryTypeIndex = find_memory_type(vk_physical_device, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memory_requirements.memoryTypeBits); + + /* Most implementations only support exporting dedicated allocations */ + + 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; + + if (argc > 3 && !strcmp(argv[2], "resource")) + { + handle_type = strcmp(argv[5], "kmt") ? + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR : + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + + sscanf(argv[6], "%p", &handle); + + ok(handle_type & buffer_external_memory_info.handleTypes, + "External memory capabilities for handleType %#x do not match on child process.\n", handle_type); + + alloc_info.pNext = &dedicated_alloc_info; + import_memory(vk_device, alloc_info, handle_type, handle); + + vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); + + return; + } + + if (!(buffer_external_memory_info.handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR)) + skip("With desired parameters, buffers are not exportable to and importable from an NT handle.\n"); + else + { + 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; + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + 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 = &sa; + + alloc_info.pNext = &export_handle_info; + + 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, &handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr); + + alloc_info.pNext = &dedicated_alloc_info; + import_memory(vk_device, alloc_info, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR, handle); + + if (pfn_vkGetPhysicalDeviceProperties2) + test_cross_process_resource(&device_id_properties, FALSE, handle); + else + skip("Skipping cross process shared resource test due to lack of VK_KHR_get_physical_device_properties2.\n"); + + vkFreeMemory(vk_device, vk_memory, NULL); + CloseHandle(handle); + } + + if (!(buffer_external_memory_info.handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR)) + skip("With desired parameters, buffers are not exportable to and importable from a KMT handle.\n"); + else + { + 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.pNext = &export_memory_info; + + 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, &handle); + ok(vr == VK_SUCCESS, "vkGetMemoryWin32HandleKHR failed, VkResult %d.\n", vr); + + alloc_info.pNext = &dedicated_alloc_info; + import_memory(vk_device, alloc_info, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR, handle); + + if (pfn_vkGetPhysicalDeviceProperties2) + test_cross_process_resource(&device_id_properties, TRUE, handle); + else + skip("Skipping cross process shared resource test due to lack of VK_KHR_get_physical_device_properties2.\n"); + + 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)) { @@ -594,6 +922,18 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice))
START_TEST(vulkan) { + char **argv; + int argc; + + argc = winetest_get_mainargs(&argv); + + if (argc > 3 && !strcmp(argv[2], "resource")) + { + ok(argc >= 7, "Missing launch arguments\n"); + for_each_device_instance(ARRAY_SIZE(test_external_memory_extensions), test_external_memory_extensions, test_external_memory, NULL); + return; + } + test_instance_version(); for_each_device(enumerate_physical_device); test_enumerate_physical_device2(); @@ -604,4 +944,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 c46ef02dcb9..5c4c4f0fe26 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. @@ -127,7 +126,9 @@ UNSUPPORTED_EXTENSIONS = [ # Either internal extensions which aren't present on the win32 platform which # winevulkan may nonetheless use, or extensions we want to generate headers for # but not expose to applications (useful for test commits) -UNEXPOSED_EXTENSIONS = {} +UNEXPOSED_EXTENSIONS = { + "VK_KHR_external_memory_win32", +}
# 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.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/vulkan-1/tests/vulkan.c | 5 +- dlls/winevulkan/make_vulkan | 20 +- dlls/winevulkan/vulkan.c | 351 ++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan_private.h | 24 +++ 4 files changed, 391 insertions(+), 9 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 75e48bfc9d1..2e2bc58c761 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -615,8 +615,9 @@ static void import_memory(VkDevice vk_device, VkMemoryAllocateInfo alloc_info, V import_handle_info.name = L"wine_test_buffer_export_name";
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &memory); - ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); - vkFreeMemory(vk_device, memory, NULL); + todo_wine ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + if (vr == VK_SUCCESS) + vkFreeMemory(vk_device, memory, NULL); } }
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 5c4c4f0fe26..f796a453eaf 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -109,7 +109,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_image_drm_format_modifier", "VK_EXT_physical_device_drm", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd",
# Extensions which require callback handling @@ -127,7 +126,7 @@ UNSUPPORTED_EXTENSIONS = [ # winevulkan may nonetheless use, or extensions we want to generate headers for # but not expose to applications (useful for test commits) UNEXPOSED_EXTENSIONS = { - "VK_KHR_external_memory_win32", + "VK_KHR_external_memory_fd", }
# The Vulkan loader provides entry-points for core functionality and important @@ -186,7 +185,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.NONE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -195,10 +194,13 @@ 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}, "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}, @@ -228,7 +230,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.NONE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE},
# VK_KHR_external_semaphore_capabilities @@ -252,12 +254,20 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_report "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + + # 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": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], }
@@ -1048,6 +1058,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 fb0ffbdfe6c..93cdeec2693 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); @@ -256,6 +259,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); @@ -354,11 +366,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;
@@ -382,11 +398,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; }
@@ -1177,18 +1216,71 @@ void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice properties->externalFenceFeatures = 0; }
+static inline void wine_vk_normalize_handle_types_win(VkExternalMemoryHandleTypeFlags *types) +{ + *types &= + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT; +} + +static inline void wine_vk_normalize_handle_types_host(VkExternalMemoryHandleTypeFlags *types) +{ + *types &= + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | +/* predicated on VK_KHR_external_memory_dma_buf + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT | */ + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT; +} + +static void wine_vk_get_physical_device_external_buffer_properties(VkPhysicalDevice phys_dev, + void (*p_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalBufferInfo *, VkExternalBufferProperties *), + const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) +{ + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info; + + wine_vk_normalize_handle_types_win(&buffer_info_dup.handleType); + 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; + wine_vk_normalize_handle_types_host(&buffer_info_dup.handleType); + + if (buffer_info->handleType && !buffer_info_dup.handleType) + { + memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + return; + } + + p_vkGetPhysicalDeviceExternalBufferProperties(phys_dev->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; + wine_vk_normalize_handle_types_win(&properties->externalMemoryProperties.exportFromImportedHandleTypes); + + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.compatibleHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_handle_types_win(&properties->externalMemoryProperties.compatibleHandleTypes); +} + void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + + wine_vk_get_physical_device_external_buffer_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalBufferProperties, buffer_info, properties); }
void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties); - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + + wine_vk_get_physical_device_external_buffer_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalBufferPropertiesKHR, buffer_info, properties); }
VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev, @@ -1605,3 +1697,256 @@ void WINAPI wine_vkDestroyDebugReportCallbackEXT(
free(object); } + +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 (export_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + export_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_handle_types_host(&export_info->handleTypes); + } + + /* 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 & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + { + 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_UNKNOWN; + + 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: + FIXME("Unable to get handle of type %x, did the application ignore the capabilities?\n", handle_info->handleType); + 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; + VkResult res; + +#if defined(USE_STRUCT_CONVERSION) + VkBufferCreateInfo_host create_info_host; +#else + VkBufferCreateInfo create_info_host; +#endif + + TRACE("%p %p %p %p\n", device, create_info, allocator, buffer); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if ((res = convert_VkBufferCreateInfo_struct_chain(create_info->pNext, (VkBufferCreateInfo *) &create_info_host))) + { + WARN("Failed to convert VkBufferCreateInfo pNext chain, res=%d.\n", res); + return res; + } + + if ((external_memory_info = wine_vk_find_struct(&create_info_host, EXTERNAL_MEMORY_BUFFER_CREATE_INFO))) + { + if (external_memory_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + external_memory_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_handle_types_host(&external_memory_info->handleTypes); + } + + 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((VkBufferCreateInfo *) &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;
I'm still not convinced that this is the right way to implement this.
On 7/22/21 1:33 AM, Zebediah Figura (she/her) wrote:
I'm still not convinced that this is the right way to implement this.
What, in specific, is wrong with the way this patch is implemented. In previous mail I mentioned how this patch mostly just sets up the winevulkan infrastructure for converting the pNext chain entries for importing and exporting resources, and accepting it doesn't imply a value-judgement on any potential path forwards in regards to storing metadata or interop with other APIs. Is the problem you have that we use EXTERNAL_MEMORY_fd at all? If I'm not mistaken, we'd be using it in any path we decide to go down. (the wineserver object, whatever it may be, will hold an fd pointing to the underlying resource).
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winevulkan/make_vulkan | 3 ++ dlls/winevulkan/vulkan.c | 96 +++++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 19 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index f796a453eaf..9178d619cd4 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -197,6 +197,7 @@ FUNCTION_OVERRIDES = { "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}, @@ -267,7 +268,9 @@ STRUCT_CHAIN_CONVERSIONS = {
# 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": [], }
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 93cdeec2693..26b4362b456 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1283,46 +1283,72 @@ void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice wine_vk_get_physical_device_external_buffer_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalBufferPropertiesKHR, buffer_info, properties); }
-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)) && external_image_info->handleType) + { + 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_dup = wine_vk_find_struct(&format_info_host, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO); + + wine_vk_normalize_handle_types_win(&external_image_info_dup->handleType); + + if (external_image_info_dup->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + external_image_info_dup->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + wine_vk_normalize_handle_types_host(&external_image_info_dup->handleType); + if (!external_image_info_dup->handleType) + { + 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_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; + wine_vk_normalize_handle_types_win(&p->exportFromImportedHandleTypes); + + if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->compatibleHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_handle_types_win(&p->compatibleHandleTypes); }
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 */ @@ -1950,3 +1976,35 @@ VkResult WINAPI wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *c
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 = *create_info; + VkResult res; + + TRACE("%p %p %p %p\n", device, create_info, allocator, image); + + 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_IMAGE_CREATE_INFO))) + { + if (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; + wine_vk_normalize_handle_types_host(&external_memory_info->handleTypes); + } + + res = device->funcs.p_vkCreateImage(device->device, &create_info_host, NULL, image); + + free_VkImageCreateInfo_struct_chain(&create_info_host); + + return res; +}