From: Jacek Caban jacek@codeweavers.com
--- dlls/winevulkan/vulkan.c | 147 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 2 + 2 files changed, 142 insertions(+), 7 deletions(-)
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 9123e65da4c..5930451ed0f 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -42,6 +42,11 @@ static BOOL use_external_memory(void) return is_wow64(); }
+static BOOL use_map_placed(void) +{ + return is_wow64(); +} + static ULONG_PTR zero_bits = 0;
#define wine_vk_count_struct(s, t) wine_vk_count_struct_((void *)s, VK_STRUCTURE_TYPE_##t) @@ -223,6 +228,7 @@ static void wine_vk_physical_device_free(struct wine_phys_dev *phys_dev) static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance *instance, VkPhysicalDevice phys_dev, VkPhysicalDevice handle) { + BOOL have_memory_placed = FALSE, have_map_memory2 = FALSE; struct wine_phys_dev *object; uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; @@ -281,6 +287,10 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance } if (!strcmp(host_properties[i].extensionName, "VK_EXT_external_memory_host")) have_external_memory_host = TRUE; + else if (!strcmp(host_properties[i].extensionName, "VK_EXT_map_memory_placed")) + have_memory_placed = TRUE; + else if (!strcmp(host_properties[i].extensionName, "VK_KHR_map_memory2")) + have_map_memory2 = TRUE; }
TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties); @@ -301,7 +311,38 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance } object->extension_count = num_properties;
- if (use_external_memory() && have_external_memory_host) + if (have_memory_placed && have_map_memory2 && use_map_placed()) + { + VkPhysicalDeviceMapMemoryPlacedFeaturesEXT map_placed_feature = + { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT, + }; + VkPhysicalDeviceFeatures2 features = + { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &map_placed_feature, + }; + + instance->funcs.p_vkGetPhysicalDeviceFeatures2KHR(phys_dev, &features); + if (map_placed_feature.memoryMapPlaced && map_placed_feature.memoryUnmapReserve) + { + VkPhysicalDeviceMapMemoryPlacedPropertiesEXT map_placed_props = + { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_PROPERTIES_EXT, + }; + VkPhysicalDeviceProperties2 props = + { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &map_placed_props, + }; + + instance->funcs.p_vkGetPhysicalDeviceProperties2(phys_dev, &props); + object->map_placed_align = map_placed_props.minPlacedMemoryMapAlignment; + TRACE("map_placed_align %u\n", object->map_placed_align); + } + } + + if (use_external_memory() && have_external_memory_host && !object->map_placed_align) { VkPhysicalDeviceExternalMemoryHostPropertiesEXT host_mem_props = { @@ -414,7 +455,31 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de } }
- if (phys_dev->external_memory_align) + if (phys_dev->map_placed_align) + { + VkPhysicalDeviceMapMemoryPlacedFeaturesEXT *features; + 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_EXT_map_memory_placed"; + new_extensions[dst->enabledExtensionCount++] = "VK_KHR_map_memory2"; + dst->ppEnabledExtensionNames = new_extensions; + + if (!(features = find_next_struct(dst->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT))) + { + features = conversion_context_alloc(ctx, sizeof(*features)); + features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT; + features->pNext = (void *)dst->pNext; + features->memoryMapRangePlaced = VK_FALSE; + dst->pNext = features; + } + features->memoryMapPlaced = VK_TRUE; + features->memoryUnmapReserve = VK_TRUE; + } + else if (phys_dev->external_memory_align) { const char **new_extensions;
@@ -1605,10 +1670,16 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo void *mapping = NULL; VkResult result;
- /* For host visible memory, we try to use VK_EXT_external_memory_host on wow64 - * to ensure that mapped pointer is 32-bit. */ 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) && + if (device->phys_dev->map_placed_align) + { + if (mem_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + { + VkDeviceSize align = device->phys_dev->map_placed_align - 1; + info.allocationSize = (info.allocationSize + align) & ~align; + } + } + else 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 = @@ -1683,6 +1754,7 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo return result; }
+ memory->size = info.allocationSize; memory->mapping = mapping; *ret = (VkDeviceMemory)(uintptr_t)memory; return VK_SUCCESS; @@ -1697,6 +1769,17 @@ void wine_vkFreeMemory(VkDevice handle, VkDeviceMemory memory_handle, const VkAl return; memory = wine_device_memory_from_handle(memory_handle);
+ if (memory->mapping && device->phys_dev->map_placed_align) + { + const VkMemoryUnmapInfoKHR info = + { + .sType = VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR, + .memory = memory->host_memory, + .flags = VK_MEMORY_UNMAP_RESERVE_BIT_EXT, + }; + device->funcs.p_vkUnmapMemory2KHR(device->host_device, &info); + } + device->funcs.p_vkFreeMemory(device->host_device, memory->host_memory, NULL);
if (memory->mapping) @@ -1730,7 +1813,42 @@ VkResult wine_vkMapMemory2KHR(VkDevice handle, const VkMemoryMapInfoKHR *map_inf VkMemoryMapInfoKHR info = *map_info; VkResult result;
+ info.memory = memory->host_memory; + + if (device->phys_dev->map_placed_align && !memory->mapping && + !find_next_struct(info.pNext, VK_STRUCTURE_TYPE_MEMORY_MAP_PLACED_INFO_EXT)) + { + VkMemoryMapPlacedInfoEXT placed_info = + { + .sType = VK_STRUCTURE_TYPE_MEMORY_MAP_PLACED_INFO_EXT, + .pNext = info.pNext, + }; + SIZE_T alloc_size = memory->size; + + info.pNext = &placed_info; + info.size = VK_WHOLE_SIZE; + info.flags |= VK_MEMORY_MAP_PLACED_BIT_EXT; + + if (NtAllocateVirtualMemory(GetCurrentProcess(), &placed_info.pPlacedAddress, zero_bits, &alloc_size, + MEM_RESERVE, PAGE_READWRITE)) + { + ERR("NtAllocateVirtualMemory failed\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + result = device->funcs.p_vkMapMemory2KHR(device->host_device, &info, data); + if (result != VK_SUCCESS) + { + ERR("vkMapMemory2EXT failed: %d\n", result); + alloc_size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &placed_info.pPlacedAddress, &alloc_size, MEM_RELEASE); + return result; + } + memory->mapping = placed_info.pPlacedAddress; + TRACE("Using VK_EXT_map_memory_placed mapping %p\n", memory->mapping); + } + if (memory->mapping) { *data = (char *)memory->mapping + info.offset; @@ -1778,8 +1896,9 @@ VkResult wine_vkUnmapMemory2KHR(VkDevice handle, const VkMemoryUnmapInfoKHR *unm struct wine_device *device = wine_device_from_handle(handle); struct wine_device_memory *memory = wine_device_memory_from_handle(unmap_info->memory); VkMemoryUnmapInfoKHR info; + VkResult result;
- if (memory->mapping) + if (memory->mapping && device->phys_dev->external_memory_align) return VK_SUCCESS;
if (!device->funcs.p_vkUnmapMemory2KHR) @@ -1791,7 +1910,21 @@ VkResult wine_vkUnmapMemory2KHR(VkDevice handle, const VkMemoryUnmapInfoKHR *unm
info = *unmap_info; info.memory = memory->host_memory; - return device->funcs.p_vkUnmapMemory2KHR(device->host_device, &info); + if (memory->mapping) + info.flags |= VK_MEMORY_UNMAP_RESERVE_BIT_EXT; + + result = device->funcs.p_vkUnmapMemory2KHR(device->host_device, &info); + + if (result == VK_SUCCESS && memory->mapping) + { + if (!(unmap_info->flags & VK_MEMORY_UNMAP_RESERVE_BIT_EXT)) + { + SIZE_T size = 0; + NtFreeVirtualMemory(GetCurrentProcess(), &memory->mapping, &size, MEM_RELEASE); + } + memory->mapping = NULL; + } + return result; }
VkResult wine_vkCreateBuffer(VkDevice handle, const VkBufferCreateInfo *create_info, diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 4e4d665299f..14987eb1a44 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -130,6 +130,7 @@ struct wine_phys_dev uint32_t extension_count;
uint32_t external_memory_align; + uint32_t map_placed_align;
struct wine_vk_mapping mapping; }; @@ -175,6 +176,7 @@ static inline struct wine_cmd_pool *wine_cmd_pool_from_handle(VkCommandPool hand struct wine_device_memory { VkDeviceMemory host_memory; + VkDeviceSize size; void *mapping; };