diff --git a/src/renderer/vulkan/shaders.zig b/src/renderer/vulkan/shaders.zig index 8382f5ee9..3f83e8a08 100644 --- a/src/renderer/vulkan/shaders.zig +++ b/src/renderer/vulkan/shaders.zig @@ -30,19 +30,11 @@ const DescriptorPool = vulkan.DescriptorPool; const Pipeline = @import("Pipeline.zig"); const math = @import("../../math.zig"); -/// Build-time-precompiled SPIR-V blobs for the 9 built-in -/// shaders. Generated by `src/build/VulkanSpv.zig`. Each decl -/// is `[]const u32` backed by a comptime-aligned u8 array -/// (align(@alignOf(u32))) so the underlying storage is on a -/// 4-byte boundary — Module.initFromSpirv can consume the -/// slices directly without alignment surgery. -/// -/// Skipping the runtime glslang call path for built-ins -/// eliminates the per-process TPoolAllocator high-water-mark -/// leak that the first-surface compile otherwise leaves -/// behind (~5 MB heaptrack delta). Custom (user) shaders still -/// go through glslang at runtime via shadertoy.spirvFromGlsl. -const vulkan_spv = @import("vulkan_spv"); +// Build-time-precompiled SPIR-V blobs are generated by +// `src/build/VulkanSpv.zig` and exposed as the `vulkan_spv` +// module — currently UNUSED at runtime; see the long +// explanation in `Shaders.init` for why we went back to +// runtime glslang compilation for built-ins. const log = std.log.scoped(.vulkan); @@ -920,16 +912,33 @@ pub const Shaders = struct { // runtime via shadertoy.spirvFromGlsl, and the per-frame // shadertoy post-pipeline below still allocates via // `alloc`, so the parameter is still load-bearing. + // All built-ins runtime-compiled via glslang. The build- + // time SPV precompile path (commits c921c4b2e / 99d26181e) + // saves ~5 MB of TPoolAllocator leak per heaptrack but + // somehow corrupts kitty image rendering (images fill the + // whole window). The diagnostic in 7c045d694... showed + // even runtime-compiling image_vert + image_frag while + // leaving the other 7 precompiled DIDN'T fix it — so the + // bug isn't local to those shaders' SPV, it's some cross- + // shader interaction (descriptor binding cross-talk? + // ProcessDeferred state divergence between fresh-process + // build-time vs sequential-compile runtime?) we don't + // understand yet. + // + // VulkanSpv.zig + src/vulkan_spvgen.zig + the generated + // vulkan_spv import stay in tree so a future investigation + // can flip the swap back on. ~5 MB cosmetic leak is the + // wrong trade-off vs visibly broken images. var modules: Modules = .{ - .bg_color_frag = try Module.initFromSpirv(device, vulkan_spv.bg_color_frag, .fragment), - .bg_image_frag = try Module.initFromSpirv(device, vulkan_spv.bg_image_frag, .fragment), - .bg_image_vert = try Module.initFromSpirv(device, vulkan_spv.bg_image_vert, .vertex), - .cell_bg_frag = try Module.initFromSpirv(device, vulkan_spv.cell_bg_frag, .fragment), - .cell_text_frag = try Module.initFromSpirv(device, vulkan_spv.cell_text_frag, .fragment), - .cell_text_vert = try Module.initFromSpirv(device, vulkan_spv.cell_text_vert, .vertex), - .full_screen_vert = try Module.initFromSpirv(device, vulkan_spv.full_screen_vert, .vertex), - .image_frag = try Module.initFromSpirv(device, vulkan_spv.image_frag, .fragment), - .image_vert = try Module.initFromSpirv(device, vulkan_spv.image_vert, .vertex), + .bg_color_frag = try Module.init(alloc, device, source.bg_color_frag, .fragment), + .bg_image_frag = try Module.init(alloc, device, source.bg_image_frag, .fragment), + .bg_image_vert = try Module.init(alloc, device, source.bg_image_vert, .vertex), + .cell_bg_frag = try Module.init(alloc, device, source.cell_bg_frag, .fragment), + .cell_text_frag = try Module.init(alloc, device, source.cell_text_frag, .fragment), + .cell_text_vert = try Module.init(alloc, device, source.cell_text_vert, .vertex), + .full_screen_vert = try Module.init(alloc, device, source.full_screen_vert, .vertex), + .image_frag = try Module.init(alloc, device, source.image_frag, .fragment), + .image_vert = try Module.init(alloc, device, source.image_vert, .vertex), }; errdefer { inline for (.{