HelpImStuckInAFractal

Progressive stills

Governor-managed photographic stills now use a separate retained StillTiles viewport. The moving ray viewport stays allocated at moving resolution. The still_generated marker records the start of the capture; completion spans subsequent frames and is not a second still marker. StillTiles is registered alongside the moving viewport, so inspect it rather than assuming SubViewport is always the active ray image. Idle measurements remain potentially stale.

Tiles are 64 × 64 pixels (clipped at the edges), ordered by distance from the image centre. An initial cached-pixel copy seeds the target from the last moving image. Each batch overwrites its regions with full-quality colour and encoded depth, with blending disabled. Unchanged completed tiles are not marched again. Painting and lens effects consume the assembled image and refresh with each batch; partially refined neighbours can temporarily affect blur, but the final pass sees the complete colour/depth image.

The scheduler targets 40 ms total wall-frame time, independent of the F3 25 ms / 40 FPS diagnostic threshold. It reserves 6 ms of headroom, tracks rolling quiet-frame baseline and estimated cost per tile, starts each capture at one tile, grows by at most one tile per observed successful batch (up to 32), and backs off immediately after an overrun. No GPU synchronization or readback is used. A single submitted tile, driver stall, or unrelated work can still exceed 40 ms; this is a feedback target, not a hard deadline. Finish latency can increase to preserve responsiveness.

Camera, scene, noise and size changes cancel the unfinished capture before another batch. The existing settle delay prevents short pauses from starting captures; it has not been lengthened. Completed targets and tile layout are reused for later stills at the same size. Standalone capture callers and intentional escape/phosphor animation retain their existing one-shot/live path.

Cost changes: one retained full-resolution colour/depth target (approximately 25.7 MiB for RGBA8 at 3230 × 2086, excluding driver attachments), a seed copy per capture, up to 32 reusable tile quads/material snapshots, frame-time bookkeeping, and repeated full-image post-processing while assembling. Ray coordinates gain pixel-centre normalization to keep separate tile interpolation consistent. No extra fractal rays are needed to finish a still. Native-driver timing remains hardware-dependent; 40 ms is not a hard limit.

Native rendering verification

Tile quads must be prepared during normal node processing, before Godot flushes CanvasItem redraws. Creating and showing them in frame_pre_draw is too late: frame_post_draw can mark the batch complete and hide it before any quad has actually drawn. Headless lifecycle tests alone cannot detect this failure.

The retained target enables transparency to preserve the shader-readable alpha depth channel. The tested macOS Compatibility opaque target quantized an alpha value of 0.5 to 0.667; the alpha-capable target preserved it at 0.502. Opaque viewport image readback also forces alpha to one, so the regression samples alpha through a second shader, as the lens does.

tests/tiled_still_gpu_test.gd uses actual draw signals and checks visible centre-first replacement, retained outer pixels, completion, target reuse and shader-readable depth. It skips when run headless; a native invocation requires permission under AGENTS.md. Tests use readbacks for assertions only; production rendering does not read the tiles back.

On 2026-10-27, native Godot 4.6.1 Compatibility on Apple M2 Max rendered the saved borgJulia level at 1280 x 800. Two warm captures completed 260 tiles in 57 and 37 frames (1.38 and 0.92 seconds), with maximum measured frame times of 41.0 and 37.9 ms respectively. Full-frame and tiled raw images matched all 4,096,000 bytes. These are bounded scene-specific checks, not performance guarantees for other resolutions or desktop/web drivers.

The display keeps the moving image until the still target’s seed draw completes. Only then does it publish the retained target and wire its painting/lens chain. This prevents the previous camera view in a reused target from flashing during handoff. The existing seed pass doubles as the publication fence: no extra render pass, texture allocation, readback or fractal ray is introduced. Lens depth mode and focus are finalized at publication, costing two uniform updates per pooled tile material (at most 32) once per still; expected CPU impact is small and has not been isolated in a benchmark.