Skip to content

feat(render-graph): design and implement runtime re-compilation for sky mode switching #779

Description

@JeanPhilippeKernel

Context

SkySystem registers multiple sky backends (SkySpherePass, SkyAtmospherePass, HDRIBackdropPass) into the render graph. Only one backend is active per scene. Switching between modes at runtime requires enabling/disabling passes, but the current RenderGraph::Compile() uses an idempotent guard:

pass.Callback->Compile(device, scene, builder, inspector, &pass.Handle);
// Inside every Compile():  if (output_pass && !(*output_pass)) { ... }

A pass compiled on the first Compile() call is never recompiled. A pass that was disabled during the first Compile() has pass.Handle == nullptr and is silently skipped in Execute().

Current workaround: all sky backends are compiled on startup (registered as enabled). Only one is active per Execute() frame. This wastes pipeline creation time for unused backends.

Problem

When mode switches at runtime (e.g. from SkySphere to Atmosphere), the new pass's Compile() has already run but its resource declarations (Setup()) may not match the current graph topology if transient resources changed. AllocateFramebuffers() also needs to re-run to allocate the new pass's framebuffer.

Additionally, the render graph topology (BuildTopology, BuildLifetimes, BuildBarriers, AllocateTransientResources) is computed once at Compile() time. Adding or removing active passes can invalidate the topology.

Design options

Option A — Selective recompile: When SkySystem::ApplyMode detects a mode change, call RenderGraph::Compile() again. Since Compile() is idempotent for already-compiled passes (handle guard), only new passes get compiled. Framebuffers are re-allocated via AllocateFramebuffers(). Old framebuffers are deferred-freed via the existing old_fb_count path.

Option B — Full reset + recompile: Clear pass.Handle for all sky passes before calling Compile(). Forces a full re-bake of the active backend's pipeline. More expensive but correct when topology changes.

Option C — Lazy compilation: Compile each pass on first Execute() when enabled rather than eagerly at startup. Requires a "needs_compile" flag per pass and moving compilation into the execute loop (with a one-frame stall on first use).

Recommended: Option A first. Option C if startup cost becomes measurable.

Acceptance criteria

  • Switching sky mode mid-session (e.g. via Settings panel or scene reload) produces no visual glitch, no Vulkan validation error, and no frame stall longer than one Compile() call.
  • The sky backend that was active before the switch disposes its framebuffer via the deferred-free path.

References

  • sky-rendering.md §7: "Mode changes at runtime require RenderGraph::Compile()"
  • SkySystem::ApplyMode() in ZEngine/Rendering/Renderers/Sky/SkySystem.cpp
  • RenderGraph::Compile() in ZEngine/Rendering/Renderers/RenderGraph.cpp

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions