--- id: PLN-0012 ticket: scene-bank-and-viewport-cache-refactor title: Plan - Scene Viewport Cache Structure status: accepted created: 2026-04-13 completed: tags: [gfx, tilemap, runtime, render] --- ## Objective Implement the `SceneViewportCache` as the operational render cache for one `Scene`, including one internal ringbuffer per layer and lightweight derived cache entries for raster acceleration. ## Background `DEC-0013` locks `SceneViewportCache` as the renderer-facing view of scene data and prefers internal ringbuffer storage per layer. This plan isolates the cache data structure and update API before resolver and renderer integration. ## Scope ### Included - Define `SceneViewportCache`. - Define the per-layer internal ringbuffer structure. - Define the cached tile entry format. - Define cache update APIs for line, column, and area/region. - Define full invalidation on scene swap. ### Excluded - camera logic - drift/hysteresis logic - final renderer migration - execution of blits into `back` ## Execution Steps ### Step 1 - Define cache entry and layer-cache structures **What:** Create the internal data model for one viewport cache layer and for cached tile entries. **How:** - Introduce a cache tile entry type that stores: - resolved `glyph_id` - resolved `palette_id` - packed flip flags - `active/empty` - fast layer-local glyph bank reference/index - Introduce one ringbuffer-backed layer-cache structure per scene layer. - Keep ringbuffer internals encapsulated and out of public semantic APIs. **File(s):** - New HAL or driver-side viewport-cache module(s), likely under: - `crates/console/prometeu-hal/src/` - and/or `crates/console/prometeu-drivers/src/` ### Step 2 - Define `SceneViewportCache` as a four-layer aggregate **What:** Create the top-level cache aggregate for one `Scene`. **How:** - Represent one cache aggregate containing four internal layer caches. - Thread through cache dimensions and tile-size assumptions for V1. - Make the cache explicitly scene-derived and non-canonical. **File(s):** - New cache module(s) - Any related exports in HAL/driver public surfaces ### Step 3 - Implement cache mutation APIs **What:** Define the update surface that later plans will use for rematerialization. **How:** - Add explicit APIs for: - refresh line - refresh column - refresh area/region - invalidate whole cache on scene swap - Ensure corner refresh can use region updates without duplicate work on already-present tiles. **File(s):** - New cache module(s) - Any helper modules shared with resolver integration ### Step 4 - Implement scene-to-cache materialization helpers **What:** Add helpers that copy canonical scene data into cache entries. **How:** - Build helpers that read canonical `SceneLayer`/`TileMap` data and populate cache entries. - Keep the helpers unaware of camera policy; they should only perform requested materialization work. - Ensure per-layer movement factors remain metadata of the scene layer, not cache-only state. **File(s):** - New cache/materialization helper module(s) ### Step 5 - Add focused tests for cache structure and update rules **What:** Protect the cache shape and update operations before wiring the resolver. **How:** - Add tests for: - ringbuffer wrap behavior - line refresh - column refresh - region refresh - scene-swap invalidation - no duplicate reload for corner-style region updates **File(s):** - Tests colocated with cache modules ## Test Requirements ### Unit Tests - Each cache layer maintains ringbuffer invariants under wrap. - Cache entry fields match the expected derived values from canonical scene tiles. - Line/column/region refresh APIs only rewrite the requested area. ### Integration Tests - Materialization from `Scene` into `SceneViewportCache` succeeds across all four layers. ### Manual Verification - Inspect debug output or temporary probes to confirm cache updates do not expose ringbuffer details outside the cache boundary. ## Acceptance Criteria - [ ] `SceneViewportCache` exists as a four-layer aggregate. - [ ] Each layer cache uses internal ringbuffer storage. - [ ] Cache entries store the lightweight derived raster fields defined by the decision. - [ ] Explicit APIs exist for line, column, area/region, and full invalidation. - [ ] Tests cover wrap and non-duplicative corner updates. ## Dependencies - Depends on `PLN-0011` for canonical `Scene` / `SceneLayer` / `TileMap` types. - Source decision: `DEC-0013` ## Risks - Over-designing cache entry shape can accidentally turn the cache into a second heavy scene representation. - Ringbuffer implementation bugs can stay hidden until resolver integration if tests are too weak. - Region refresh semantics can become ambiguous if API boundaries are not explicit early.