Greatly reduces number of maps for applications which do not do this themselves. Also add a config option to use older map-on-demand behavior, which might be nice for debugging tools.
Signed-off-by: Hans-Kristian Arntzen post@arntzen-software.no --- libs/vkd3d/device.c | 1 + libs/vkd3d/resource.c | 33 +++++++++++++++++++++++++++++++++ libs/vkd3d/vkd3d_private.h | 2 ++ 3 files changed, 36 insertions(+)
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 460bdf9..d81d53c 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -428,6 +428,7 @@ static void vkd3d_init_debug_report(struct vkd3d_instance *instance) static const struct vkd3d_debug_option vkd3d_config_options[] = { {"vk_debug", VKD3D_CONFIG_FLAG_VULKAN_DEBUG}, /* enable Vulkan debug extensions */ + {"nopersistent", VKD3D_CONFIG_FLAG_NO_PERSISTENT_MAPPING}, /* No persistent host pointer mapping. */ };
static uint64_t vkd3d_init_config_flags(void) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 88f184d..87277f7 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -299,6 +299,9 @@ static void d3d12_heap_destroy(struct d3d12_heap *heap)
TRACE("Destroying heap %p.\n", heap);
+ if (heap->is_persistent && heap->map_ptr) + VK_CALL(vkUnmapMemory(device->vk_device, heap->vk_memory)); + vkd3d_private_store_destroy(&heap->private_store);
VK_CALL(vkFreeMemory(device->vk_device, heap->vk_memory, NULL)); @@ -420,6 +423,18 @@ static HRESULT d3d12_heap_map(struct d3d12_heap *heap, uint64_t offset, VkResult vr; int rc;
+ /* If we have a persistent heap, there is no need to lock and map/unmap. + * Just hand a pointer to caller. There is technically a need to do cache maintenance here + * but we always use COHERENT memory types for host memory, so no need to deal with incoherent + * cached host memory. */ + if (heap->is_persistent) + { + TRACE("Mapping persistently mapped heap %p.\n", heap); + assert(heap->map_ptr); + *data = (BYTE *)heap->map_ptr + offset; + return S_OK; + } + if ((rc = pthread_mutex_lock(&heap->mutex))) { ERR("Failed to lock mutex, error %d.\n", rc); @@ -475,6 +490,10 @@ static void d3d12_heap_unmap(struct d3d12_heap *heap, struct d3d12_resource *res struct d3d12_device *device = heap->device; int rc;
+ /* If the heap is persistent, mapping happens when heap is destroyed. */ + if (heap->is_persistent) + return; + if ((rc = pthread_mutex_lock(&heap->mutex))) { ERR("Failed to lock mutex, error %d.\n", rc); @@ -543,11 +562,13 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, VkDeviceSize vk_memory_size; HRESULT hr; int rc; + const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
heap->ID3D12Heap_iface.lpVtbl = &d3d12_heap_vtbl; heap->refcount = 1;
heap->is_private = !!resource; + heap->is_persistent = false;
heap->desc = *desc;
@@ -614,6 +635,18 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, return hr; }
+ /* If the heap is in HOST_VISIBLE space, just persistently map it. + * This way we avoid mapping and unmapping the whole memory block and taking locks every time + * a small sub-region is mapped. */ + if ((device->vkd3d_instance->config_flags & VKD3D_CONFIG_FLAG_NO_PERSISTENT_MAPPING) == 0) + { + if (device->memory_properties.memoryTypes[heap->vk_memory_type].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) + { + if (VK_CALL(vkMapMemory(device->vk_device, heap->vk_memory, 0, VK_WHOLE_SIZE, 0, &heap->map_ptr)) == VK_SUCCESS) + heap->is_persistent = true; + } + } + heap->device = device; if (!heap->is_private) d3d12_device_add_ref(heap->device); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index a51ca4d..d842f58 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -130,6 +130,7 @@ struct vkd3d_vulkan_info enum vkd3d_config_flags { VKD3D_CONFIG_FLAG_VULKAN_DEBUG = 0x00000001, + VKD3D_CONFIG_FLAG_NO_PERSISTENT_MAPPING = 0x00000002 };
struct vkd3d_instance @@ -360,6 +361,7 @@ struct d3d12_heap LONG refcount;
bool is_private; + bool is_persistent; D3D12_HEAP_DESC desc;
pthread_mutex_t mutex;