Skip to content

Shader material destroyed mid-update is submitted for one frame before the next renderer sync #883

Closed

Description

@apotema

What

A shader material replaced or cleared during active_scene_update_fn has its old backend material destroyed immediately — but tick has already run renderer.sync, so the imminent render() submits the dead id. Result: one frame drawn through the plain-sprite fallback before the next sync picks up the new material.

Raised by Codex on #882 (thread discussion_r…9527, line 126 of shader_material_mixin.zig). It is plausible from the ordering and was deliberately not changed on that PR: the fix is a design decision about renderer-sync versus resource lifetime, and the same ordering applies to the curated-effect setMaterial path, so a one-off patch on a merge-gated PR would be the wrong shape.

Why it matters

A one-frame flash to the fallback is exactly the class of visual glitch that reads as "the shader stuttered" and is nearly impossible to reproduce on demand. It is also the kind of thing a fixed-time golden never catches, because goldens sample after sync.

Options

  1. Retire list — destroy is deferred until after the next renderer.sync, so a submitted id is always live for the frame it was cached in. Simple, bounded (one frame of extra lifetime), and covers setMaterial too.
  2. Resync before destroy — re-run the affected entity's sync inline when a material changes mid-update. Tighter, but puts sync work on the update path and needs care with the world/renderer split.

(1) is the conventional answer in renderers with cached draw lists.

Acceptance

  • Replacing or clearing a shader material (and a curated setMaterial) during scene update never submits a destroyed id
  • A mechanism test: swap the material mid-update, render, and assert the material path ran on that frame — not merely that nothing crashed
  • Whichever option is chosen, the old material's destruction is still guaranteed within one frame (no leak by deferral)

Refs: #882.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions