Skip to content

Retain and incrementally invalidate GPU scene data #16

Description

@zoeyrose

Important

This preserved product issue is now part of the fresh MIT replacement program. Final implementation owner: atrinik/renderer. Legacy C/SDL2, packet, global-state, and file-path details below are historical evidence only.

Replacement implementation contract

Make scene/resource revisions and retained packets part of the native renderer design. Preserve painter/lighting/effect invalidation correctness, measure before adding partial pixel caches, and use explicit CPU/GPU memory budgets.

New implementation and tests are independent MIT work unless an exact contribution by an approved MIT provenance grantor is admitted through the recorded file-level MIT grant. Preserve every player-facing, accessibility, disclosure, and performance design decision below.

Required verification

  • Test pure state/geometry/material/UI behavior headlessly where possible and run supported Linux/Windows integration paths.
  • Add bounded malformed, stale, lifecycle, resource-loss, and recovery cases appropriate to the owner.
  • Add shared Go/Rust protocol fixtures for authoritative fields; presentation never reconstructs hidden rules.
  • Use released shared renderer/protocol/toolkit contracts and wrapper-managed replacement scenarios.
Preserved product/design specification and historical implementation notes

Why

The map-data path already handles ordinary movement incrementally. display_mapscroll() rotates the five-window MapCell caches and clears only newly exposed edge strips. The visual path does not preserve that work: every map packet eventually sets one global redraw flag, then map_draw_map() traverses every visible cell on every active physical depth, regenerates deferred draw commands, sorts the unified painter queue, updates lighting as needed, and repaints the complete map target.

After #17 moves drawing to the GPU, full viewport sprite submission may already be cheap enough. CPU-side traversal, command construction, sorting, lighting invalidation, and texture/effect preparation can still scale poorly with stacked levels, animations, and frequent movement. This issue should measure those costs and retain render data incrementally without compromising painter-order or lighting correctness.

Depends on #17.

Design direction

Do not cache final pixels as independent map rows or columns. Isometric rows project to diagonal bands; tall sprites overlap neighboring bands; floors, actors, walls, roofs, effects, and multiple physical depths interleave in one painter order; smooth lighting spans cell boundaries; and door hints depend on later occluders.

Prefer retained per-cell render packets and granular invalidation:

  • Each packet records its source texture/material, transform, projected bounds, painter key, owning cell/depth/layer, and relevant revision keys.
  • Camera position is separate from world render state. Ordinary movement changes the camera transform and creates or invalidates packets only for newly exposed or changed cells.
  • Geometry, face/animation, visibility/fog, lighting, effect, and UI annotation changes have explicit invalidation scopes.
  • Stable painter buckets or incremental merging replace full queue reconstruction/sorting where they are measurably beneficial.
  • The GPU may continue drawing the complete visible packet list. Partial render-target updates are an optional later stage, not the starting assumption.

Work

  • Extend the render profiler with map cells visited, packets reused/built/removed, sort/merge time, draw count, uploaded bytes, invalidated cells, dirty projected area, and full-invalidation reasons.
  • Record baselines after Build the shared SDL3 and wgpu GPU renderer #17 for idle scenes, cardinal/diagonal walking, continuous movement, stacked depths +1/+2, animated maps, smooth lighting, weather/effects, and teleport/map transitions at two representative resolutions.
  • Give map cells or their render-cache entries explicit revisions for geometry/faces, animation, visibility/fog, lighting, and derived effects.
  • Retain per-cell render packets across frames and map scrolls. Rebuild only packets whose source state, projection-dependent state, or material inputs changed.
  • Separate camera/world offset from packet content so a one-tile scroll reuses retained packets and processes only newly exposed edge cells plus genuinely changed server updates.
  • Maintain the documented unified back-to-front ordering across all physical depths. Evaluate stable painter buckets or an incremental ordered structure against rebuilding and qsorting the complete queue.
  • Track projected sprite bounds, including tall, doubled, rotated, zoomed, outlined, and multi-part sprites, so invalidation expands to every pixel a changed cell can affect.
  • Define lighting invalidation neighborhoods for smooth ground quads and structural light profiles. A light or support-height change must invalidate every dependent packet/texture, not only its source tile.
  • Keep annotations, target UI, door occlusion hints, fog/camera cutaways, minimap rendering, and effect sprites in explicit retained or dynamic layers with correct dependencies.
  • Treat new maps, teleports, level transitions, renderer recreation, resize, zoom, tileset/resource reload, and incompatible cache revisions as intentional full invalidations.
  • Benchmark retained full-list GPU submission before implementing partial pixel caching.
  • Only if profiling shows a material remaining GPU fill/submission cost, prototype dirty rectangles or an oversized guard-band render target. Repaint each dirty region by replaying all intersecting commands in painter order; do not split compositing into incorrect independent map rows/columns.
  • Document cache ownership, revision propagation, full-invalidation conditions, and profiling procedure in the client architecture guidance.

Acceptance criteria

  • Ordinary one-tile cardinal movement rebuilds only newly exposed and changed cell packets; diagonal movement rebuilds only the corresponding two edge sets with their overlap handled once.
  • Unchanged cells retain their render packets and GPU resources across movement without stale lighting, animation, fog, or transforms.
  • Teleport/map/level/resize/zoom/renderer-reset paths invalidate coherently and never display pixels or commands from the previous view.
  • Visual comparisons preserve stacked-level painter ordering, tall-sprite overlap, roofs/walls, smooth lighting, fog/cutaways, door hints, target UI, minimap behavior, weather, and animated effects.
  • Before/after measurements report map CPU time, packet reuse/rebuild counts, ordering cost, draw submission, upload traffic, dirty area, and memory use for every baseline scenario.
  • The retained design demonstrates a repeatable improvement in movement or animation workloads without a material regression in idle, teleport, map-load, or UI-heavy workloads. If full GPU redraw is already faster or simpler, the evidence is recorded and unnecessary partial-pixel caching is not merged.
  • Debug assertions or diagnostics detect stale revision dependencies and invalid packet ownership during development.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Effort

    None yet

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions