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@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);