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 9ef863837d1..d226057c69e 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -120,6 +120,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 = [ @@ -521,8 +526,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 @@ -665,6 +670,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. """
@@ -2651,7 +2660,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(): @@ -2671,6 +2680,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") @@ -2680,6 +2691,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") @@ -2739,7 +2752,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 @@ -2758,7 +2771,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 @@ -2857,7 +2870,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 @@ -2866,7 +2879,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)) @@ -2874,7 +2887,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)) @@ -2882,7 +2895,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)) @@ -2939,7 +2952,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 @@ -3433,7 +3446,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 --- v9: Add tests for accessing shared resources across device and process boundaries. --- dlls/vulkan-1/tests/vulkan.c | 402 +++++++++++++++++++++++++++++++++++ dlls/winevulkan/make_vulkan | 5 +- 2 files changed, 405 insertions(+), 2 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index f222c631232..0bfee72cd59 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -548,6 +548,379 @@ 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, 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(VkInstance vk_instance, VkPhysicalDevice vk_physical_device, BOOL kmt, HANDLE handle) +{ + char driver_uuid[VK_UUID_SIZE * 2 + 1], device_uuid[VK_UUID_SIZE * 2 + 1]; + PFN_vkGetPhysicalDeviceProperties2 pfn_vkGetPhysicalDeviceProperties2; + VkPhysicalDeviceIDPropertiesKHR device_id_properties; + VkPhysicalDeviceProperties2KHR device_properties; + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION info; + char **argv, buf[MAX_PATH]; + unsigned int i; + BOOL res; + + if (!(pfn_vkGetPhysicalDeviceProperties2 + = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2"))) + pfn_vkGetPhysicalDeviceProperties2 + = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2KHR"); + if (!pfn_vkGetPhysicalDeviceProperties2) + { + skip("Skipping cross process shared resource test due to lack of VK_KHR_get_physical_device_properties2.\n"); + return; + } + + 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); + + 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 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; + VkDeviceMemory vk_memory, vk_memory_import; + VkMemoryRequirements memory_requirements; + VkBufferCreateInfo buffer_create_info; + VkMemoryAllocateInfo alloc_info; + uint32_t queue_family_index; + SECURITY_ATTRIBUTES sa; + VkBuffer vk_buffer; + VkDevice vk_device; + HANDLE handle; + VkResult vr; + char **argv; + int argc; + + 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); + + 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); + + argc = winetest_get_mainargs(&argv); + if (argc > 3 && !strcmp(argv[2], "resource")) + { + sscanf(argv[6], "%p", &handle); + + import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + import_handle_info.pNext = &dedicated_alloc_info; + import_handle_info.handleType = strcmp(argv[5], "kmt") ? + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR : + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR; + import_handle_info.handle = handle; + import_handle_info.name = NULL; + + alloc_info.pNext = &import_handle_info; + + vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory); + ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + + vkFreeMemory(vk_device, vk_memory, NULL); + vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); + + return; + } + + 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; + + 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); + + 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 = 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); + 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); + + test_cross_process_resource(vk_instance, vk_physical_device, FALSE, handle); + + vkFreeMemory(vk_device, vk_memory, NULL); + CloseHandle(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.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); + + 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 = 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); + + test_cross_process_resource(vk_instance, vk_physical_device, TRUE, handle); + + vkFreeMemory(vk_device, vk_memory, NULL); + } + + vkDestroyBuffer(vk_device, vk_buffer, NULL); + vkDestroyDevice(vk_device, NULL); +} + +static void test_unique_device(uint8_t driver_uuid[VK_UUID_SIZE], uint8_t device_uuid[VK_UUID_SIZE], + uint32_t extension_count, const char * const *enabled_extensions, + void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice)) +{ + PFN_vkGetPhysicalDeviceProperties2 pfn_vkGetPhysicalDeviceProperties2; + VkPhysicalDeviceIDPropertiesKHR device_id_properties; + VkPhysicalDeviceProperties2KHR device_properties; + VkPhysicalDevice *vk_physical_devices; + VkInstance vk_instance; + unsigned int i, j; + uint32_t count; + VkResult vr; + + if ((vr = create_instance_skip(extension_count, enabled_extensions, &vk_instance)) < 0) + return; + ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr); + + pfn_vkGetPhysicalDeviceProperties2 + = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2"); + if (!pfn_vkGetPhysicalDeviceProperties2) + pfn_vkGetPhysicalDeviceProperties2 + = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2KHR"); + if (!pfn_vkGetPhysicalDeviceProperties2) + { + skip("Skipping cross process shared resource test due to lack of VK_KHR_get_physical_device_properties2.\n"); + return; + } + + vr = vkEnumeratePhysicalDevices(vk_instance, &count, NULL); + if (vr || !count) + { + skip("No physical devices. VkResult %d.\n", vr); + vkDestroyInstance(vk_instance, NULL); + return; + } + + vk_physical_devices = heap_calloc(count, sizeof(*vk_physical_devices)); + ok(!!vk_physical_devices, "Failed to allocated memory.\n"); + vr = vkEnumeratePhysicalDevices(vk_instance, &count, vk_physical_devices); + ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr); + + for (i = 0; i < count; i++) + { + 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_devices[i], &device_properties); + + for (j = 0; j < VK_UUID_SIZE; j++) + { + if (device_id_properties.driverUUID[j] != driver_uuid[j] || device_id_properties.deviceUUID[j] != device_uuid[j]) + break; + } + + if (j == VK_UUID_SIZE) + { + if (test_func_instance) + test_func_instance(vk_instance, vk_physical_devices[i]); + else + test_func(vk_physical_devices[i]); + + break; + } + } + ok(i != count, "Failed to find matching physical device.\n"); + + heap_free(vk_physical_devices); + + vkDestroyInstance(vk_instance, 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 +967,34 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice))
START_TEST(vulkan) { + unsigned int val; + unsigned int i; + char **argv; + int argc; + + argc = winetest_get_mainargs(&argv); + + if (argc > 3) + { + if (!strcmp(argv[2], "resource")) + { + uint8_t driver_uuid[VK_UUID_SIZE], device_uuid[VK_UUID_SIZE]; + + ok(argc >= 7, "Missing launch arguments\n"); + + for (i = 0; i < VK_UUID_SIZE; i++) + { + /* %02hhX overflows to write 4 bytes on win32 */ + sscanf(&argv[3][i * 2], "%02X", &val); driver_uuid[i] = val; + sscanf(&argv[4][i * 2], "%02X", &val); device_uuid[i] = val; + } + + test_unique_device(driver_uuid, device_uuid, + 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 +1005,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 d226057c69e..f640cc81ded 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. @@ -123,7 +122,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.
On 09.06.21 21:32, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
v9: Add tests for accessing shared resources across device and process boundaries.
dlls/vulkan-1/tests/vulkan.c | 402 +++++++++++++++++++++++++++++++++++ dlls/winevulkan/make_vulkan | 5 +- 2 files changed, 405 insertions(+), 2 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index f222c631232..0bfee72cd59 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -548,6 +548,379 @@ 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, 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(VkInstance vk_instance, VkPhysicalDevice vk_physical_device, BOOL kmt, HANDLE handle) +{
- char driver_uuid[VK_UUID_SIZE * 2 + 1], device_uuid[VK_UUID_SIZE * 2 + 1];
- PFN_vkGetPhysicalDeviceProperties2 pfn_vkGetPhysicalDeviceProperties2;
- VkPhysicalDeviceIDPropertiesKHR device_id_properties;
- VkPhysicalDeviceProperties2KHR device_properties;
- STARTUPINFOA si = { sizeof(si) };
- PROCESS_INFORMATION info;
- char **argv, buf[MAX_PATH];
- unsigned int i;
- BOOL res;
- if (!(pfn_vkGetPhysicalDeviceProperties2
= (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2")))
You don't create a 1.1 instance, so don't use this function.
pfn_vkGetPhysicalDeviceProperties2
= (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2KHR");
You should enable VK_KHR_get_physical_device_properties2 if you want to use this.
- if (!pfn_vkGetPhysicalDeviceProperties2)
- {
skip("Skipping cross process shared resource test due to lack of VK_KHR_get_physical_device_properties2.\n");
return;
- } > +
- 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);
- 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 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;
- VkDeviceMemory vk_memory, vk_memory_import;
- VkMemoryRequirements memory_requirements;
- VkBufferCreateInfo buffer_create_info;
- VkMemoryAllocateInfo alloc_info;
- uint32_t queue_family_index;
- SECURITY_ATTRIBUTES sa;
- VkBuffer vk_buffer;
- VkDevice vk_device;
- HANDLE handle;
- VkResult vr;
- char **argv;
- int argc;
- 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);
- 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);
- argc = winetest_get_mainargs(&argv);
- if (argc > 3 && !strcmp(argv[2], "resource"))
- {
sscanf(argv[6], "%p", &handle);
import_handle_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
import_handle_info.pNext = &dedicated_alloc_info;
import_handle_info.handleType = strcmp(argv[5], "kmt") ?
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR :
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR;
import_handle_info.handle = handle;
import_handle_info.name = NULL;
alloc_info.pNext = &import_handle_info;
vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &vk_memory);
ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr);
vkFreeMemory(vk_device, vk_memory, NULL);
vkDestroyBuffer(vk_device, vk_buffer, NULL);
vkDestroyDevice(vk_device, NULL);
return;
- }
- 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;
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);
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 = 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);
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);
test_cross_process_resource(vk_instance, vk_physical_device, FALSE, handle);
vkFreeMemory(vk_device, vk_memory, NULL);
CloseHandle(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.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);
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 = 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);
test_cross_process_resource(vk_instance, vk_physical_device, TRUE, handle);
vkFreeMemory(vk_device, vk_memory, NULL);
- }
- vkDestroyBuffer(vk_device, vk_buffer, NULL);
- vkDestroyDevice(vk_device, NULL);
+}
+static void test_unique_device(uint8_t driver_uuid[VK_UUID_SIZE], uint8_t device_uuid[VK_UUID_SIZE],
uint32_t extension_count, const char * const *enabled_extensions,
void (*test_func_instance)(VkInstance, VkPhysicalDevice), void (*test_func)(VkPhysicalDevice))
+{
- PFN_vkGetPhysicalDeviceProperties2 pfn_vkGetPhysicalDeviceProperties2;
- VkPhysicalDeviceIDPropertiesKHR device_id_properties;
- VkPhysicalDeviceProperties2KHR device_properties;
- VkPhysicalDevice *vk_physical_devices;
- VkInstance vk_instance;
- unsigned int i, j;
- uint32_t count;
- VkResult vr;
- if ((vr = create_instance_skip(extension_count, enabled_extensions, &vk_instance)) < 0)
return;
- ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr);
- pfn_vkGetPhysicalDeviceProperties2
= (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2");
again, this is a 1.1 function
- if (!pfn_vkGetPhysicalDeviceProperties2)
pfn_vkGetPhysicalDeviceProperties2
= (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(vk_instance, "vkGetPhysicalDeviceProperties2KHR");
again, enable the extension
- if (!pfn_vkGetPhysicalDeviceProperties2)
- {
skip("Skipping cross process shared resource test due to lack of VK_KHR_get_physical_device_properties2.\n");
return;
- }
- vr = vkEnumeratePhysicalDevices(vk_instance, &count, NULL);
- if (vr || !count)
- {
skip("No physical devices. VkResult %d.\n", vr);
vkDestroyInstance(vk_instance, NULL);
return;
- }
- vk_physical_devices = heap_calloc(count, sizeof(*vk_physical_devices));
- ok(!!vk_physical_devices, "Failed to allocated memory.\n");
- vr = vkEnumeratePhysicalDevices(vk_instance, &count, vk_physical_devices);
- ok(vr == VK_SUCCESS, "Got unexpected VkResult %d.\n", vr);
- for (i = 0; i < count; i++)
- {
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_devices[i], &device_properties);
for (j = 0; j < VK_UUID_SIZE; j++)
{
if (device_id_properties.driverUUID[j] != driver_uuid[j] || device_id_properties.deviceUUID[j] != device_uuid[j])
break;
}
memcmp?
if (j == VK_UUID_SIZE)
{
if (test_func_instance)
test_func_instance(vk_instance, vk_physical_devices[i]);
else
test_func(vk_physical_devices[i]);
break;
}
- }
- ok(i != count, "Failed to find matching physical device.\n");
- heap_free(vk_physical_devices);
- vkDestroyInstance(vk_instance, 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 +967,34 @@ static void for_each_device(void (*test_func)(VkPhysicalDevice))
START_TEST(vulkan) {
- unsigned int val;
- unsigned int i;
- char **argv;
- int argc;
- argc = winetest_get_mainargs(&argv);
- if (argc > 3)
- {
if (!strcmp(argv[2], "resource"))
{
uint8_t driver_uuid[VK_UUID_SIZE], device_uuid[VK_UUID_SIZE];
ok(argc >= 7, "Missing launch arguments\n");
for (i = 0; i < VK_UUID_SIZE; i++)
{
/* %02hhX overflows to write 4 bytes on win32 */
sscanf(&argv[3][i * 2], "%02X", &val); driver_uuid[i] = val;
Shouldn't these be on separate lines?
sscanf(&argv[4][i * 2], "%02X", &val); device_uuid[i] = val;
}
test_unique_device(driver_uuid, device_uuid,
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 +1005,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 d226057c69e..f640cc81ded 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.
@@ -123,7 +122,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: Derek Lesho dlesho@codeweavers.com --- dlls/vulkan-1/tests/vulkan.c | 8 +- dlls/winevulkan/make_vulkan | 20 +- dlls/winevulkan/vulkan.c | 351 ++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan_private.h | 24 +++ 4 files changed, 394 insertions(+), 9 deletions(-)
diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index 0bfee72cd59..03df0c74413 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -779,10 +779,14 @@ static void test_external_memory(VkInstance vk_instance, VkPhysicalDevice vk_phy 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); - ok(vk_memory_import != vk_memory, "Expected new memory object.\n"); + 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_import, NULL); + }
test_cross_process_resource(vk_instance, vk_physical_device, FALSE, handle);
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index f640cc81ded..677a6ea0c9e 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -108,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 @@ -123,7 +122,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 @@ -182,7 +181,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}, @@ -191,10 +190,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}, @@ -224,7 +226,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 @@ -260,12 +262,20 @@ 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": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], }
@@ -1056,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 bdd9f2151c0..87fe92e45f7 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, @@ -1710,3 +1802,256 @@ 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 (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;
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 677a6ea0c9e..0c8a523c3c8 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -193,6 +193,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}, @@ -275,7 +276,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 87fe92e45f7..31c3ae1f1fd 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 */ @@ -2055,3 +2081,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; +}