From: Jacek Caban jacek@codeweavers.com
--- dlls/winevulkan/vulkan.c | 163 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 4 + 2 files changed, 160 insertions(+), 7 deletions(-)
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index b092756fd4e..9470bcec864 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -31,6 +31,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
+static BOOL is_wow64(void) +{ + return sizeof(void *) == sizeof(UINT64) && NtCurrentTeb()->WowTebOffset; +} + +static BOOL use_external_memory(void) +{ + return is_wow64(); +} + +static ULONG_PTR zero_bits(void) +{ + return is_wow64() ? 0x7fffffff : 0; +} + #define wine_vk_count_struct(s, t) wine_vk_count_struct_((void *)s, VK_STRUCTURE_TYPE_##t) static uint32_t wine_vk_count_struct_(void *s, VkStructureType t) { @@ -227,6 +242,8 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance handle->base.unix_handle = (uintptr_t)object; WINE_VK_ADD_DISPATCHABLE_MAPPING(instance, handle, phys_dev, object);
+ instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(phys_dev, &object->memory_properties); + res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &num_host_properties, NULL); if (res != VK_SUCCESS) @@ -264,6 +281,23 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance { TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties[i].extensionName); } + if (use_external_memory() && !strcmp(host_properties[i].extensionName, "VK_EXT_external_memory_host")) + { + VkPhysicalDeviceExternalMemoryHostPropertiesEXT host_mem_props = + { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT, + }; + VkPhysicalDeviceProperties2 props = + { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &host_mem_props, + }; + instance->funcs.p_vkGetPhysicalDeviceProperties2KHR(phys_dev, &props); + object->external_memory_align = host_mem_props.minImportedHostPointerAlignment; + if (object->external_memory_align) + TRACE("Using eVK_EXT_external_memory_host for memory mapping with alignment: %u\n", + object->external_memory_align); + } }
TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties); @@ -353,7 +387,8 @@ static void wine_vk_device_get_queues(struct wine_device *device, } }
-static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) +static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_dev, + struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { unsigned int i;
@@ -375,6 +410,19 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src } }
+ if (phys_dev->external_memory_align) + { + const char **new_extensions; + + new_extensions = conversion_context_alloc(ctx, (dst->enabledExtensionCount + 2) * + sizeof(*dst->ppEnabledExtensionNames)); + memcpy(new_extensions, src->ppEnabledExtensionNames, + dst->enabledExtensionCount * sizeof(*dst->ppEnabledExtensionNames)); + new_extensions[dst->enabledExtensionCount++] = "VK_KHR_external_memory"; + new_extensions[dst->enabledExtensionCount++] = "VK_EXT_external_memory_host"; + dst->ppEnabledExtensionNames = new_extensions; + } + return VK_SUCCESS; }
@@ -447,8 +495,8 @@ NTSTATUS init_vulkan32(void *args) * This function takes care of extensions handled at winevulkan layer, a Wine graphics * driver is responsible for handling e.g. surface extensions. */ -static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src, - VkInstanceCreateInfo *dst, struct wine_instance *object) +static VkResult wine_vk_instance_convert_create_info(struct conversion_context *ctx, + const VkInstanceCreateInfo *src, VkInstanceCreateInfo *dst, struct wine_instance *object) { VkDebugUtilsMessengerCreateInfoEXT *debug_utils_messenger; VkDebugReportCallbackCreateInfoEXT *debug_report_callback; @@ -516,6 +564,19 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo } }
+ if (use_external_memory()) + { + const char **new_extensions; + + new_extensions = conversion_context_alloc(ctx, (dst->enabledExtensionCount + 2) * + sizeof(*dst->ppEnabledExtensionNames)); + memcpy(new_extensions, src->ppEnabledExtensionNames, + dst->enabledExtensionCount * sizeof(*dst->ppEnabledExtensionNames)); + new_extensions[dst->enabledExtensionCount++] = "VK_KHR_get_physical_device_properties2"; + new_extensions[dst->enabledExtensionCount++] = "VK_KHR_external_memory_capabilities"; + dst->ppEnabledExtensionNames = new_extensions; + } + return VK_SUCCESS; }
@@ -689,6 +750,7 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre VkDeviceCreateInfo create_info_host; struct VkQueue_T *queue_handles; struct wine_queue *next_queue; + struct conversion_context ctx; struct wine_device *object; unsigned int i; VkResult res; @@ -712,10 +774,12 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre
object->phys_dev = phys_dev;
- res = wine_vk_device_convert_create_info(create_info, &create_info_host); + init_conversion_context(&ctx); + res = wine_vk_device_convert_create_info(phys_dev, &ctx, create_info, &create_info_host); if (res == VK_SUCCESS) res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, &create_info_host, NULL /* allocator */, &object->device); + free_conversion_context(&ctx); WINE_VK_ADD_DISPATCHABLE_MAPPING(phys_dev->instance, device_handle, object->device, object); if (res != VK_SUCCESS) { @@ -780,6 +844,7 @@ VkResult wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, VkInstance client_instance = client_ptr; VkInstanceCreateInfo create_info_host; const VkApplicationInfo *app_info; + struct conversion_context ctx; struct wine_instance *object; VkResult res;
@@ -794,9 +859,11 @@ VkResult wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, list_init(&object->wrappers); pthread_rwlock_init(&object->wrapper_lock, NULL);
- res = wine_vk_instance_convert_create_info(create_info, &create_info_host, object); + init_conversion_context(&ctx); + res = wine_vk_instance_convert_create_info(&ctx, create_info, &create_info_host, object); if (res == VK_SUCCESS) res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance); + free_conversion_context(&ctx); if (res != VK_SUCCESS) { ERR("Failed to create instance, res=%d\n", res); @@ -1446,18 +1513,85 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo { struct wine_device *device = wine_device_from_handle(handle); struct wine_device_memory *memory; + VkMemoryAllocateInfo info = *alloc_info; + VkImportMemoryHostPointerInfoEXT host_pointer_info; + uint32_t mem_flags; + void *mapping = NULL; VkResult result;
+ mem_flags = device->phys_dev->memory_properties.memoryTypes[alloc_info->memoryTypeIndex].propertyFlags; + if (device->phys_dev->external_memory_align && (mem_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + !find_next_struct(alloc_info->pNext, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT)) + { + VkMemoryHostPointerPropertiesEXT props = + { + .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT, + }; + uint32_t i, flags, align = device->phys_dev->external_memory_align - 1; + SIZE_T alloc_size = info.allocationSize; + + if (NtAllocateVirtualMemory(GetCurrentProcess(), &mapping, zero_bits(), &alloc_size, + MEM_COMMIT, PAGE_READWRITE)) + { + ERR("NtAllocateVirtualMemory failed\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + result = device->funcs.p_vkGetMemoryHostPointerPropertiesEXT(device->device, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, mapping, &props); + if (result != VK_SUCCESS) + { + ERR("vkGetMemoryHostPointerPropertiesEXT failed: %d\n", result); + return result; + } + + if (!(props.memoryTypeBits & (1u << info.memoryTypeIndex))) + { + for (i = 0; i < device->phys_dev->memory_properties.memoryTypeCount; i++) + { + if (!(props.memoryTypeBits & (1u << i))) + continue; + flags = device->phys_dev->memory_properties.memoryTypes[i].propertyFlags; + flags = flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + mem_flags = flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + if ((flags & mem_flags) == mem_flags) + { + TRACE("Memory type not compatible with host memory, using %u instead\n", i); + info.memoryTypeIndex = i; + break; + } + } + if (i == device->phys_dev->memory_properties.memoryTypeCount) + { + FIXME("Not found memory type compatible with requested memory type\n"); + alloc_size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &mapping, &alloc_size, MEM_RELEASE); + } + } + + if (props.memoryTypeBits & (1u << info.memoryTypeIndex)) + { + host_pointer_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT; + host_pointer_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; + host_pointer_info.pHostPointer = mapping; + host_pointer_info.pNext = info.pNext; + info.pNext = &host_pointer_info; + + info.allocationSize = (info.allocationSize + align) & ~align; + } + } + if (!(memory = malloc(sizeof(*memory)))) return VK_ERROR_OUT_OF_HOST_MEMORY;
- result = device->funcs.p_vkAllocateMemory(device->device, alloc_info, NULL, &memory->memory); + result = device->funcs.p_vkAllocateMemory(device->device, &info, NULL, &memory->memory); if (result != VK_SUCCESS) { free(memory); return result; }
+ memory->mapping = mapping; *ret = (VkDeviceMemory)(uintptr_t)memory; return VK_SUCCESS; } @@ -1472,6 +1606,13 @@ void wine_vkFreeMemory(VkDevice handle, VkDeviceMemory memory_handle, const VkAl memory = wine_device_memory_from_handle(memory_handle);
device->funcs.p_vkFreeMemory(device->device, memory->memory, NULL); + + if (memory->mapping) + { + SIZE_T alloc_size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &memory->mapping, &alloc_size, MEM_RELEASE); + } + free(memory); }
@@ -1482,6 +1623,13 @@ VkResult wine_vkMapMemory(VkDevice handle, VkDeviceMemory memory_handle, VkDevic struct wine_device_memory *memory = wine_device_memory_from_handle(memory_handle); VkResult result;
+ if (memory->mapping) + { + *data = (char *)memory->mapping + offset; + TRACE("returning %p\n", *data); + return VK_SUCCESS; + } + result = device->funcs.p_vkMapMemory(device->device, memory->memory, offset, size, flags, data);
#ifdef _WIN64 @@ -1502,7 +1650,8 @@ void wine_vkUnmapMemory(VkDevice handle, VkDeviceMemory memory_handle) struct wine_device *device = wine_device_from_handle(handle); struct wine_device_memory *memory = wine_device_memory_from_handle(memory_handle);
- device->funcs.p_vkUnmapMemory(device->device, memory->memory); + if (!memory->mapping) + device->funcs.p_vkUnmapMemory(device->device, memory->memory); }
static inline void adjust_max_image_count(struct wine_phys_dev *phys_dev, VkSurfaceCapabilitiesKHR* capabilities) diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 8055b2380fd..92504bffb41 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -125,9 +125,12 @@ struct wine_phys_dev VkPhysicalDevice handle; /* client physical device */ VkPhysicalDevice phys_dev; /* native physical device */
+ VkPhysicalDeviceMemoryProperties memory_properties; VkExtensionProperties *extensions; uint32_t extension_count;
+ uint32_t external_memory_align; + struct wine_vk_mapping mapping; };
@@ -172,6 +175,7 @@ static inline struct wine_cmd_pool *wine_cmd_pool_from_handle(VkCommandPool hand struct wine_device_memory { VkDeviceMemory memory; + void *mapping; };
static inline struct wine_device_memory *wine_device_memory_from_handle(VkDeviceMemory handle)