Skip to content

[Audit][High] setTextureUniforms never called after shadow system init, shadow map handles remain zero #619

@MichaelFisher1997

Description

@MichaelFisher1997

🔍 Module Scanned

modules/engine-ui/src/ (automated audit scan)

📝 Summary

The setTextureUniforms function is never called after shadow system initialization, causing shadow_map_handles in the render context to remain zero-initialized. When DebugShadowOverlay calls ui.drawDepthTexture(handle, tex_rect) using handles from getShadowMapHandle(), the handles are invalid (0), causing "Texture handle X not found in textures map" errors during debug shadow overlay rendering.

📍 Location

  • File: modules/engine-graphics/src/vulkan/rhi_state_control.zig:13
  • Function/Scope: setTextureUniforms and shadow_runtime.shadow_map_handles

🔴 Severity: High

  • High: Memory leaks, race conditions, incorrect rendering, broken features

💥 Impact

When the debug shadow overlay is enabled (via debug_shadow debug feature), calling drawDepthTexture will pass invalid texture handle 0 to the Vulkan debug shadow pipeline. This results in:

  1. Error logging: "drawDepthTexture: Texture handle 0 not found in textures map!"
  2. The debug shadow overlay renders nothing for cascade textures
  3. Potential descriptor binding issues with VkImageView being null

The root cause is that setTextureUniforms (which should propagate shadow_map_handles from shadow system to render state) is never invoked after the shadow system initializes these handles at startup. The handles are registered correctly during rhi_resource_setup.zig:116 but the copy into shadow_runtime.shadow_map_handles only happens through setTextureUniforms (see rhi_state_control.zig:15).

🔎 Evidence

Issue in rhi_state_control.zig:13-15:

pub fn setTextureUniforms(ctx: anytype, texture_enabled: bool, shadow_map_handles: [rhi.SHADOW_CASCADE_COUNT]rhi.TextureHandle) void {
    ctx.options.textures_enabled = texture_enabled;
    ctx.shadow_runtime.shadow_map_handles = shadow_map_handles;  // <-- This is the only place that updates shadow_map_handles

Shadow map handles initialized to zero in rhi_context_types.zig:99:

shadow_map_handles: [rhi.SHADOW_CASCADE_COUNT]rhi.TextureHandle = .{0} ** rhi.SHADOW_CASCADE_COUNT,

Handles are registered in rhi_resource_setup.zig:116 but never copied to render context:

ctx.shadow_runtime.shadow_map_handles[si] = try ctx.resources.registerExternalTexture(shadow_res, shadow_res, .depth, layer_view, ctx.shadow_system.shadow_sampler_regular);

getShadowMapHandle in rhi_shadow_bridge.zig:22-24 returns the zero-initialized handles:

pub fn getShadowMapHandle(ctx: anytype, cascade_index: u32) rhi.TextureHandle {
    if (cascade_index >= rhi.SHADOW_CASCADE_COUNT) return 0;
    return ctx.shadow_runtime.shadow_map_handles[cascade_index];  // <-- Returns 0!
}

Debug shadow overlay uses these handles without validation in debug_shadow_overlay.zig:31:

const handle = shadow.getShadowMapHandle(@intCast(i));
if (handle == 0) continue;  // This check is present, so nothing renders

🛠️ Proposed Fix

Add a call to setTextureUniforms during RHI initialization or after shadow system setup to propagate the initialized shadow map handles from ctx.shadow_runtime.shadow_map_handles (set during registerExternalTexture) to the render state copy.

In rhi_resource_setup.zig, after line 116 where handles are set:

ctx.shadow_runtime.shadow_map_handles[si] = try ctx.resources.registerExternalTexture(...);

Add after the loop (around line 128):

// Propagate shadow map handles to render state
state_control.setTextureUniforms(ctx, true, ctx.shadow_runtime.shadow_map_handles);

Alternatively, modify getShadowMapHandle to directly query ctx.shadow_system.shadow_image_views instead of going through the stale shadow_runtime.shadow_map_handles.

✅ Acceptance Criteria

  • drawDepthTexture successfully renders shadow cascade textures in debug overlay when debug_shadows build option is enabled
  • No "Texture handle X not found in textures map" errors appear when debug shadow overlay is active
  • Shadow map handles are correctly propagated from shadow system to render state after initialization
  • All existing tests in zig build test continue to pass

📚 References

  • rhi_state_control.zig:13-19 - setTextureUniforms function that updates shadow_map_handles
  • rhi_shadow_bridge.zig:22-24 - getShadowMapHandle implementation
  • rhi_context_types.zig:99 - shadow_map_handles field initialization
  • rhi_resource_setup.zig:105-116 - where shadow map handles are initially registered

Metadata

Metadata

Assignees

No one assigned

    Labels

    automated-auditIssues found by automated opencode audit scansbugSomething isn't workingenhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions