Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ jobs:
- uses: actions/checkout@v4
- run: python3 scripts/generate-design-tokens.py --check
- run: python3 scripts/generate-app-icons.py --check
- name: Check domain and framework dependency boundaries
run: python3 -B -I -m unittest discover -s tests -p test_architecture.py -v
- name: Check capture dependency and pixel integrity
run: python3 -B -I -m unittest discover -s tests -p test_component_lab.py -v
- run: python3 scripts/check-component-lab.py
- run: python3 -m unittest discover -s tests -v
- run: shellcheck scripts/*.sh configs/lucid/*.sh
Expand Down Expand Up @@ -82,6 +86,43 @@ jobs:
- run: cargo fmt --manifest-path lucent/Cargo.toml --all --check
- run: cargo clippy --manifest-path lucent/Cargo.toml --locked --workspace --all-targets -- -D warnings
- run: cargo test --manifest-path lucent/Cargo.toml --locked --workspace
- name: Capture compiled release-gate package and test-name inventories
id: compiled-inventory
run: |
task_inventory="$RUNNER_TEMP/lucent-compiled-inventory"
mkdir -m 700 "$task_inventory"
git rev-parse HEAD > "$task_inventory/source-commit.txt"
cargo metadata --manifest-path lucent/Cargo.toml --offline --locked --no-deps --format-version 1 > "$task_inventory/packages.json"
# --list executes no tests or native fixtures. Keep each harness's
# stdout separate: workspace stdout/stderr can interleave summaries.
inventory() {
task_id="$1"
shift
cargo test --manifest-path lucent/Cargo.toml --offline --locked "$@" -- --list > "$task_inventory/$task_id-all.txt"
cargo test --manifest-path lucent/Cargo.toml --offline --locked "$@" -- --list --ignored > "$task_inventory/$task_id-ignored.txt"
}
inventory lucent-domain-tests -p lucent-domain --lib
inventory lucent-api-tests -p lucent-api --lib
inventory lucent-ui-tests -p lucent-ui --lib
inventory lucent-wayland-tests -p lucent-wayland --lib
inventory desktop-tests -p lucent-desktop --bin lucent-desktop
inventory video-tests -p lucent-services --lib 'video::'
inventory application-adapter-tests -p lucent-services --lib 'applications::'
inventory upload-tests -p lucent-render --lib 'stream_upload::tests::'
inventory desktop-bar-pixels-tests -p lucent-desktop --bin lucent-desktop bar_handoff_carriers_keep_identical_pixels
inventory allocation-tests -p lucent-render --lib 'allocation::tests::'
inventory video-allocation-example-tests -p lucent-services --example video-allocation-observer
inventory video-frame-tests -p lucent-video-frame --lib
inventory video-plane-vulkan-tests -p lucent-render --lib 'video_planes::tests::video_planes_gpu_'
inventory video-scene-vulkan-tests -p lucent-render --lib 'video_scene::tests::video_scene_gpu_'
inventory native-video-example-tests -p native-video-planes --bin native-video-planes
inventory component-lab-tests -p lucent-lab --lib
- name: Retain compiled inventories separately from execution evidence
uses: actions/upload-artifact@v4
with:
name: compiled-test-inventory
path: ${{ runner.temp }}/lucent-compiled-inventory
if-no-files-found: error
- run: dbus-run-session -- cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-services notification_ -- --ignored
- run: cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-services audio_protocol -- --ignored
- run: cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-services bluetooth_protocol -- --ignored
Expand All @@ -92,6 +133,8 @@ jobs:
run: |
export VK_DRIVER_FILES="$(find /usr/share/vulkan/icd.d -name '*lvp*' -print -quit)"
test -n "$VK_DRIVER_FILES"
cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-render video_planes_gpu_ -- --ignored --nocapture --test-threads=1
cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-render video_scene_gpu_ -- --ignored --nocapture --test-threads=1
cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-render frozen_stream_snapshot_keeps_pixels -- --ignored --nocapture
cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-render trace_reports_final_bound_alias -- --ignored --nocapture
cargo test --manifest-path lucent/Cargo.toml --locked -p lucent-render international_style_masks -- --ignored --nocapture
Expand Down
80 changes: 80 additions & 0 deletions docs/native-video-planes.md

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions docs/wallpaper-retargeting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Same-asset playback retargeting

This is a separate library capability and an independent observer prototype.
The desktop still uses the existing static `WallpaperPlaybackPort::play` API.
This full-demand source extension has not been compiled or measured; it makes
no memory, cadence or improvement claim. Its authored tests and formatting/parser
checks are separate from the parent 0bec hosted-CI result and earlier observer
measurements.

`RetargetablePlaybackOptions` contains only frame-rate and looping policy.
`WallpaperTargetPort` supplies the sole physical target as a
`WallpaperTargetDemand`: an optional checked `WallpaperPixelTarget` and a nonzero
`WallpaperTargetRevision`. These are transient domain values, independent of
monitor selection, saved preferences, Wayland and rendering.

## Source-size demand and observation absence

The inner `WallpaperTargetDemand.target` follows `PlaybackOptions.target`:
`None` requests source/native-size pixels, and `Some(checked_target)` requests
the existing physical-cover conversion. An admitted
`Some(WallpaperTargetDemand { target: None, .. })` is a complete source-size
snapshot. It is different from `WallpaperTargetPort::try_latest() == Ok(None)`,
which means no snapshot was available because of temporary contention. Initial
outer absence still fails admission; later outer absence keeps the previous
demand. It never changes a fitted target to source size or cancels playback.

The pure `WallpaperTargetDemand::retarget` transition preserves a revision for
equal source-size or fitted demand, advances exactly once for either changed
direction, and fails without mutation at revision exhaustion. The latest-target
adapter performs compare-and-set under its own lock and delegates that policy
to the domain value. Both source-size and fitted snapshots retain their last
admitted value when a port refresh reports an error.

Source → fitted → source and fitted → source → fitted transitions use the same
admitted decoder/input/timing owner. Conversion receives the optional demand
directly, so source size restores the existing native-size conversion rather
than substituting a small or focused-display target. Only actual converted
extent changes replace conversion scratch and the bounded publication pool.
Alpha-capable/paletted formats retain native pixels in every mode; their demand
revision still changes when the intent changes.

Authored tests compare every decoded frame, timestamp and source aspect against
static references in both transition directions, including reordered EOF frames,
rewind and callback cancellation. Additional tests cover contention versus source
admission, CAS/no-op/exhaustion, alpha pixels, retired pool ownership and a consumer
retaining last-good pixels while rejecting stale frames and preserving terminal
failure. These tests require hosted execution before being reported as passing.

The observer CLI still runs its existing FHD → 4K → FHD sequence; this extension
does not add a source-size native measurement or rewrite any frozen comparison
runner/receipt. The full source/target semantics must be included in a separately
bound native comparison before production integration. Startup unknown → FHD can
affect retained allocations and is not excluded from the final resource objective.
The desktop is unchanged. Its integration must keep producer generation, target
revision and streamed-image revision separate, preserve last-good/error visibility,
and await terminal `Ended` ownership before claiming non-overlapping replacement
workers. No UI-thread join or memory improvement is established here.

`LatestWallpaperTargetAdapter` implements that port in services. A control
writer calls `set(expected_revision, target)`. A stale expected revision fails;
the same target with the current revision is a no-op. Changed demand increments
with `checked_next`, which fails before mutation at exhaustion. The adapter
stores one latest value, not a command queue. Decoder reads use `try_lock` and
return `None` during contention. Initial `None` is an explicit unavailable
error before decoder admission; later `None` keeps the last admitted demand.
Regressing snapshots and equal-revision/different-target snapshots fail.

`play_retargetable` is an additional port method. Unsupported adapters report an
explicit unavailable capability error; they never call static play as a hidden
restart fallback. `NativeVideoWallpapers` validates the same owned asset as
static play and consumes target snapshots during its existing decode work.
There is no new control-polling thread or timer worker.

Within a playback cycle, target changes keep the admitted input, decoder,
decoder threads, source shape, presentation timeline, source clock and I/O
deadline owner. Only a change in actual converted pixel extents retires the
converter and its bounded publication pool. The old pool drops before the new
one allocates; already published immutable pixel owners remain valid. Alpha,
palette and unknown-alpha formats keep the existing source-size fallback;
their changed target revision is still attached even when no converter resize
is needed. Source aspect, timestamps, straight alpha, row validation and
filtering policy are unchanged.

Every published `TargetedMediaFrame` carries the revision captured before
conversion. A new demand can arrive during conversion. The consumer must compare
the result to its current intent and discard stale results; it must never
relabel old pixels with a newer revision. Converter lifetime no longer decides
whether a decoded frame is the first source prefix: source admission separately
tracks dimensions/format and the first decoded PTS. Retargeting therefore cannot
reclassify a later missing timestamp as an unseekable initial prefix.

EOF behavior remains the existing source policy: fully drain reordered frames,
hold the final source duration, and reuse an eligible live H.264 session through
the bounded seek/flush path. Unsupported or failed EOF seeks retain the existing
reopen path. Target updates themselves do not reopen. One port call does not
claim that every codec/EOF condition retained a single native context.

## Independent comparison

The services `video-allocation-observer` accepts optional private JSON
`"retarget": true`. The default remains the measured three-reopen sequence.
The retarget mode makes one play call on one worker for FHD → 4K → FHD. The
coordinator updates only the target adapter and rejects stale revision results.
It keeps one latest allocation across phase boundaries until a valid
replacement arrives, then cancels, joins and drops the final latest once.
An unsupported, failed, early-returning or unjoined producer never authorizes
another playback worker. No phase output is emitted until cleanup completes.

Each target has a bounded five-second readiness wait and three process-memory
points, with no allocator query while playback is alive. The observation period
starts after the first matching target frame is observed. These phase clocks
include different startup/readiness work from the old reopen mode, so
publication counts or elapsed-time differences are not FPS or a speedup.
Per-target RSS includes the live decoder and held latest frame. Those points
must not be compared directly with the old after-join/after-drop measurements.

With `allocator_stats` enabled, the whole retarget run has three allocator
observations: before the worker, after its exact join with the latest held,
and after that latest drops. Only the final stopped-state observations offer a
comparable allocator-accounting scope. Free arena bytes remain distinct from
resident RSS; no allocator trimming, overrides, allocation padding, process
offloading, resolution reduction or cadence reduction is used.

The new `retarget_phase`/`retarget_finished` output requires a separately
reviewed, source-bound runner. Existing frozen runners and receipts must not be
rewritten or reused as proof for this mode. Native output/pixel/EOF/cancellation
validation and the same-process memory comparison must precede desktop wiring.
25 changes: 25 additions & 0 deletions lucent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading