285 lines
16 KiB
Markdown
285 lines
16 KiB
Markdown
# STEP20C applied scene / input probe
|
||
|
||
**Status: EXPERIMENTAL / PARTIALLY_FEASIBLE.** The protocol was recorded
|
||
before the private patch and the bounded replay below. STEP20C
|
||
remains **NEXT**; production multi-output Mosaic is **NOT YET SUPPORTED**.
|
||
This protocol authorizes only disposable private instrumentation and fixed
|
||
headless geometry. It changes no production source, clipping policy, UX,
|
||
public ABI, package or installed dependency.
|
||
|
||
## Question and hypotheses
|
||
|
||
Can the scene actually applied at output-state construction be observed
|
||
alongside the scene used by a later real pointer hit test, without inventing
|
||
a native atomic transaction generation? The previous buffer probe identified
|
||
32 committed buffers and headless presents, but its global `bi_hold` released
|
||
IDs 3, 15, 21 and 27 when HEADLESS-2 repainted after HEADLESS-1 commits.
|
||
That private instrumentation defect prevents claiming those four buffers
|
||
were retained until present. The corrective patch is separate from the
|
||
historical fixture.
|
||
|
||
Hypotheses: a per-output hold survives a different output's repaint;
|
||
sampled visible/hidden/returned applied scene and clip agree with selected
|
||
buffer pixels; hit testing sees the sampled applied clip; actual pointer
|
||
delivery may differ from the scene hit because of XDG grab semantics. A
|
||
logical camera target, IPC acceptance, `wlr_scene_node_at()` result and
|
||
headless `present` are different observations.
|
||
|
||
## Ownership and scene audit boundary
|
||
|
||
`wlr_scene_output_build_state()` can install a swapchain buffer in the
|
||
pending output state. The state owns its reference until
|
||
`wlr_output_state_finish()`. A private `wlr_buffer_lock()` taken while that
|
||
state is live owns a separate reference; the matching unlock must occur on
|
||
present, same-output replacement, rejection, timeout or output destruction.
|
||
The lock prevents swapchain slot reuse while held. No event-state or pixel
|
||
pointer may outlive its callback or access scope. Use output identity plus
|
||
native `commit_seq`, not an address alone or predicted sequence. Never give
|
||
a no-buffer commit an earlier buffer fingerprint.
|
||
|
||
Sway's logical `scroll_x` is not itself an applied scene generation.
|
||
`transaction.c` applies current container/output scene positions and
|
||
visibility, including tiled translation; the private Mosaic/SceneFX
|
||
patches set tiled and owner-derived popup clips. XDG map/unmap and popup
|
||
hierarchy changes can mutate scene trees separately. Pending geometry,
|
||
current geometry, applied node position and logical camera are logged as
|
||
distinct fields. SceneFX clip propagation constrains render, damage and
|
||
`wlr_scene_node_at()` in the private build. The experimental epoch, if
|
||
used, advances only at explicitly instrumented mutations; it is **not**
|
||
a native SwayFX transaction generation. Mapping, effects, damage, direct
|
||
SceneFX mutations and uninstrumented upstream paths remain outside any
|
||
partial counter until proven otherwise.
|
||
|
||
`sway/input/cursor.c` calls `node_at_coords()` and scene hit testing for
|
||
pointer paths, while `sway/input/seat.c` relays button notifications to
|
||
wlroots. XDG grabs can filter delivery and issue `popup_done`. Record the
|
||
requested and resulting global coordinate, hit node/surface and current
|
||
applied snapshot at the actual hit call, then separate seat notification
|
||
and client-observed events. Never infer delivery solely from node-at, and
|
||
never assign an input event a fictional frame number.
|
||
|
||
## Private instrument and modes
|
||
|
||
Use a distinct correction patch after the frozen presentation and buffer
|
||
patches. A per-output, single-slot hold is bounded to one selected
|
||
HEADLESS-1 buffer in this matrix. Other-output repaint/present cannot
|
||
evict it. A same-output commit with a *new* buffer may replace it; a
|
||
configuration-only commit cannot. Release is idempotent by clearing the
|
||
slot before unlock. A two-second post-commit timer bounds waiting for an
|
||
absent present, but does not bound a stalled GPU readback. Track lock,
|
||
release, timer and output identity in logs. Paths not safely triggered are
|
||
**NOT TESTED**.
|
||
|
||
Mode 0 records scene, native commit/present and input with no new buffer
|
||
lock/read. Mode 1 reads at most three selected true buffers: visible 400,
|
||
hidden 1280, restored 400. Mode 2 additionally reads those buffers a
|
||
second time only while the owned lock remains live at matching present.
|
||
SceneFX FX texture readback can synchronize GPU/CPU internally. Compare
|
||
stage timings and event counts against mode 0; do not attribute total cost
|
||
solely to `glFinish()`.
|
||
|
||
## Fixed matrix and correlation
|
||
|
||
HEADLESS-1 `(-800,0)` and HEADLESS-2 `(0,0)` are each 800×600, scale 1,
|
||
normal transform. The client hierarchy is TOPLEVEL → POPUP_A → POPUP_B,
|
||
with real pointer-button serials for both grabs. Confirm outputs and
|
||
native commit/present events. Run stable 400 with a real B hit; 1280 with
|
||
the owner fully hidden; return to 400 with the same mapped A/B; then at
|
||
most three hide/return pairs. In distinct runs, click visible B, clipped
|
||
B on HEADLESS-2 and hidden owner; send six close alternating commands;
|
||
compare unmodified SwayFX and private `splith` controls without inventing
|
||
a Mosaic camera for them.
|
||
|
||
Each record uses a monotonic timestamp where available. Preserve
|
||
PRE_BUILD, POST_BUILD, COMMIT_ACCEPTED and PRESENT_CALLBACK applied
|
||
snapshots and the native `(output, commit_seq)` link. Separately preserve
|
||
the applied snapshot at hit test, the wlroots seat notification and the
|
||
client delivery. A matching experimental epoch across observations is
|
||
limited evidence only for mutations covered by its increments; time
|
||
ordering is not an atomic identity. Preserve coalesced commands and
|
||
commits without observed present as such.
|
||
|
||
## Acceptance and stop rules
|
||
|
||
**FEASIBLE** requires same-output buffer lifetime through present in the
|
||
tested paths, observed applied scene at build and hit, actual pointer
|
||
delivery agreement, bounded cleanup and no blocking regression.
|
||
**PARTIALLY_FEASIBLE** covers useful scene/render/input observations with
|
||
incomplete mutation coverage, temporal identity or error-path tests.
|
||
**INCONCLUSIVE** applies when safe observability is unavailable.
|
||
**BLOCKED** requires a reproduced memory violation, crash, visual leak,
|
||
invisible hit or blocking regression. A clean unsupported readback is not
|
||
a compositor defect. Stop on a reproducible crash and retain evidence.
|
||
|
||
Caps: three transition pairs, three selected readback buffers per run,
|
||
one held slot per tested output, 8 MiB per copied buffer, two-second
|
||
post-commit hold timeout, bounded captures/logs and explicit process
|
||
cleanup. No scaling, rotation, migration or hotplug is tested. Even a
|
||
successful fixed headless matrix does not authorize production STEP20C.
|
||
|
||
## Measurements
|
||
|
||
The primary private laboratory is
|
||
`/tmp/swayfx-mosaic-nested-grab-l2HvAkRe/`, rebuilt from the frozen buffer
|
||
fixture. Its corrected output, transaction, cursor and seat sources were
|
||
byte-identical to the independent rebuild in
|
||
`/tmp/swayfx-mosaic-nested-grab-8CiDjoij/`. The corrective patch has
|
||
SHA-256 `8a0766536fa728a6be6ef29aea3be67abbfad107f2fcd6048718097499a4d88f`.
|
||
Only these disposable copies were changed. The final-patch independent
|
||
one-pair run `private_mosaic-buffer_cycles-asi2-1791782683026614149`
|
||
again read three buffers and matched all three native commits and headless
|
||
presents, with three byte-identical second reads and one unlock per hold.
|
||
Its separate visible, clipped and hidden pointer runs repeated the
|
||
client-delivery results. The fixed geometry was confirmed by IPC in the
|
||
run snapshots; each A/B chain used two real pointer-button serials
|
||
(the three-pair run requested A=55 and B=60, each used unchanged). All
|
||
named runs exited without runner or XDG protocol failure.
|
||
|
||
### Buffer ownership and pixels
|
||
|
||
Mode 0 (`private_mosaic-buffer_cycles-asi0-1791781864140604493`) recorded
|
||
95 accepted native commits and 93 headless presents, with no probe lock or
|
||
read. Mode 1 (`...asi1-1791781908846694616`) recorded 87/85 and read three
|
||
selected buffers. Mode 2 (`...asi2-1791781917161051239`) recorded 88/86,
|
||
read those three selected states and read each again at its matching
|
||
present. The two unpaired accepted commits in each run were initial output
|
||
sequence 2, one per output: **UNEXPLAINED / NO PRESENT OBSERVED**.
|
||
|
||
The selected HEADLESS-1 buffers in mode 2 have actual native sequences
|
||
23, 27 and 30, with experimental applied epochs 13, 15 and 17. All three
|
||
are 800×600 GBM XB24 source buffers, read as XRGB8888 with stride 3200 and
|
||
1,920,000 bytes per copy. The SHA-256 sequence is
|
||
`9e6d2f7b094fd5124c0207a30cb294acec3a01da15b90008d7f7449d27e1ee7c`,
|
||
`03e815da50d0f04b16660340db19c1a03225f31bac0824d490c2ffbab0ee165c`,
|
||
then the first hash again. A/B exact-color counts are 42,200/17,940 at
|
||
400, 0/0 at 1280, then 42,200/17,940 after return. Each second read is
|
||
byte-identical. Every selected buffer matched its synchronous commit
|
||
callback, accepted native sequence and `presented=true` headless event;
|
||
each extra lock was released **once**, on that event. No cross-output
|
||
release occurred. A HEADLESS-2 `POST_BUILD` and commit intervened between
|
||
the lock of buffer ID 3 and its matching HEADLESS-1 present; the buffer
|
||
remained locked through that interval. This is the direct positive test
|
||
against the historical scope defect.
|
||
|
||
In one-pair private fault injection
|
||
`private_mosaic-buffer_cycles-asi1-1791781965826777786`, ID 1 was
|
||
intentionally retained after its present and released once when a later
|
||
accepted HEADLESS-1 buffer commit replaced it. The other two selected
|
||
buffers released on present. In separate run
|
||
`private_mosaic-buffer_cycles-asi1-1791781980485708932`, ID 1 released
|
||
once by the two-second timer (logged age 2,000,030,155 ns); the other
|
||
two released on present. The timer and slot were cleaned in both paths.
|
||
The rejected-commit and output-destroy branches compile but were **NOT
|
||
TESTED** by a controlled runtime trigger. A same-output configuration
|
||
commit without a selected new buffer was not a controlled lifetime test;
|
||
the code condition excludes eviction, but runtime qualification is
|
||
**NOT TESTED**.
|
||
|
||
The historical 32-buffer readback used 61.44 MB of first copies; this
|
||
selective run used 5.76 MB, a **90.6% reduction in copied bytes and first
|
||
readback count**. Mode 2 adds 5.76 MB for its three second reads. Sequential
|
||
runs are not a controlled latency benchmark: median HEADLESS-1
|
||
POST_BUILD→COMMIT_ACCEPTED over all frames was 0.083, 0.109 and 0.112 ms
|
||
in modes 0, 1 and 2, while the three selected readback commits alone took
|
||
about 4.255/1.621/1.082 ms in mode 1 and 3.287/1.004/1.025 ms in mode
|
||
2. Host scheduling, renderer work, copies and logs were not separated.
|
||
The readback is therefore still materially intrusive on sampled commits;
|
||
no reliable wall-clock speedup is claimed.
|
||
|
||
### Applied scene and pointer
|
||
|
||
The experimental epoch increments after `arrange_popups()` handles a
|
||
popup and after `transaction_progress()` completes `arrange_root()`.
|
||
It is visible in PRE_BUILD, POST_BUILD and COMMIT_ACCEPTED stage logs,
|
||
and at `node_at_coords()` hits and wlroots seat button notification.
|
||
The final patch also records the root-popup applied clip and logical camera
|
||
at each hit. The visible B hit had logical 400, applied tiled scene -400,
|
||
clip x=400 and a nonempty root-popup clip. With the owner hidden at 1280,
|
||
the root-popup clip was explicitly empty at the hit; the observed surface
|
||
under the pointer was an ordinary surface, not a popup. The clipped
|
||
HEADLESS-2 hit also found the ordinary surface while the root-popup clip
|
||
remained bounded to HEADLESS-1. Nested-popup mapping remains verified in
|
||
the client log, not atomically exported with the hit record.
|
||
The three selected buffers carried applied tiled scene/clip `-400/400`,
|
||
`-1280/1280`, `-400/400`, consistent with their decoded pixels. This is
|
||
an ordered observation, not an atomic frame/scene identity.
|
||
|
||
In the three-pair mode-2 run, the same owner IPC ID 8 and one A/B map
|
||
persisted through all three hide/return pairs. Six further alternating
|
||
IPC camera requests were accepted and returned to 400; they are not
|
||
counted as six presented images. Before the final visible B button, the
|
||
last observed HEADLESS-1 headless present was native sequence 48, whose
|
||
COMMIT_ACCEPTED stage and subsequent scene hit both recorded epoch 37,
|
||
applied scene `-400` and clip x=400. No *instrumented* mutation occurred
|
||
between these observations. Buffer 48 was **not** among the three copied
|
||
buffers, and the partial epoch cannot exclude uninstrumented mutations.
|
||
It does not prove atomic frame-specific input agreement.
|
||
|
||
Separate `run-negative-private_mosaic-{visible,b_cross,hidden_click}`
|
||
controls logged actual requested and obtained global coordinates,
|
||
`wlr_scene_node_at()` result, applied clip, seat notification and client
|
||
events. Visible B received its button. On HEADLESS-2's clipped B portion,
|
||
the hit and seat focus were the ordinary client, whose button was logged;
|
||
B received no button from that point and `popup_done` occurred B then A
|
||
under the XDG grab. With the owner fully hidden at 1280, the hit was an
|
||
ordinary surface under the pointer, no popup button was delivered, and
|
||
`popup_done` again occurred B then A. The private and unmodified `splith`
|
||
controls retained the ordinary crossing B button behavior. A seat's
|
||
focused-surface value is logged before wlroots notification; client logs
|
||
are the separate evidence of actual delivery. No pointer event is
|
||
assigned a native frame ID.
|
||
|
||
The counter does **not** cover every SceneFX node mutation, client buffer
|
||
commit, damage, animation, effect/saved-buffer change, direct XDG scene
|
||
change, output configuration or internal grab decision. It also increments
|
||
for some arrangements that may leave sampled state unchanged. Consequently
|
||
matching epoch values provide only bounded negative evidence about the
|
||
instrumented sites. No visual leak, invisible popup hit, memory-lifetime
|
||
anomaly, crash or blocking standard-layout regression was reproduced in
|
||
the tested matrix. Scaling, rotation, migration, full effects/damage and
|
||
physical presentation remain **NOT TESTED**.
|
||
|
||
**Verdict: PARTIALLY_FEASIBLE.** Per-output reference ownership fixes the
|
||
historical cross-output release in the tested path, and applied scene,
|
||
buffer, native present, scene hit and actual client delivery can be
|
||
observed separately. The partial epoch and intrusive readback cannot yet
|
||
establish a complete temporal scene/render/input generation. The next
|
||
minimal gate is to instrument or formally bound every applied scene and
|
||
hit-affecting mutation, then repeat a low-impact selected-buffer/input
|
||
test against that complete boundary. This is no production decision.
|
||
|
||
## Proof manifests and validation
|
||
|
||
A further fresh, bounded replay in
|
||
`/tmp/swayfx-mosaic-nested-grab-OWIvboDB/` rebuilt private SceneFX and
|
||
Mosaic from the preserved fixture chain. One visible/hidden/returned pair
|
||
produced 65 accepted commits and 63 headless presents in trace-only mode,
|
||
with no buffer lock, then 65/63 in second-read mode. All three selected
|
||
HEADLESS-1 buffers matched native presents, had byte-identical second
|
||
reads, and were unlocked once at their matching present. A HEADLESS-2
|
||
build/commit occurred while the first HEADLESS-1 reference was retained.
|
||
The three states repeated clip x=400/1280/400 and the visible/hidden/
|
||
visible color counts. Fresh visible, clipped and hidden pointer runs
|
||
reproduced the B delivery and XDG dismissal distinction; unmodified and
|
||
private standard `splith` controls delivered the crossing B button.
|
||
This is a targeted replay, not a new matrix qualification.
|
||
|
||
The primary and independent labs retain structured `results-asi/`, raw
|
||
buffers, captures, event logs and source/artifact SHA-256 manifests. The
|
||
rebuild starts from published Mosaic `11c80a40f20240a2ca137d412f6e3b711c5d5f80`,
|
||
inherits private Mosaic `cd550382b311efdbfe3ed892f4e1d281d852e754`
|
||
and SceneFX `37ccd723bef49e6891156ffafce8f549f01446cc` through the
|
||
frozen fixture chain, and uses pinned SwayFX
|
||
`fd71a6bdc061bd633b488ae7b83e8a6981d22f86` with wlroots 0.20.2.
|
||
The five-source manifest in each
|
||
lab has SHA-256
|
||
`0ef45e3e4d7623498d20db8a290ca1dd7bc6cdd6e69a2276e96a01ad1ae475cb`
|
||
and all five source checks pass. The primary lab's 729-artifact manifest
|
||
has SHA-256
|
||
`f7cdefe8d90e2548c927951341b37f8c72b2ad3e64dee53fda6f43438f2b8ef9`;
|
||
the final-patch independent lab's 189-artifact manifest has SHA-256
|
||
`d3f3782538646e37444fde3fd68a7cb494c50dfa190e6df60f176d5ddd1e47ce`.
|
||
All listed available artifacts passed `sha256sum -c`. The older main-lab
|
||
intermediate runs remain in the primary manifest as negative development
|
||
evidence; final-patch reproduction is distinguished by the independent
|
||
lab path and source-equivalence check.
|