From 660065c556559a0f06022b63f9ef55cdb63f90ab Mon Sep 17 00:00:00 2001 From: abux Date: Fri, 10 Jul 2026 02:40:02 +0100 Subject: [PATCH] Prepare shaders for later use (Pipelines) --- src/assets/shaders/pbr.wgsl | 17 +++++++ src/component/root.zig | 1 + src/component/unlit_material.zig | 0 src/plugin.zig | 20 ++++++++ src/renderer.zig | 12 +++++ src/resource/cache.zig | 53 ++++++++++++++++++++++ src/resource/root.zig | 1 + src/system/frame.zig | 78 ++++++++++++++++++++++++++++++++ src/template/registry.zig | 25 ++++++++-- 9 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 src/assets/shaders/pbr.wgsl create mode 100644 src/component/unlit_material.zig create mode 100644 src/resource/cache.zig diff --git a/src/assets/shaders/pbr.wgsl b/src/assets/shaders/pbr.wgsl new file mode 100644 index 0000000..cec44b5 --- /dev/null +++ b/src/assets/shaders/pbr.wgsl @@ -0,0 +1,17 @@ +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4f { + var p = vec2f(0.0, 0.0); + if (in_vertex_index == 0u) { + p = vec2f(-0.5, -0.5); + } else if (in_vertex_index == 1u) { + p = vec2f(0.5, -0.5); + } else { + p = vec2f(0.0, 0.5); + } + return vec4f(p, 0.0, 1.0); +} + +@fragment +fn fs_main() -> @location(0) vec4f { + return vec4f(0.0, 0.4, 1.0, 1.0); +} diff --git a/src/component/root.zig b/src/component/root.zig index acb23f4..d193c16 100644 --- a/src/component/root.zig +++ b/src/component/root.zig @@ -3,3 +3,4 @@ pub const Camera = @import("camera.zig"); // --- MATERIALS --- pub const PBRMaterial = @import("pbr_material.zig"); +pub const UnlitMaterial = @import("unlit_material.zig"); diff --git a/src/component/unlit_material.zig b/src/component/unlit_material.zig new file mode 100644 index 0000000..e69de29 diff --git a/src/plugin.zig b/src/plugin.zig index 530721d..502ab34 100644 --- a/src/plugin.zig +++ b/src/plugin.zig @@ -4,6 +4,7 @@ const App = @import("app"); const system = @import("system/root.zig"); const resource = @import("resource/root.zig"); +const component = @import("component/root.zig"); /// ---------------------------------------------------- /// ---------------------------------------------------- @@ -23,11 +24,21 @@ fn build( try ctx.app.resources.set(resource.Instance{}); try ctx.app.resources.set(resource.Device{}); try ctx.app.resources.set(resource.window{}); + try ctx.app.resources.set(resource.Cache.init(ctx.app.alloc)); // --- RENDER --- try ctx.app.resources.set(resource.RenderFrame{}); try ctx.app.resources.set(resource.RenderQueue.init(ctx.app.alloc)); + { // TEST + try ctx.app.world.spawn(.{ + component.PBRMaterial{}, + }); + try ctx.app.world.spawn(.{ + component.UnlitMaterial{}, + }); + } + // --- INIT --- try ctx.app.schedules.addMany(App.stage.Init, &.{ system.instance.init, @@ -35,12 +46,21 @@ fn build( system.device.init, system.frame.begin, + system.frame.prepare, }); // --- DEINIT --- try ctx.app.schedules.addMany(App.stage.Deinit, &.{ system.frame.end, + struct { // TODO: Clean this shit up 🥀 + pub fn sys(_ctx: App.scheduler.Context) !void { + if (_ctx.app.resources.getPtr(resource.Cache)) |cache| { + cache.deinit(); + } + } + }.sys, + system.device.deinit, system.window.deinit, system.instance.deinit, diff --git a/src/renderer.zig b/src/renderer.zig index e526c7b..7f8cd2b 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -2,9 +2,21 @@ const std = @import("std"); const App = @import("app"); const Platform = @import("platform_plugin"); +// +// PUBLIC +// + pub const plugin = @import("plugin.zig").plugin; pub const system = @import("system/root.zig"); pub const resource = @import("resource/root.zig"); +pub const template = @import("template/root.zig"); + +// +// EMBEDED +// + +pub const PBRShader = @embedFile("assets/shaders/pbr.wgsl"); +pub const UnlitShader = @embedFile("assets/shaders/pbr.wgsl"); test "Main" { // --- APP --- diff --git a/src/resource/cache.zig b/src/resource/cache.zig new file mode 100644 index 0000000..43bfb60 --- /dev/null +++ b/src/resource/cache.zig @@ -0,0 +1,53 @@ +//! ---------------------------------------------------- +//! ---------------------------------------------------- + +const std = @import("std"); +const App = @import("app"); +const wgpu = @import("wgpu"); +const Registry = @import("../template/registry.zig").Registry; +const Handle = App.template.Handle; +const Self = @This(); + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const ShaderID = union(enum) { + pbr, + unlit, + custom: Handle([]const u8), +}; + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub const PipelineKey = struct { + shader: ShaderID, +}; + +// +// FIELDS +// + +shaders: Registry(ShaderID, *wgpu.WGPUShaderModuleImpl), +pipelines: Registry(PipelineKey, *wgpu.WGPURenderPipelineImpl), + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn init(alloc: std.mem.Allocator) Self { + return .{ + .shaders = .init(alloc), + .pipelines = .init(alloc), + }; +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn deinit(self: *Self) void { + { // SHADERS + var it = self.shaders.iterator(); + while (it.next()) |entry| { + wgpu.wgpuShaderModuleRelease(entry.value.*); + } + } + + self.shaders.deinit(); + self.pipelines.deinit(); +} diff --git a/src/resource/root.zig b/src/resource/root.zig index 6ae1375..a451188 100644 --- a/src/resource/root.zig +++ b/src/resource/root.zig @@ -2,6 +2,7 @@ pub const Instance = @import("instance.zig"); pub const Device = @import("device.zig"); pub const window = @import("window.zig"); +pub const Cache = @import("cache.zig"); // --- DRAW --- pub const RenderFrame = @import("render_frame.zig"); diff --git a/src/system/frame.zig b/src/system/frame.zig index 1912318..a2d41de 100644 --- a/src/system/frame.zig +++ b/src/system/frame.zig @@ -5,10 +5,15 @@ const std = @import("std"); const sdl = @import("sdl"); const wgpu = @import("wgpu"); const App = @import("app"); +const component = @import("../component/root.zig"); const Window = @import("../resource/window.zig"); const Device = @import("../resource/device.zig"); const RenderFrame = @import("../resource/render_frame.zig"); +const Cache = @import("../resource/cache.zig"); + +const PBRShader = @import("../renderer.zig").PBRShader; +const UnlitShader = @import("../renderer.zig").UnlitShader; /// ---------------------------------------------------- /// ---------------------------------------------------- @@ -102,3 +107,76 @@ pub fn end(ctx: App.scheduler.Context) !void { // --- DEBUG --- sdl.SDL_Delay(2000); // TODO: Remove } + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn prepare(ctx: App.scheduler.Context) !void { + // --- GET RESOURCES --- + const res = try ctx.app.resources.getMany(struct { + window: *Window, + device: *Device, + cache: *Cache, + }); + + // 1) Prepare Shaders + // 2) Prepare Pipelines + + // --- QUERY --- + { + var query = ctx.app.world.query(struct { + pbr_material: ?*component.PBRMaterial, + unlit_material: ?*component.UnlitMaterial, + }, .{}); + while (query.next()) |e| { + + // --- GET SHADER ID --- + const shader_id: Cache.ShaderID = blk: { + if (e.pbr_material) |_| break :blk .pbr; + if (e.unlit_material) |_| break :blk .unlit; + break :blk .unlit; + }; + + // --- ENSURE SHADER MODULE --- + if (!res.cache.shaders.contains(shader_id)) { + // --- GET SHADER CODE --- + const shader_code = switch (shader_id) { + .pbr => PBRShader, + .unlit => UnlitShader, + else => return error.UnknownShaderCode, // TODO: Yes + }; + + // --- WGSL DESC --- + var wgsl_desc: wgpu.WGPUShaderSourceWGSL = .{ + .chain = .{ .sType = wgpu.WGPUSType_ShaderSourceWGSL }, + .code = .{ .data = shader_code, .length = wgpu.WGPU_STRLEN }, + }; + + // --- SHADER MODULE --- + const module = wgpu.wgpuDeviceCreateShaderModule( + res.device.raw, + &wgpu.WGPUShaderModuleDescriptor{ + .label = .{ + .data = @tagName(shader_id), + .length = wgpu.WGPU_STRLEN, + }, + .nextInChain = &wgsl_desc.chain, + }, + ) orelse return error.ShaderModule; + errdefer wgpu.wgpuShaderModuleRelease(module); + + // --- ADD NEW --- + try res.cache.shaders.put( + shader_id, + module, + ); + + // TODO: Only show on debug mode + std.debug.print("\x1b[35m┣━ SHADER\x1b[0m {s}\n", .{@tagName( + shader_id, + )}); + } + + // TODO: Pipelines + } + } +} diff --git a/src/template/registry.zig b/src/template/registry.zig index 00d2832..4be699c 100644 --- a/src/template/registry.zig +++ b/src/template/registry.zig @@ -1,5 +1,6 @@ const std = @import("std"); const App = @import("app"); +const Handle = App.template.Handle; /// ---------------------------------------------------- /// ---------------------------------------------------- @@ -22,6 +23,7 @@ pub fn Registry( pub const Entry = struct { key: K, value: V, + handle: Handle(V), }; // @@ -29,7 +31,7 @@ pub fn Registry( // meta: std.ArrayList(Metadata), - lookup: std.AutoHashMap(K, usize), + lookup: std.AutoHashMap(K, Handle(V)), entries: std.ArrayList(Entry), alloc: std.mem.Allocator, @@ -110,13 +112,20 @@ pub fn Registry( value: V, metadata: Metadata, ) !void { - try self.entries.append(self.alloc, .{ .key = key, .value = value }); + const handle: Handle(V) = .{ + .idx = @intCast(self.entries.items.len), + }; + + try self.entries.append(self.alloc, .{ .key = key, .value = value, .handle = handle }); errdefer _ = self.entries.swapRemove(self.entries.items.len - 1); try self.meta.append(self.alloc, metadata); errdefer _ = self.meta.swapRemove(self.meta.items.len - 1); - try self.lookup.put(key, self.entries.items.len - 1); + try self.lookup.put( + key, + handle, + ); } // @@ -184,8 +193,14 @@ pub fn Registry( /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn getEntry(self: Self, key: K) ?*const Entry { - const idx = self.lookup.get(key) orelse return null; - return &self.entries.items[idx]; + const handle = self.lookup.get(key) orelse return null; + return &self.entries.items[@intCast(handle.idx)]; + } + + /// ---------------------------------------------------- + /// ---------------------------------------------------- + pub fn getHandle(self: *Self, key: K) ?Handle(V) { + return self.lookup.get(key); } /// ----------------------------------------------------