Skip to content

fix(d3d11): allocate the per-eye bridge as TYPELESS so Linear projects present - #327

Merged
dfattal merged 1 commit into
DisplayXR:mainfrom
byungjul:fix/d3d11-linear-srgb-eye-textures
Sep 15, 2026
Merged

dfattal merged 1 commit into
DisplayXR:mainfrom
byungjul:fix/d3d11-linear-srgb-eye-textures

Conversation

@byungjul

Copy link
Copy Markdown
Contributor

Fixes #326.

A Linear project takes the sRGB swapchain path on present (dxr_prov_set_color_space_linear -> want_srgb), and the D3D11 zero-copy MultiPass path then allocated its per-eye bridge textures with that same concrete format, R8G8B8A8_UNORM_SRGB.

The runtime hands its swapchain images back as R8G8B8A8_TYPELESS, so submit ended up doing CopySubresourceRegion from an _UNORM_SRGB source into a TYPELESS destination. That faults inside the NVIDIA D3D11 UMD:

nvwgf2umx!SetDependencyInfo+0x62031        <- cmp byte ptr [rax+34h],3, rax=0
nvwgf2umx!OpenAdapter10+0x2bc56
d3d11!CResource<ID3D11Resource>::CopySubresourceRegion<0,0>+0x486
d3d11!CContext::TID3D11DeviceContext_CopySubresourceRegion_<2>+0x1e3
displayxr_unity!...                        <- submit_frame, per-eye slice copy
UnityPlayer!UnityMain+0x9f57e2

and the frames before it goes down show a black panel, because the eye content never reaches the swapchain image.

Gamma projects were unaffected — their bridge is _UNORM, which copies into the TYPELESS image fine. D3D12 was unaffected too: it uses the own-device shared bridge rather than this same-device copy. Dumping both ends of the copy makes the difference a single field:

dst src
Linear (crashes) fmt=27 TYPELESS fmt=29 UNORM_SRGB
Gamma (fine) fmt=27 TYPELESS fmt=28 UNORM

Change

Allocate the per-eye bridge as the TYPELESS parent of the swapchain format instead of the concrete format. It is the same format family, so the copy is trivially legal, and TYPELESS is also what D3D11 requires of a resource that has to carry an sRGB render-target view — which is exactly what Unity builds for an eye texture declared with kUnityXRRenderTextureFlagsSRGB. Gamma keeps working unchanged because 28 and 29 share that TYPELESS parent.

Scoped to the eye targets: ps_sc_dxgi_format() is untouched, so the swapchain itself, wsui, Local2D and the zone layers keep the concrete formats they have always used. The new typeless parameter on ps_alloc_unity_tex() defaults to 0, so every existing call site is unchanged.

Verification

Windows 11, Unity 6000.3.14f1, BiRP + MultiPass, RTX 4090 Laptop (driver 32.0.15.8180), Leia SR display (ACR0001), built player. Each config was run through the 2D home screen and into a 3D scene, i.e. across the 1-view -> 2-view layout renegotiation:

Config Before After
Linear + D3D11 black panel, then crash renders, correct brightness, no crash
Gamma + D3D11 fine unchanged
Linear + D3D12 fine unchanged

After the fix, WITNESS reports a steady presents/s=60.0 weaves/s=60.0 mode=3d with no crash dumps. Correct brightness on Linear also confirms Unity does build the sRGB RTV over the TYPELESS resource, which is the assumption the change rests on.

Notes

  • The editor path (ps_alloc_shared_tex_d3d11, own-device NT-handle bridge) is left alone. It may have the same exposure, but I could not verify whether a shared NT-handle texture accepts a TYPELESS format here, so I did not want to change it blind.
  • The prebuilt Runtime/Plugins/Windows/x64/displayxr_unity.dll is deliberately not included, since binaries look like they are refreshed in release commits.

…s present

A Linear project asks for an sRGB swapchain on the present path
(dxr_prov_set_color_space_linear -> want_srgb), and the D3D11 zero-copy
MultiPass path then allocated its per-eye bridge textures with that same
concrete format — DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.

The runtime hands its swapchain images back as R8G8B8A8_TYPELESS, so submit
ended up calling CopySubresourceRegion with an _UNORM_SRGB source against a
TYPELESS destination. That faults inside the NVIDIA D3D11 UMD
(nvwgf2umx!SetDependencyInfo, null dereference under
d3d11!CContext::TID3D11DeviceContext_CopySubresourceRegion_), taking the
player down, and the frames before it goes show a black panel because the
eye content never reaches the swapchain. Gamma projects were unaffected:
their bridge is _UNORM, which copies into the TYPELESS image fine. D3D12 was
unaffected too — it uses the own-device shared bridge, not this copy.

Allocate the per-eye bridge as the TYPELESS parent of the swapchain format
instead. It is the same format family, so the copy is trivially legal, and
TYPELESS is also what D3D11 requires of a resource that has to carry an sRGB
render-target view — which is exactly what Unity builds for an eye texture
declared with kUnityXRRenderTextureFlagsSRGB. Gamma keeps working unchanged
because 28 and 29 share that TYPELESS parent.

Scoped to the eye targets: ps_sc_dxgi_format() is untouched, so the
swapchain itself, wsui, Local2D and the zone layers keep the concrete
formats they have always used.

Verified on Windows 11, Unity 6000.3.14f1, BiRP + MultiPass, RTX 4090 Laptop
(driver 32.0.15.8180), Leia SR display, built player:
  - Linear + D3D11: 3D scene renders, correct brightness, no crash (was a
    black screen followed by a crash on the 1-view -> 2-view transition)
  - Gamma  + D3D11: unchanged from before the patch
  - Linear + D3D12: unchanged from before the patch

Signed-off-by: byungjul <byungju.lee@leiainc.com>
@byungjul
byungjul requested a review from dfattal as a code owner September 15, 2026 07:54
@dfattal
dfattal merged commit e3cd83f into DisplayXR:main Sep 15, 2026
8 checks passed
dfattal added a commit that referenced this pull request Sep 15, 2026
…dge (#326)

Rebuilt from e3cd83f (PR #327), which landed source-only. MSVC 2022, Release.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

D3D11 + Linear color space: black panel and NVIDIA UMD crash in the per-eye submit copy

2 participants