Repository navigation
fix(weave/linux): ignore a stale-size v4 overlay instead of stretching it (XR_DXR_weave v17) - #1837
Conversation
…g it (XR_DXR_weave v17) In a resize race a present-owner keeps handing its old overlay buffer, still the OLD window's size, for a frame or more after the window (input, woven output) changed size. Seen on the DS1 with the browser's whole-page overlay as a black border and black 2D on maximise / unmaximise. The black margin is the runtime's own post-weave blend, not the display processor: the DP offer (set_overlay_2d) is gated on the layer being exactly the output size, so the mismatched layer fell through to the v4 post-weave blend, which drew it over the whole output as if it were window-sized. The stage-A OPAQUE_FD path was worse: it imported the overlay at the window's size whatever the buffer's real size (a smaller allocation failed the import and, since #1825, refused the submit; a larger one was read with the wrong layout). Both submit paths now treat an overlay whose size is not this submit's window size as ABSENT for that frame: no DP offer, no post-weave blend, no off-panel / flat-region redraw, content woven normally. The submit is accepted, not refused (refusing would hold frames through every resize); #1825's refusal of an overlay that cannot be imported is unchanged. One WARN on entering the stale state, one when the overlay matches again. Window size: the input for a batch submit, else the bound geometry (legacy without geometry: rect offset + extent; v6 without geometry: unchecked). Real overlay size: - dma-buf: the descriptor's declared width x height (not imported if stale). - stage A: nothing carries a size (XrWeaveSubmitOverlaysDXR has no extent, an fd has none), so a wire field would have nothing to fill it from. The engine recovers it instead: an inode it already imported IS that import's size (the cache keeps the allocation alive; allocations never change size), and an unseen fd smaller than W x H x 4 bytes cannot be window-sized. An unseen stage-A buffer LARGER than the window remains undetectable (documented). v14: a frame whose overlay was ignored forces layer_unchanged = false on the next overlay offered to the DP, whose cached layer predates the ignored frames. XR_DXR_weave SPEC_VERSION 17, no new structure: it qualifies v16's "accepted with an overlay chained means composited" for a caller whose overlay is its 2D, which needs to know whether a mismatched overlay is dropped (v17) or stretched (older desktop-Linux runtimes). Spec version field in the doc header brought up from a stale 13. weave_probe_vk_linux gains the case in both runs, headless on sim_display (DXR_PLUGIN_EXCLUSIVE=sim-display, active plug-in confirmed in the log, private runtime dir socket): - stage A: never-seen 960x540 overlay under 1280x720 (allocation path), cached 1280x720 overlay under 1600x900 (identity path), each followed by a matching overlay: ignored -> composited, no refusal. PASS. - dma-buf: two frames with a declared 960x540 overlay, then the matching one declared "unchanged": ignored -> composited, no refusal. PASS (also --linear); fd counts flat over 600 frames. - main (negative control): dma-buf step 0 reads opaque green (the stale layer stretched over everything); stage A step 0 is REFUSED. FAIL. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Cross-session review (browser-linux): no blocking findings. Treating a size-mismatched overlay as absent for the frame (no DP offer, no post-weave blend, submit still accepted, one WARN per transition) is the right contract — it is exactly the failure the first Linux browser panel run hit (an overlay staged at the pre-resize size blended as if window-sized → black margin; see browser-pvt#238's panel-run-1 notes). The v14 reset after an ignored run is correct: the DP's cached layer predates it. The handle-path inference (first-import size kept exact; smaller allocation caught; larger undetectable) is acceptable since the browser uses dma-buf only, and the spec says so. Spec v17 bump is warranted. From the browser side: the Linux page mode in #238 already validates the overlay against the frame's window size in Viz and in the provider before sending, so it never relies on this drop; I will gate nothing on v17 but will document that an older runtime stretches a mismatched overlay. |
…refuses (XR_DXR_weave v18) Two gaps in the Android weave engine's v4 overlay handling, found while porting the browser's whole-page overlay (browser-pvt#226) to Android: 1. A cached overlay was a STANDING overlay. The engine caches the overlay import by AHardwareBuffer identity (the caller re-sends the same buffer every frame), and composited mc->weave.overlay_image whenever it was set - so after one submit that chained an overlay, every later submit was composited with it, chained or not. The browser's whole-page overlay switches itself off while the page scrolls (its 0351 safety floor); on those frames the last page it sent would be composited over a page that has moved. The import is still cached (no re-import for the same buffer), but the overlay is now composited only on a submit that chains one (mc->weave.overlay_this_submit). 2. An overlay that could not be imported was DROPPED and the frame woven anyway, returning success. A caller that hands its whole 2D over as the overlay reads "accepted with the overlay chained" as "composited" and presents the woven output as the complete frame. The submit is now refused (XRT_ERROR_WEAVE_REFUSED -> XR_ERROR_RUNTIME_FAILURE) before anything is recorded, so the woven output is left exactly as the previous accepted submit left it: the desktop-Linux v16 rule (#1825) and the D3D11 service's. One WARN on the first refusal, then 1 in 300. XR_DXR_weave SPEC_VERSION 18: no new structure, the Android gate for the one kind of caller that needs it (overlay == its 2D), exactly as v16 is on desktop Linux. The macOS engine still drops an unreadable overlay. Callers whose overlay decorates content they present anyway (0099's over-plane mode) see no difference except on a frame that chains no overlay, which no longer shows the previous frame's. Not tested on hardware: the NP02J is off the bus right now. Compiled by CI (build-android). The branch feat/android-overlay-2d-dp (DP-side overlay offer) touches the same block; its offer must also require overlay_this_submit once both land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Renumbered v17 -> v18 on rebase: main took v17 for the desktop-Linux stale-size overlay rule (#1837).
…refuses (XR_DXR_weave v18) (#1835) Two gaps in the Android weave engine's v4 overlay handling, found while porting the browser's whole-page overlay (browser-pvt#226) to Android: 1. A cached overlay was a STANDING overlay. The engine caches the overlay import by AHardwareBuffer identity (the caller re-sends the same buffer every frame), and composited mc->weave.overlay_image whenever it was set - so after one submit that chained an overlay, every later submit was composited with it, chained or not. The browser's whole-page overlay switches itself off while the page scrolls (its 0351 safety floor); on those frames the last page it sent would be composited over a page that has moved. The import is still cached (no re-import for the same buffer), but the overlay is now composited only on a submit that chains one (mc->weave.overlay_this_submit). 2. An overlay that could not be imported was DROPPED and the frame woven anyway, returning success. A caller that hands its whole 2D over as the overlay reads "accepted with the overlay chained" as "composited" and presents the woven output as the complete frame. The submit is now refused (XRT_ERROR_WEAVE_REFUSED -> XR_ERROR_RUNTIME_FAILURE) before anything is recorded, so the woven output is left exactly as the previous accepted submit left it: the desktop-Linux v16 rule (#1825) and the D3D11 service's. One WARN on the first refusal, then 1 in 300. XR_DXR_weave SPEC_VERSION 18: no new structure, the Android gate for the one kind of caller that needs it (overlay == its 2D), exactly as v16 is on desktop Linux. The macOS engine still drops an unreadable overlay. Callers whose overlay decorates content they present anyway (0099's over-plane mode) see no difference except on a frame that chains no overlay, which no longer shows the previous frame's. Not tested on hardware: the NP02J is off the bus right now. Compiled by CI (build-android). The branch feat/android-overlay-2d-dp (DP-side overlay offer) touches the same block; its offer must also require overlay_this_submit once both land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Renumbered v17 -> v18 on rebase: main took v17 for the desktop-Linux stale-size overlay rule (#1837).
Problem
During a resize, a present-owner keeps sending its old overlay buffer for a frame or more after the window has changed size. That buffer is still the old window's size, while the input and the woven output already have the new size. On the DS1, the browser's whole-page v4 overlay showed a black border and black 2D content on maximise and unmaximise.
Where the black margin comes from: the runtime's own post-weave blend, not the display processor. The DP offer (
set_overlay_2d) only takes a layer that is exactly the output size. A mismatched layer is never offered to the DP. It falls through to the runtime'sv4 overlay atlaspost-weave blend (vk_local2d_composite_flatten_draw), which draws the smaller layer over the whole output as if it were window-sized.The stage-A
OPAQUE_FDpath had a worse version of the problem. It imported the overlay at the window's size (have_geometry ? win_w : in_w) whatever the buffer's real size was:Fix (
comp_multi_weave_linux.c)layer_unchanged = false, because the DP's cached layer is older than the ignored frames. The DP contract is already stateless per frame (noset_overlay_2dcall means no layer), so an ignored frame never composites the cached layer.What the handle path (stage A) carries
No size at all.
XrWeaveSubmitOverlaysDXRhas no extent field and an fd carries no dimensions. Adding a field toipc_arg_weave_submitwould not help, because the app-facing stage-A call has nothing to fill it from. So the wire is unchanged, andtests_ipc_protoand the IPC size accounting are untouched. The engine recovers the size another way:W×H×4bytes cannot hold a window-sized BGRA8 image in any tiling.The dma-buf path compares the descriptor's declared
width × heightand does not import a mismatched overlay at all.Spec:
XR_DXR_weavev17 (no new structure)v16 told a caller whose overlay is its whole 2D that "accepted with an overlay chained" means "composited", and such a caller gates on that. v17 qualifies the guarantee: it holds only for a window-sized overlay. A mismatched overlay is now dropped (woven without it, still accepted). Older desktop-Linux runtimes stretch it instead. Callers need to tell those two behaviours apart, so this is a version bump rather than a silent change. The update is in the spec doc (§5d and the version history) and the header comment. The doc header's
Spec Versionfield was stale at 13 and is now 17. The macOS, Android and D3D11 engines are unchanged.Test
weave_probe_vk_linuxnow runs the resize-race case in both runs. Everything was headless on sim_display:DXR_PLUGIN_EXCLUSIVE=sim-display(active plug-in confirmed in the service log), with a private runtime-dir socket. The DS1 panel and the installeddisplayxr.socketwere not used.The stale overlay is opaque green everywhere, so any composite of it shows up at every probe point.
--linear.ctest -R "ipc|weave": 6/6 pass.🤖 Generated with Claude Code