Runtime-side counterpart: DisplayXR/displayxr-runtime#1134 (full evidence chain there).
What the runtime observes
On a hybrid box (render = NVIDIA dGPU, scanout = Intel iGPU), when the runtime's output-device
split (DXR_WEAVE_ON_SCANOUT=1) puts the weave on the scanout adapter, and no face is
tracked, leia_dp_d3d11_process_atlas writes a fully (0,0,0,0) transparent-black output for
~22 consecutive frames every ~1983 ms — ~366 ms of black every 2 s.
On the render adapter (split off) the same untracked state is rendered correctly, every frame.
So this is adapter-dependent, not a general untracked-path defect.
What the runtime can rule out
The runtime instrumented the call site (DXR_SPLIT_COVER_DIAG, DisplayXR/displayxr-runtime@d627a9edb)
and can state the following about the frames that come out black:
- The DP covers the target. The compositor clears the back buffer to magenta immediately before
process_atlas; on the black frames not one of five sampled points is still magenta. The DP is
not returning early — it draws, and what it draws is (0,0,0,0).
- The atlas handed in is correct, on the correct device. Dumped and inspected on a black frame:
a clean 1280x360 2x1 stereo atlas, opaque, dark-navy background, cube present in both tiles.
- Every parameter is invariant across the good/black boundary. Same
tile_columns/tile_rows
(2x1), same view dims (640x360), same output dims, same atlas encoding, same transparency mode
(client_presents=false, opaque), same context and device.
set_frame_timing is not implicated: measured R = 15.8 ms on the black frames and on the
good ones alike, i.e. the split does not inflate the prediction horizon here.
- Predicted eyes are constant:
get_predicted_eye_positions returns valid=1 count=2 with the
pair fully collapsed, L = R = (0.000, 0.100, 0.600) — the plug-in's own untracked signature
(is_tracking = (dx²+dy²+dz²) > 1e-6 → false) — and it does not move across the boundary.
So nothing the runtime supplies changes at that ~2 s period. The cycle is internal DP / SR SDK
state.
Discriminating hint
Because the inputs are invariant, the ~2 s cycle has to be driven from inside. Two suspicions,
neither verified:
-
The untracked pulse / "seeking viewer" animation's own render pass silently failing on Intel
— a shader, blend, viewport or state assumption that holds on NVIDIA and not on the iGPU. An
output of exactly (0,0,0,0) rather than garbage smells like a pass that ran and wrote nothing
but transparent, or a clear that was not followed by its draw.
-
An adapter-dependent resource in the untracked path. Worth checking that everything the
untracked branch touches is created on the device that is actually weaving. Two asymmetries were
noticed while reading (both fine when the runtime passes a matching pair, but worth confirming
under this configuration):
- the SR weaver renders on the create-time cached
sr->d3d11_context
(leia_sr_d3d11.cpp CreateDX11Weaver / srCreateWeaverDX11), while the DP's own passes use
the per-call context; leiasr_d3d11_weave takes no context parameter at all;
- every lazily-created D3D11 resource uses
ldp->device cached at factory time
(leia_display_processor_d3d11.cpp), never ctx->GetDevice().
The runtime does pass a matching device/context pair here (the DP is created with the split's
out device and process_atlas is called with the same out context), so neither is wrong in
this configuration — but both mean "which adapter" is decided once at create time, which is the
shape of bug that shows up only on the second adapter.
Also noticed while reading, unrelated to this bug but against the repo's own invariant:
w_weave() (leia_sr_d3d11.cpp) calls the v1 weaver->weave() with no try/catch, on the
per-frame path, into a C caller that cannot catch. Same omission in the D3D12 arm.
Repro
Any scanout-split session, no face in front of the camera, ~2 s period:
set DXR_WEAVE_ON_SCANOUT=1
test_apps\build\bin\cube_handle_d3d11_win.exe REM in-process
REM or, for the service path: start the service with the same var, then
REM set XRT_FORCE_MODE=ipc and launch the same exe
Confirm weave placement: ... weave/present on the SCANOUT adapter in the log, then step out of
the camera's view for ~30 s.
Needs a hybrid render/scanout box; on the reference machine the panel is driven by the Intel UHD
while rendering happens on the RTX 3080.
The runtime can help
DXR_SPLIT_COVER_DIAG=2 (service direct path) reports, per tick, whether the DP covered the target,
whether its input was black, whether its output was black, the predicted eyes, the measured R, and
burst edges with wall-clock deltas. DXR_WEAVE_PROBE=1 plus a %TEMP%\dxr_woven_trigger file dumps
the in-process back buffer exactly as the DP left it. Happy to add whatever else would narrow this
from the runtime side — including dumping the DP input and output on the same frame, which is
already wired.
Runtime-side counterpart: DisplayXR/displayxr-runtime#1134 (full evidence chain there).
What the runtime observes
On a hybrid box (render = NVIDIA dGPU, scanout = Intel iGPU), when the runtime's output-device
split (
DXR_WEAVE_ON_SCANOUT=1) puts the weave on the scanout adapter, and no face istracked,
leia_dp_d3d11_process_atlaswrites a fully(0,0,0,0)transparent-black output for~22 consecutive frames every ~1983 ms — ~366 ms of black every 2 s.
On the render adapter (split off) the same untracked state is rendered correctly, every frame.
So this is adapter-dependent, not a general untracked-path defect.
What the runtime can rule out
The runtime instrumented the call site (
DXR_SPLIT_COVER_DIAG, DisplayXR/displayxr-runtime@d627a9edb)and can state the following about the frames that come out black:
process_atlas; on the black frames not one of five sampled points is still magenta. The DP isnot returning early — it draws, and what it draws is
(0,0,0,0).a clean 1280x360 2x1 stereo atlas, opaque, dark-navy background, cube present in both tiles.
tile_columns/tile_rows(2x1), same view dims (640x360), same output dims, same atlas encoding, same transparency mode
(
client_presents=false, opaque), same context and device.set_frame_timingis not implicated: measuredR = 15.8 mson the black frames and on thegood ones alike, i.e. the split does not inflate the prediction horizon here.
get_predicted_eye_positionsreturnsvalid=1 count=2with thepair fully collapsed,
L = R = (0.000, 0.100, 0.600)— the plug-in's own untracked signature(
is_tracking = (dx²+dy²+dz²) > 1e-6→ false) — and it does not move across the boundary.So nothing the runtime supplies changes at that ~2 s period. The cycle is internal DP / SR SDK
state.
Discriminating hint
Because the inputs are invariant, the ~2 s cycle has to be driven from inside. Two suspicions,
neither verified:
The untracked pulse / "seeking viewer" animation's own render pass silently failing on Intel
— a shader, blend, viewport or state assumption that holds on NVIDIA and not on the iGPU. An
output of exactly
(0,0,0,0)rather than garbage smells like a pass that ran and wrote nothingbut transparent, or a clear that was not followed by its draw.
An adapter-dependent resource in the untracked path. Worth checking that everything the
untracked branch touches is created on the device that is actually weaving. Two asymmetries were
noticed while reading (both fine when the runtime passes a matching pair, but worth confirming
under this configuration):
sr->d3d11_context(
leia_sr_d3d11.cppCreateDX11Weaver/srCreateWeaverDX11), while the DP's own passes usethe per-call context;
leiasr_d3d11_weavetakes no context parameter at all;ldp->devicecached at factory time(
leia_display_processor_d3d11.cpp), neverctx->GetDevice().The runtime does pass a matching device/context pair here (the DP is created with the split's
out device and
process_atlasis called with the same out context), so neither is wrong inthis configuration — but both mean "which adapter" is decided once at create time, which is the
shape of bug that shows up only on the second adapter.
Also noticed while reading, unrelated to this bug but against the repo's own invariant:
w_weave()(leia_sr_d3d11.cpp) calls the v1weaver->weave()with no try/catch, on theper-frame path, into a C caller that cannot catch. Same omission in the D3D12 arm.
Repro
Any scanout-split session, no face in front of the camera, ~2 s period:
Confirm
weave placement: ... weave/present on the SCANOUT adapterin the log, then step out ofthe camera's view for ~30 s.
Needs a hybrid render/scanout box; on the reference machine the panel is driven by the Intel UHD
while rendering happens on the RTX 3080.
The runtime can help
DXR_SPLIT_COVER_DIAG=2(service direct path) reports, per tick, whether the DP covered the target,whether its input was black, whether its output was black, the predicted eyes, the measured
R, andburst edges with wall-clock deltas.
DXR_WEAVE_PROBE=1plus a%TEMP%\dxr_woven_triggerfile dumpsthe in-process back buffer exactly as the DP left it. Happy to add whatever else would narrow this
from the runtime side — including dumping the DP input and output on the same frame, which is
already wired.