feat(render): Add backend-independent damage rendering#173
Merged
doodlewind merged 4 commits intoJul 24, 2026
Conversation
HalfSweet
marked this pull request as ready for review
July 24, 2026 06:55
HalfSweet
force-pushed
the
feat/esp32p4-dirty-regions
branch
from
July 24, 2026 09:22
04827f1 to
c4d55cd
Compare
doodlewind
approved these changes
Jul 24, 2026
doodlewind
left a comment
Collaborator
There was a problem hiding this comment.
Reviewed the full diff and ran the complete local gate (the repo has no CI for bun tests/goldens). This is clean work — the damage planner lands at exactly the right altitude and the correctness story is proven, not asserted.
Validation (local merge with current main)
engine/core98/98,esp32p4-ppa17/17,engine/wasm1/1,--features esp-idfcheck clean; PR CI green.- Goldens with the rebuilt wasm: 49/49 via the full-render path.
- Extra end-to-end check I ran: temporarily switched
tests/golden.tscapture torenderIncremental()— 49/49 goldens still pass byte-exactly across all 11 apps, with sparse frame captures exercising multi-frame damage accumulation between renders. The web-host switch cannot drift from the pinned pixels. - Full
bun run testchain green.
What I particularly like
damage.rsis genuinely backend-neutral: mechanism (diff → disjoint conservative regions) in core, policy (region cap, 75% promotion) at the caller. No platform vocabulary anywhere in core/wasm/web code.- The prepare/commit transaction plus
invalidate()on failed renders, and the compatibility full-render path invalidating the wasm tracker — the two ABIs can interleave safely. Ui::raster_revisionalso retroactively hardens #160'salpha_texture_cacheagainst same-handle content mutation. Nice catch.- Scissor-moved ops are covered by treating the clip rects themselves as damage bounds — subtle and correct.
wasm-ops.jsfeature-detects the new exports and falls back for older wasm builds, honoring the established tolerance convention.
Non-blocking observations
update_texture_t8bumps the revision every video frame, so incremental hosts do full redraws for the whole playback — correct and no worse than today; a future targeted path could damage only the video quad's bounds.- Fresh texture uploads also bump the revision, forcing one full redraw even for not-yet-referenced textures — over-conservative but cheap and rare.
- docs/DESIGN.md calls the byte order "PPA-memory ARGB8" — core code correctly says LE-ARGB8888/BGRA-memory; suggest the doc adopt the neutral name too.
- Per-region replay re-decodes the full DrawList up to 8×; pixel work dominates and the promotion policy caps pathology, so fine as shipped — worth remembering if region counts ever grow.
Merge-ready from my side (squash subject should lowercase "add" per the Conventional Commits house style).
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.
Base
mainat391f144.Web/WASM, and documentation layers.
Summary
DamageTrackerthat compares retained DrawListsand produces conservative logical damage regions for persistent targets
points while preserving the existing full-frame APIs
framebuffer and retain DrawList painter order across PPA and software
fallback operations
hosts to them
conservatively, and promote damage covering at least 75% of the target to a
full redraw
Design
The tracker uses a two-phase prepare/commit lifecycle so failed renders do not
advance framebuffer history. Each target snapshot includes the DrawList,
viewport/format/scale signature, and the Core raster-resource revision.
Initial frames, incompatible targets, changed resources, structural DrawList
changes, or explicitly invalidated targets therefore repaint conservatively.
Incremental rasterization clears each selected region and replays the complete
current DrawList under a root clip. This preserves blending, occlusion, and
mixed hardware/software painter order without requiring individual operations
to know what was previously behind them.
The original full-frame rendering ABI remains available for callers without a
persistent framebuffer and for deterministic golden capture.
Commits
ec0e103feat(core): add incremental damage rendering88961a0feat(esp32p4): render PPA frames incrementally5e56599feat(web): enable incremental wasm renderingc4d55cddocs: describe incremental rendering architectureValidation
Re-run after rebasing onto
main:esp-idffeature check passedwasm32-unknown-unknownrelease build passedgit diff --checkpassedAdditional validation performed before the rebase:
RGB565 and PPA output byte-exact against full-frame references
base commit produced byte-identical actual PNGs for all 7 mismatches
The repository-wide Bun command also encountered the existing PSP toolchain
doctor test hanging while validating an invalid explicit LLVM override. The
remaining scripted test groups were run separately and passed.