From 233ff38175beaca02e298d069fe6d5c7e679d612 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Tue, 28 Jun 2022 19:05:21 +0200 Subject: [PATCH] vkd3d: Force LINEAR images to be allocated as committed resources. We have no way of expressing size / alignment requirements to applications since the API query does not provide us with heap information. Reuse the fallback path for promoting placed to committed. Guardians of the Galaxy hits a case where it tries to place 3x host-visible 3D images in one heap, and they end up overlapping in memory due to a 16x16x80 3D texture taking up far less space in optimal tiling compared to linear tiling on AMD. Signed-off-by: Hans-Kristian Arntzen --- libs/vkd3d/memory.c | 22 ++++++++++++++++++++++ libs/vkd3d/resource.c | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/libs/vkd3d/memory.c b/libs/vkd3d/memory.c index 61c6bc7f..1ec4fe2c 100644 --- a/libs/vkd3d/memory.c +++ b/libs/vkd3d/memory.c @@ -1477,6 +1477,7 @@ static bool vkd3d_heap_allocation_accept_deferred_resource_placements(struct d3d HRESULT vkd3d_allocate_heap_memory(struct d3d12_device *device, struct vkd3d_memory_allocator *allocator, const struct vkd3d_allocate_heap_memory_info *info, struct vkd3d_memory_allocation *allocation) { + struct vkd3d_allocate_heap_memory_info heap_info; struct vkd3d_allocate_memory_info alloc_info; HRESULT hr; @@ -1492,6 +1493,27 @@ HRESULT vkd3d_allocate_heap_memory(struct d3d12_device *device, struct vkd3d_mem if (!(info->heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS)) alloc_info.flags |= VKD3D_ALLOCATION_FLAG_GLOBAL_BUFFER; + if (is_cpu_accessible_heap(&info->heap_desc.Properties)) + { + if (info->heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS) + { + /* If the heap was only designed to handle images, the heap is useless, + * and we can force everything to go through committed path. */ + memset(allocation, 0, sizeof(*allocation)); + return S_OK; + } + else + { + /* CPU visible textures are never placed on a heap directly, + * since LINEAR images have alignment / size requirements + * that are vastly different from OPTIMAL ones. + * We can place buffers however. */ + heap_info = *info; + info = &heap_info; + heap_info.heap_desc.Flags |= D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS; + } + } + hr = vkd3d_allocate_memory(device, allocator, &alloc_info, allocation); if (hr == E_OUTOFMEMORY && vkd3d_heap_allocation_accept_deferred_resource_placements(device, &info->heap_desc.Properties, info->heap_desc.Flags)) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index d33ae5ac..a8c7b187 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -2863,15 +2863,25 @@ HRESULT d3d12_resource_create_placed(struct d3d12_device *device, const D3D12_RE VkMemoryRequirements memory_requirements; VkBindImageMemoryInfo bind_info; struct d3d12_resource *object; + bool force_committed; VkResult vr; HRESULT hr; if (FAILED(hr = d3d12_resource_validate_heap(desc, heap))) return hr; - if (heap->allocation.device_allocation.vk_memory == VK_NULL_HANDLE) + /* Placed linear textures are ... problematic + * since we have no way of signalling that they have different alignment and size requirements + * than optimal textures. GetResourceAllocationInfo() does not take heap property information + * and assumes that we are not modifying the tiling mode. */ + force_committed = desc->Dimension != D3D12_RESOURCE_DIMENSION_BUFFER && + is_cpu_accessible_heap(&heap->desc.Properties); + + if (force_committed || heap->allocation.device_allocation.vk_memory == VK_NULL_HANDLE) { - WARN("Placing resource on heap with no memory backing it. Falling back to committed resource.\n"); + if (!force_committed) + WARN("Placing resource on heap with no memory backing it. Falling back to committed resource.\n"); + if (FAILED(hr = d3d12_resource_create_committed(device, desc, &heap->desc.Properties, heap->desc.Flags & ~(D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES |