Added Plugins [Renderer, Cache, Common]

This commit is contained in:
abux 2026-07-28 22:37:53 +01:00
parent 8dc9953666
commit 5e62d2c268
10 changed files with 483 additions and 0 deletions

View file

@ -48,6 +48,18 @@ pub fn build(b: *std.Build) void {
}); });
exe.root_module.addImport("app", app.module("app")); exe.root_module.addImport("app", app.module("app"));
const gtl = b.dependency("gtl", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("gtl", gtl.module("gtl"));
const zla = b.dependency("zla", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zla", zla.module("zla"));
// //
// SYSTEM DEPENDENCIES // SYSTEM DEPENDENCIES
// //

View file

@ -13,9 +13,12 @@ const App = @import("app");
// //
const template = @import("plugins/template/root.zig"); const template = @import("plugins/template/root.zig");
const common = @import("plugins/common/root.zig");
const platform = @import("plugins/platform/root.zig"); const platform = @import("plugins/platform/root.zig");
const device = @import("plugins/device/root.zig"); const device = @import("plugins/device/root.zig");
const window = @import("plugins/window/root.zig"); const window = @import("plugins/window/root.zig");
const cache = @import("plugins/cache/root.zig");
const renderer = @import("plugins/renderer/root.zig");
/// ---------------------------------------------------- /// ----------------------------------------------------
/// ---------------------------------------------------- /// ----------------------------------------------------
@ -29,6 +32,8 @@ pub fn main(init: std.process.Init) !void {
platform.plugin, platform.plugin,
device.plugin, device.plugin,
window.plugin, window.plugin,
cache.plugin,
renderer.plugin,
}); });
try app.plugins.build(&app); try app.plugins.build(&app);

View file

@ -0,0 +1,19 @@
@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

@ -0,0 +1,131 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const std = @import("std");
const gtl = @import("gtl");
const wgpu = @import("wgpu");
const Self = @This();
const Material = @import("../../common/component/material.zig");
const ShaderCache = @import("shader_cache.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const GPUPipeline = struct {
raw: *wgpu.WGPURenderPipelineImpl,
};
//
// FIELDS
//
pipelines: gtl.KeyedSlotMap(Material.Unique, GPUPipeline),
shader_cache: *ShaderCache,
queue: *wgpu.WGPUQueueImpl,
device: *wgpu.WGPUDeviceImpl,
alloc: std.mem.Allocator,
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(
shader_cache: *ShaderCache,
queue: *wgpu.WGPUQueueImpl,
device: *wgpu.WGPUDeviceImpl,
alloc: std.mem.Allocator,
) Self {
return .{
.pipelines = .init(alloc),
.shader_cache = shader_cache,
.queue = queue,
.device = device,
.alloc = alloc,
};
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(self: *Self) void {
// --- FREE PIPELINES ---
for (self.pipelines.items()) |entry| {
wgpu.wgpuRenderPipelineRelease(entry.value.raw);
}
// --- # ---
self.pipelines.deinit();
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn getOrCreate(
self: *Self,
key: Material.Unique,
) !*GPUPipeline {
return try self.pipelines.getOrPut(key, .{
.raw = try self.createPipeline(key),
});
}
/// ----------------------------------------------------
/// ----------------------------------------------------
fn createPipeline(
self: *Self,
key: Material.Unique,
) !*wgpu.WGPURenderPipelineImpl {
// --- ENSURE SHADER MODULE ---
const shader_module = try self.shader_cache.getOrCreate(
key.shader,
);
// --- RESULT ---
return wgpu.wgpuDeviceCreateRenderPipeline(self.device, &wgpu.WGPURenderPipelineDescriptor{
.label = .{ .data = @tagName(key.shader), .length = wgpu.WGPU_STRLEN },
.vertex = .{
.module = shader_module.raw,
.entryPoint = .{ .data = "vs_main", .length = wgpu.WGPU_STRLEN },
},
.fragment = &wgpu.WGPUFragmentState{
.module = shader_module.raw,
.entryPoint = .{ .data = "fs_main", .length = wgpu.WGPU_STRLEN },
.targetCount = 1,
.targets = &wgpu.WGPUColorTargetState{
.format = 28,
.blend = &wgpu.WGPUBlendState{
.color = .{
.srcFactor = wgpu.WGPUBlendFactor_SrcAlpha,
.dstFactor = wgpu.WGPUBlendFactor_OneMinusSrcAlpha,
.operation = wgpu.WGPUBlendOperation_Add,
},
.alpha = .{
.srcFactor = wgpu.WGPUBlendFactor_Zero,
.dstFactor = wgpu.WGPUBlendFactor_One,
.operation = wgpu.WGPUBlendOperation_Add,
},
},
.writeMask = wgpu.WGPUColorWriteMask_All,
},
},
.primitive = .{
.topology = switch (key.topology) {
.triangle_list => wgpu.WGPUPrimitiveTopology_TriangleList,
.point_list => wgpu.WGPUPrimitiveTopology_PointList,
.line_list => wgpu.WGPUPrimitiveTopology_LineList,
},
.frontFace = switch (key.front_face) {
.ccw => wgpu.WGPUFrontFace_CCW,
.cw => wgpu.WGPUFrontFace_CW,
},
.cullMode = switch (key.cull_mode) {
.back => wgpu.WGPUCullMode_Back,
.front => wgpu.WGPUCullMode_Front,
.none => wgpu.WGPUCullMode_None,
},
},
.multisample = .{
.count = 1,
.mask = ~@as(u32, 0),
.alphaToCoverageEnabled = 0,
},
}) orelse {
return error.PipelineCreationFailed;
};
}

View file

@ -0,0 +1,103 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const std = @import("std");
const gtl = @import("gtl");
const wgpu = @import("wgpu");
const Self = @This();
//
// EMBEDED
//
const PBRCode = @embedFile("embeded/shaders/pbr.wgsl");
const UnlitCode = @embedFile("embeded/shaders/pbr.wgsl");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const ShaderID = union(enum) {
pbr,
unlit,
custom: u32,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const GPUShader = struct {
raw: *wgpu.WGPUShaderModuleImpl,
};
//
// FIELDS
//
modules: gtl.KeyedSlotMap(ShaderID, GPUShader),
custom_paths: std.ArrayList([]const u8),
device: *wgpu.WGPUDeviceImpl,
alloc: std.mem.Allocator,
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(
device: *wgpu.WGPUDeviceImpl,
alloc: std.mem.Allocator,
) Self {
return .{
.modules = .init(alloc),
.custom_paths = .empty,
.device = device,
.alloc = alloc,
};
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(self: *Self) void {
// --- FREE SHADERS ---
for (self.modules.items()) |entry| {
wgpu.wgpuShaderModuleRelease(entry.value.raw);
}
// --- # ---
self.modules.deinit();
self.custom_paths.deinit(self.alloc);
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn getOrCreate(
self: *Self,
key: ShaderID,
) !*GPUShader {
return try self.modules.getOrPut(key, .{
.raw = try self.createShader(key),
});
}
/// ----------------------------------------------------
/// ----------------------------------------------------
fn createShader(
self: *Self,
key: ShaderID,
) !*wgpu.WGPUShaderModuleImpl {
// --- CODE ---
const code: []const u8 = switch (key) {
.pbr => PBRCode,
.unlit => UnlitCode,
.custom => |v| self.custom_paths.items[@intCast(v)], // TODO: Handle out of bounds
};
// --- SOURCE ---
var source: wgpu.WGPUShaderSourceWGSL = .{
.chain = .{ .sType = wgpu.WGPUSType_ShaderSourceWGSL },
.code = .{ .data = code.ptr, .length = wgpu.WGPU_STRLEN },
};
// --- RESULT ---
return wgpu.wgpuDeviceCreateShaderModule(self.device, &wgpu.WGPUShaderModuleDescriptor{
.label = .{ .data = @tagName(key), .length = wgpu.WGPU_STRLEN },
.nextInChain = &source.chain,
}) orelse {
return error.ShaderModuleCreationFailed;
};
}

33
src/plugins/cache/root.zig vendored Normal file
View file

@ -0,0 +1,33 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
//
// PRIVATE
//
const App = @import("app");
const lifetime = @import("system/lifetime.zig");
//
// PUBLIC
//
pub const ShaderCache = @import("resource/shader_cache.zig");
pub const PipelineCache = @import("resource/pipeline_cache.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const plugin: App.plugin.Plugin = .{
.name = "Cache",
.build = build,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
fn build(
_: *App.plugin.Plugin,
app: *App,
) !void {
try app.schedules.add(App.stage.init, lifetime.init);
try app.schedules.add(App.stage.deinit, lifetime.deinit);
}

92
src/plugins/cache/system/lifetime.zig vendored Normal file
View file

@ -0,0 +1,92 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const std = @import("std");
const gtl = @import("gtl");
const App = @import("app");
const WGPUDevice = @import("../../device/resource/wgpu_device.zig");
const ShaderCache = @import("../resource/shader_cache.zig");
const PipelineCache = @import("../resource/pipeline_cache.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(app: *App) !void {
// --- # ---
const res = try app.resources.getMany(struct {
device: *const WGPUDevice,
});
// --- SHADER CACHE ---
const shaders = try app.resources.getOrSet(ShaderCache.init(
res.device.raw,
app.alloc,
));
// --- PIPELINE CACHE ---
const pipelines = try app.resources.getOrSet(PipelineCache.init(
shaders,
res.device.queue,
res.device.raw,
app.alloc,
));
// TODO: Remove or place it somewhere else, idk
// --- TEST ---
_ = try pipelines.getOrCreate(.{});
_ = try pipelines.getOrCreate(.{});
_ = try pipelines.getOrCreate(.{ .shader = .unlit });
_ = try pipelines.getOrCreate(.{ .shader = .unlit });
{ // DEBUG
std.debug.print("{s}┏━{s} PIPELINES\n", .{ gtl.ansi.blue, gtl.ansi.reset });
for (pipelines.pipelines.items(), 0..) |entry, i| {
// std.debug.print("\x1b[33m\x1b[0m {s:<12} {s}\n", .{ plugin.name, plugin.description });
std.debug.print(
\\{s}┃ ┏━{s} {}
\\{s}┃ ┃ {s}Shader: {s}
\\{s}┃ ┃ {s}Cull Mode: {s}
\\{s}┃ ┃ {s}Blend Mode: {s}
\\{s}┃ ┃ {s}Front Face: {s}
\\{s}┃ ┃ {s}Topology: {s}
\\
, .{
gtl.ansi.blue,
gtl.ansi.reset,
i,
gtl.ansi.blue,
gtl.ansi.reset,
@tagName(entry.key.shader),
gtl.ansi.blue,
gtl.ansi.reset,
@tagName(entry.key.cull_mode),
gtl.ansi.blue,
gtl.ansi.reset,
@tagName(entry.key.blend_mode),
gtl.ansi.blue,
gtl.ansi.reset,
@tagName(entry.key.front_face),
gtl.ansi.blue,
gtl.ansi.reset,
@tagName(entry.key.topology),
});
std.debug.print("{s}┃ ┗━{s}\n", .{ gtl.ansi.blue, gtl.ansi.reset });
}
std.debug.print("{s}┗━{s}\n", .{ gtl.ansi.blue, gtl.ansi.reset });
}
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(app: *App) !void {
// --- # ---
const res = try app.resources.getMany(struct {
shaders: *ShaderCache,
pipelines: *PipelineCache,
});
// --- # ---
res.shaders.deinit();
res.pipelines.deinit();
}

View file

@ -0,0 +1,52 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const gtl = @import("gtl");
const ShaderID = @import("../../cache/resource/shader_cache.zig").ShaderID;
const Handle = gtl.Handle;
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Style = struct {
albedo: @Vector(4, f32) = .{ 1, 1, 1, 1 },
metallic: f32 = 0.0,
roughness: f32 = 0.5,
_pad0: [2]f32 = .{ 0, 0 },
};
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Unique = struct {
shader: ShaderID = .pbr,
front_face: enum {
cw,
ccw,
} = .ccw,
cull_mode: enum {
back,
front,
none,
} = .back,
topology: enum {
triangle_list,
point_list,
line_list,
} = .triangle_list,
blend_mode: enum {
none,
alpha,
additive,
multiply,
} = .none,
};
//
// FIELDS
//
style: Style = .{},
unique: Unique = .{},

View file

@ -0,0 +1,8 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
//
// COMPONENTS
//
pub const Material = @import("component/material.zig");

View file

@ -0,0 +1,28 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
//
// PRIVATE
//
const App = @import("app");
//
// PUBLIC
//
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const plugin: App.plugin.Plugin = .{
.name = "Renderer",
.build = build,
};
/// ----------------------------------------------------
/// ----------------------------------------------------
fn build(
_: *App.plugin.Plugin,
app: *App,
) !void {
_ = app;
}