Prepare shaders for later use (Pipelines)

This commit is contained in:
abux 2026-07-10 02:40:02 +01:00
parent 807e9c91fd
commit 660065c556
9 changed files with 202 additions and 5 deletions

View file

@ -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);
}

View file

@ -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");

View file

View file

@ -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,

View file

@ -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 ---

53
src/resource/cache.zig Normal file
View file

@ -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();
}

View file

@ -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");

View file

@ -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
}
}
}

View file

@ -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);
}
/// ----------------------------------------------------