Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Documents/Build-PORTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,36 @@ uniforms at `b0, space1`, fragment textures/samplers at `t#/s#, space2`, fragmen
at `b0, space3`. Getting one wrong fails pipeline creation the same opaque way, because the
root signature SDL builds will not cover the shader's bindings.

### Anisotropic sampling forces linear min/mag/mip

Same shape of trap, one layer down. Vulkan and Metal carry the three filters and anisotropy
as independent fields; D3D12 packs them into one `D3D12_FILTER` enum, and anisotropy is a bit
set on top of an all-linear encoding. `SDLToD3D12_Filter` builds it arithmetically, so

```c
enable_anisotropy = true; mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
```

encodes `MIN_MAG_LINEAR_MIP_POINT (0x14) | ANISOTROPIC (0x40)` = `0x54`, **which is not a
member of `D3D12_FILTER`**. Only `0x55` (`D3D12_FILTER_ANISOTROPIC`) and `0xd5` (its
comparison form) are legal. So: if `enable_anisotropy` is set, all three of `min_filter`,
`mag_filter` and `mipmap_mode` must be linear.

Getting it wrong is not a returned error. `CreateSampler` returns `void`, so the runtime
answers an unrecognised filter by **removing the device** — after which every texture and
pipeline fails with `DXGI_ERROR_INVALID_CALL` and nothing points back at the sampler:

```
D3D12 ERROR: ID3D12Device::CreateSampler: Filter unrecognized. [ STATE_CREATION ERROR #742 ]
D3D12: Removing Device.
D3D12 ERROR: ID3D12Device::RemoveDevice: ... [ EXECUTION ERROR #232: DEVICE_REMOVAL_PROCESS_AT_FAULT ]
```

Watch for a `SDL_GPUSamplerCreateInfo` **reused** between samplers: that is how the water
renderer got one, by switching `mipmap_mode` for a second sampler while `enable_anisotropy`
stayed set from the first. Windows 11 hid it — its newer `D3D12Core.dll` sanitises the bit
pattern where Windows 10's treats it as an illegal call.

## One source list per module

Every module's `CMakeLists.txt` used to have a `WIN32` branch feeding it a different set of
Expand Down
12 changes: 11 additions & 1 deletion Render/SDLWaterRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,17 @@ void SDLWaterRenderer::createPipelines()
si.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
si.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
si.max_lod = 0.f; // the render target has no mip chain
si.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
// mipmap_mode stays LINEAR, and must: si still carries enable_anisotropy from the
// sampler above, and D3D12 encodes anisotropy as a bit on top of the min/mag/mip
// filter -- MIN_MAG_LINEAR_MIP_POINT | ANISOTROPIC is 0x54, which is not a member of
// D3D12_FILTER. CreateSampler cannot fail by return code, so the runtime answers an
// unrecognised filter by REMOVING THE DEVICE, and every texture and pipeline after it
// fails with DXGI_ERROR_INVALID_CALL -- including the font atlas, which is where it
// finally surfaced, as a null FT::Font several subsystems away.
// Vulkan and Metal carry the filters and anisotropy as independent fields, so the same
// call is legal there and this only ever reached Windows.
// Nothing is lost: with one mip level there is nothing for POINT and LINEAR to differ
// over, and max_lod above already pins sampling to it.
samplerClamp_ = SDL_CreateGPUSampler(device_, &si);

// 1x1 flat wave map: the decoder's bias, so water.frag.hlsl's slope() reads 0.
Expand Down
Loading