Repository navigation
fix(weave/linux): an overlay that cannot be imported refuses the submit (XR_DXR_weave v16) - #1825
Merged
Merged
Conversation
…it (XR_DXR_weave v16)
The desktop-Linux weave engine dropped a chained v4 overlay it could not
import (weave_cache_acquire -> NULL) and wove the frame anyway, returning
success. The D3D11 service refuses such a submit before it clears the
woven output. A caller that hands the whole of its 2D over as the overlay
(the browser's whole-page overlay, browser-pvt#226) reads "accepted with
the overlay chained" as "composited" and presents the woven output as the
complete frame, so the Linux behaviour would show a frame with the page
missing - for example whenever the overlay's DRM modifier does not import
on the service's device.
Both Linux submit paths (stage-A OPAQUE_FD and stage-B dma-buf) now refuse
the submit when the overlay import fails, before the acquire fence is
taken and before anything is recorded, so the woven output is left exactly
as the previous accepted submit left it. One WARN on the first refusal,
then 1 in 300 (the import helper already names the cause once per slot).
XR_DXR_weave SPEC_VERSION 16: no new structure, a gate for the one kind of
desktop-Linux caller that needs it (overlay == its 2D). The macOS and
Android engines still drop an unreadable overlay; their only overlay
callers decorate content they present anyway.
weave_probe_vk_linux --dmabuf gains the case: after the pixel run, a
submit whose overlay fd is a memfd (a valid fd that is no dma-buf) must be
refused, and the woven output read back afterwards must still hold the
last accepted frame's parity. Headless, sim_display only
(DXR_PLUGIN_EXCLUSIVE=sim-display, active plug-in confirmed in the log):
fixed: "unreadable overlay: submit refused (-2); woven output UNTOUCHED"
-> PASS (also with --linear; stage-A probe PASS; fd counts flat)
main: "FAIL: a submit whose overlay cannot be imported was ACCEPTED"
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dfattal
force-pushed
the
fix/linux-weave-refuse-unreadable-overlay
branch
from
October 5, 2026 08:25
2f05e2d to
5f70016
Compare
dfattal
added a commit
that referenced
this pull request
Oct 7, 2026
…g it (XR_DXR_weave v17) (#1837) 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>
dfattal
added a commit
that referenced
this pull request
Oct 7, 2026
…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).
dfattal
added a commit
that referenced
this pull request
Oct 7, 2026
…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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The desktop-Linux weave engine (
comp_multi_weave_linux.c) dropped a chained v4 overlay that it could not import, wove the frame anyway, and returned success. The D3D11 service does the opposite: it refuses a submit whose overlay it cannot open or acquire, before it clears the woven output.From this change, both Linux submit paths do what D3D11 does:
When the overlay import fails, the submit is refused before the acquire fence is taken and before anything is recorded. The woven output is left exactly as the previous accepted submit left it.
XR_DXR_weaveSPEC_VERSION 16. There is no new structure. The version is a gate for one kind of desktop-Linux caller: one whose overlay is its 2D. The macOS and Android engines are unchanged and still drop an unreadable overlay. Their only overlay callers decorate content that they present anyway.Why
The browser's whole-page overlay (browser-pvt#226, now being ported to Linux) hands the runtime the whole flat page as the overlay. It reads "accepted with the overlay chained" as "the page was composited" and presents the woven output as the complete frame. With the old Linux behaviour, one non-importable overlay would put a frame on screen with the page missing. A DRM modifier that does not import on the service's device is enough to cause it.
With v16, the browser holds its last composed frame on a refused submit. After a bounded number of refused frames it paints the page itself. The browser enables Linux page mode only when the runtime reports spec 16 or later.
Tests
Headless, sim_display only. Both the service and the client ran with
DXR_PLUGIN_EXCLUSIVE=sim-display, and the log confirmedactive plug-in: id=sim-display. Each run used a privateXDG_RUNTIME_DIRandXRT_FORCE_MODE=ipc, against a--hybrid --appsbuild.weave_probe_vk_linux --dmabufgains one case after its pixel run:unreadable overlay: submit refused (-2); woven output UNTOUCHED, PASS (also with--linear; the stage-A probe without--dmabufpasses; fd counts stay flat)mainengine (A/B)FAIL: a submit whose overlay cannot be imported was ACCEPTED (the overlay was dropped and the frame woven anyway)Interplay
set_overlay_2dDP slot) touches the same overlay-import area ofcomp_multi_weave_linux.c. The two changes are orthogonal: this one only adds a refusal right afterweave_cache_acquire(... "overlay"). Whichever lands second should rebase cleanly or with a trivial conflict.🤖 Generated with Claude Code