hexops / mach

zig game engine & graphics toolkit
https://machengine.org
Other
3.13k stars 152 forks source link

Sprite example fails to run on D3D12 with a discrete GPU #1225

Open hordurj opened 1 month ago

hordurj commented 1 month ago

When running the Sprite example on a discrete GPU (NVIDIA) on D3D12 backend I get the following windows debug message:

[22904] D3D12 ERROR: ID3D12Device::CreatePlacedResource: A texture resource with either D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET or D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL set cannot be created on a heap with the D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES flag. [ STATE_CREATION ERROR #638: CREATERESOURCEANDHEAP_INVALIDHEAPPROPERTIES]

hordurj commented 1 month ago

This is happening because of different resource tier levels https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_heap_tier?redirectedfrom=MSDN

The current implementation works with Tier 2 but not Tier 1.

The NVIDIA I tested on is a GTX 1050 which is Tier 1 with recent drivers on Windows 11.

in d3d12.zig / MemoryHeap.init the heap Flags are set by .buffer => c.D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,

if the flag is changed to D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES

Then the following error occurs:

[28308] D3D12 ERROR: ID3D12Device::CreateHeap: D3D12_HEAP_FLAGS has invalid flag combinations set. The following flags may not all be set simultaneously. Exactly one must be left unset, or all may be left unset when the adapter supports D3D12_RESOURCE_HEAP_TIER_2 or creating a heap in conjunction with D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER: D3D12_FEATURE_DATA_D3D12_OPTIONS::ResourceHeapTier = D3D12_RESOURCE_HEAP_TIER_1, D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER = 0, D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES = 0, D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES = 0, and D3D12_HEAP_FLAG_DENY_BUFFERS = 0. [ STATE_CREATION ERROR #631: CREATEHEAP_INVALIDMISCFLAGS]

A solution would be to detect which tier is available and then create separate heaps used by textures and other buffers.

hordurj commented 1 month ago

There is code to support Tier 1 and Tier 2. But it is not working properly.

In Tier 1 the heaps need to be separated: (https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_heap_tier)

When allocating resources there is logic that tries to find the right heap to use. All textures were being placed in the Buffers category. When I changed that to .other_texture I got a complaint because in the loadTexture in the Sprite example the texture was also marked as a render target. i.e. D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES is used for the other texture so it can't also be a render target.