Summary
Implement dynamic resolution rendering that adjusts render resolution based on frame time budget. During fast camera movement or at extreme render distances, render at lower resolution and upscale via TAA. This keeps frame time consistent regardless of scene complexity.
Depends on: #388 (double-buffer upload — needs stable frame pacing)
How It Works
- Each frame: measure GPU time of previous frame
- If over budget (e.g., 16ms for 60 FPS target): reduce resolution scale (e.g., 0.7x)
- If under budget: increase resolution scale (e.g., 1.0x = native)
- Render at adjusted resolution into offscreen target
- TAA resolve + upscale to native swapchain resolution
- Smooth transitions: scale changes ±0.01 per frame (no popping)
Implementation Plan
Step 1: Offscreen render targets
- Create color + depth attachments at dynamically-sized resolution
- When scale changes: recreate these targets (or pre-allocate at max size and use view subsets)
- More efficient: pre-allocate at native resolution, use
vkCmdSetViewport/vkCmdSetScissor to render into a sub-region, then upscale
Step 2: Frame time tracking
- Use existing GPU timestamps from
rhi_timing.zig
- Track rolling average over 8 frames to avoid thrashing
- Budget: configurable (16ms for 60 FPS, 8ms for 120 FPS)
Step 3: Scale adjustment logic
const target_ms = 1000.0 / target_fps;
const current_ms = rolling_avg_gpu_ms;
if (current_ms > target_ms * 1.1) {
// Over budget: reduce scale
scale = @max(scale - 0.02, min_scale);
} else if (current_ms < target_ms * 0.8) {
// Under budget: increase scale
scale = @min(scale + 0.01, max_scale);
}
Step 4: TAA upscale integration
- TAA pass already exists (
taa_system.zig)
- Modify to accept input at lower resolution and output at native
- TAA's temporal accumulation naturally smooths the upscale
- Jitter pattern scaled to match render resolution
Step 5: Settings integration
- Add "Dynamic Resolution" toggle to settings
- Add min/max scale bounds (default: 0.5x - 1.0x)
- Add target FPS setting (60, 120, 144, unlimited)
- Show current scale in timing overlay
Step 6: Quality considerations
- UI always renders at native resolution (no blur on text/menus)
- Only world rendering uses dynamic resolution
- Post-processing (bloom, FXAA) runs at native resolution on upscaled image
Files to Modify
src/engine/graphics/vulkan/frame_manager.zig — dynamic render targets
src/engine/graphics/vulkan/swapchain_presenter.zig — resolve to native
src/engine/graphics/vulkan/taa_system.zig — accept variable input resolution
src/engine/graphics/render_graph.zig — pass resolution to sub-passes
src/engine/ui/timing_overlay.zig — show current scale
src/game/settings/data.zig — dynamic resolution toggle, min/max scale, target FPS
Testing
Roadmap: docs/PERFORMANCE_ROADMAP.md — Batch 6, Issue 4B
Summary
Implement dynamic resolution rendering that adjusts render resolution based on frame time budget. During fast camera movement or at extreme render distances, render at lower resolution and upscale via TAA. This keeps frame time consistent regardless of scene complexity.
Depends on: #388 (double-buffer upload — needs stable frame pacing)
How It Works
Implementation Plan
Step 1: Offscreen render targets
vkCmdSetViewport/vkCmdSetScissorto render into a sub-region, then upscaleStep 2: Frame time tracking
rhi_timing.zigStep 3: Scale adjustment logic
Step 4: TAA upscale integration
taa_system.zig)Step 5: Settings integration
Step 6: Quality considerations
Files to Modify
src/engine/graphics/vulkan/frame_manager.zig— dynamic render targetssrc/engine/graphics/vulkan/swapchain_presenter.zig— resolve to nativesrc/engine/graphics/vulkan/taa_system.zig— accept variable input resolutionsrc/engine/graphics/render_graph.zig— pass resolution to sub-passessrc/engine/ui/timing_overlay.zig— show current scalesrc/game/settings/data.zig— dynamic resolution toggle, min/max scale, target FPSTesting
Roadmap:
docs/PERFORMANCE_ROADMAP.md— Batch 6, Issue 4B