dzn: Unaligned block-compressed textures are silently unsupported
Calling vkGetImageMemoryRequirements
with a VkImageCreateInfo
that specifies a block-compressed format (for example VK_FORMAT_BC4_UNORM_BLOCK
), and an extent that is not aligned to the block size (4), results in a VkMemoryRequirements
object with the size
field set to UINT64_MAX
. This then causes following memory allocations to fail with OUT_OF_MEMORY
errors.
Tracing this back through the driver, the culprit is here. The following D3D12_RESOURCE_DESC
(taken from a real world application) causes dzn_ID3D12Device4_GetResourceAllocationInfo
to return an error (which is signified by a SizeInBytes
of UINT64_MAX
):
D3D12_RESOURCE_DESC desc = {
.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
.Width = 80,
.Height = 45,
.DepthOrArraySize = 1,
.MipLevels = 1,
.Format = DXGI_FORMAT_BC4_TYPELESS,
.SampleDesc = { .Count = 1, .Quality = 0 },
.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
.Flags = D3D12_RESOURCE_FLAG_NONE
};
This is understandable, as D3D12 has a (un)documented limitation that block-compressed textures need to be aligned to their block size (in this instance 4). See the remark here and conversation here.
Some reading over the Vulkan documentation for block-compressed formats, this requirement doesn't appear to be listed anywhere, nor are there any other alignment requirements for these formats. This results in different behaviour between applications running on native Vulkan drivers, and Vulkan layered on D3D12.
It does seem like this requirement is relaxed in some versions of Windows, as this feature flag exists: UnalignedBlockTexturesSupported. However, in my testing on the Windows 10 and 11 machines I have available to me, this is false on all of them (including my target platform which is a Windows on ARM64 device).
Beyond the primary issue, I believe there should be an error boundary between the call to GetResourceAllocationInfo
and the result returned to the caller of GetImageMemoryRequirements(2)
. It shouldn't require me to step through the driver source, and understand the result that D3D12 is returning to figure out why the result of GetImageMemoryRequirements
contains such a large size
value. Calls to GetResourceAllocationInfo
that do have a SizeInBytes
of UINT64_MAX
should return a VK_ERROR
.
I would assume everything mentioned above for GetResourceAllocationInfo
(which is where we encountered the issue), also applies to other resource creation/allocation D3D12 functions that take a D3D12_RESOURCE_DESC
(like CreateCommittedResource
).