[PATCH vkd3d 1/2] vkd3d: Always return a valid allocation size for D3D12 default alignments.

Conor McCarthy cmccarthy at codeweavers.com
Wed Nov 13 08:48:28 CST 2019


Some hardware and driver combinations, e.g. AMD RX 580 / RADV, do not support
alignments of 0x1000 and 0x10000. This causes GetResourceAllocationInfo() to
return a size of ~0 for valid D3D12 alignments. Some games do not check for
this. For example Hitman 2 will allocate heaps of size 0xffffffff and run out
of vram. This patch also fixes RX 580 alignment test failures.

Signed-off-by: Conor McCarthy <cmccarthy at codeweavers.com>
---
 libs/vkd3d/device.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index 0624318..7421978 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -2893,6 +2893,19 @@ static void STDMETHODCALLTYPE d3d12_device_CopyDescriptorsSimple(ID3D12Device *i
             1, &src_descriptor_range_offset, &descriptor_count, descriptor_heap_type);
 }
 
+static bool d3d12_validate_resource_alignment(const D3D12_RESOURCE_DESC *desc,
+        uint64_t requested_alignment, uint64_t vk_alignment, uint64_t estimated_size)
+{
+    /* We must return true if the requested alignment is one of D3D12's default alignments. Some games,
+     * e.g. Hitman 2, assume that these will work and don't check the returned allocation size for ~0. */
+    if (requested_alignment == D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT)
+        return estimated_size <= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+
+    return !(desc->Alignment % vk_alignment)
+            || requested_alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT
+            || (desc->SampleDesc.Count > 1 && requested_alignment == D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT);
+}
+
 static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResourceAllocationInfo(
         ID3D12Device *iface, D3D12_RESOURCE_ALLOCATION_INFO *info, UINT visible_mask,
         UINT count, const D3D12_RESOURCE_DESC *resource_descs)
@@ -2930,6 +2943,7 @@ static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResour
 
     if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
     {
+        estimated_size = desc->Width;
         info->SizeInBytes = desc->Width;
         info->Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
     }
@@ -2943,21 +2957,20 @@ static D3D12_RESOURCE_ALLOCATION_INFO * STDMETHODCALLTYPE d3d12_device_GetResour
 
         info->Alignment = max(info->Alignment, requested_alignment);
 
-        if (info->Alignment < D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)
+        if (!(format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0)))
         {
-            if (!(format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0)))
-            {
-                WARN("Invalid format %#x.\n", desc->Format);
-                goto invalid;
-            }
-
-            estimated_size = desc->Width * desc->Height * desc->DepthOrArraySize * format->byte_count;
-            if (estimated_size > D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)
-                info->Alignment = max(info->Alignment, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
+            WARN("Invalid format %#x.\n", desc->Format);
+            goto invalid;
         }
+
+        estimated_size = desc->Width * desc->Height * desc->DepthOrArraySize * format->byte_count;
+
+        if (info->Alignment < D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT
+                && estimated_size > D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)
+            info->Alignment = max(info->Alignment, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
     }
 
-    if (desc->Alignment % info->Alignment)
+    if (!d3d12_validate_resource_alignment(desc, requested_alignment, info->Alignment, estimated_size))
     {
         WARN("Invalid resource alignment %#"PRIx64" (required %#"PRIx64").\n",
                 desc->Alignment, info->Alignment);
-- 
2.23.0




More information about the wine-devel mailing list