Changed some architectural stuff | Some cleanup | Random stuff

This commit is contained in:
abux 2026-07-30 12:37:17 +02:00
parent 0eb9a44828
commit b8733f6782
11 changed files with 292 additions and 176 deletions

View file

@ -43,13 +43,13 @@ struct ModelUniform {
// UNIFORMS
//
// @group(0) @binding(0)
// var<uniform> camera: CameraUniform;
// @group(1) @binding(0)
// var<uniform> model: ModelUniform;
@group(0) @binding(0)
var<uniform> camera: CameraUniform;
@group(1) @binding(0)
var<uniform> model: ModelUniform;
@group(2) @binding(0)
var<uniform> material: Material;
//
@ -76,6 +76,8 @@ fn vs_main(in: VertexInput) -> VertexOutput {
@fragment
fn fs_main(out: VertexOutput) -> @location(0) vec4f {
return vec4f(out.uv, 0.3, 1.0);
// return vec4f(material.albedo);
var final_color: vec4f = material.albedo;
final_color.x += out.uv.x * 0.2;
final_color.y += out.uv.y * 0.2;
return vec4f(final_color);
}

View file

@ -6,7 +6,7 @@ const gtl = @import("gtl");
const wgpu = @import("wgpu");
const Self = @This();
const Material = @import("../../common/component/material.zig");
const Material = @import("../../renderer/template/material.zig");
const ShaderCache = @import("shader_cache.zig");
const ShaderID = ShaderCache.ShaderID;
const Vertex = @import("mesh_cache.zig").Vertex;
@ -16,6 +16,8 @@ const Vertex = @import("mesh_cache.zig").Vertex;
pub const GPUPipeline = struct {
raw: *wgpu.WGPURenderPipelineImpl,
layout: *wgpu.WGPUPipelineLayoutImpl,
bind_group_layouts: [1]*wgpu.WGPUBindGroupLayoutImpl,
// bind_group_layouts: []const *wgpu.WGPUBindGroupLayoutImpl,
};
/// ----------------------------------------------------
@ -23,6 +25,7 @@ pub const GPUPipeline = struct {
pub const GPUMaterial = struct {
buffer: *wgpu.WGPUBufferImpl,
bind_group: *wgpu.WGPUBindGroupImpl,
dirty: bool = true,
};
//
@ -61,7 +64,7 @@ pub fn init(
pub fn deinit(self: *Self) void {
// --- FREE PIPELINES ---
for (self.pipelines.items()) |entry| {
// wgpu.wgpuPipelineLayoutRelease(entry.value.layout);
wgpu.wgpuPipelineLayoutRelease(entry.value.layout);
wgpu.wgpuRenderPipelineRelease(entry.value.raw);
}
@ -81,17 +84,25 @@ pub fn deinit(self: *Self) void {
/// ----------------------------------------------------
pub fn getOrCreateMaterial(
self: *Self,
material: Material,
material_handle: gtl.Handle(Material),
) !*GPUMaterial {
return try self.materials.getOrPut(
material.unique.shader,
return try self.materials_gpu.getOrPut(
material_handle,
blk: {
// --- # ---
if (self.materials_gpu.getByKey(material_handle)) |v| return v;
const material = self.materials.get(material_handle) orelse return error.MaterialNotFound;
// --- ENSURE PIPELINE ---
const pipeline = try self.getOrCreatePipeline(material);
// --- UNIFORM ---
const uniform = wgpu.wgpuDeviceCreateBuffer(self.device, &wgpu.WGPUBufferDescriptor{
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
.size = @sizeOf(Material.Style),
}) orelse return error.Buffer;
// --- WRITE TO UNIFORM ---
wgpu.wgpuQueueWriteBuffer(
self.queue,
uniform,
@ -100,10 +111,25 @@ pub fn getOrCreateMaterial(
@sizeOf(Material.Style),
);
// --- BIND GROUP ---
const bind_group = wgpu.wgpuDeviceCreateBindGroup(self.device, &wgpu.WGPUBindGroupDescriptor{
.layout = pipeline.bind_group_layouts[0],
.entryCount = 1,
.entries = &[_]wgpu.WGPUBindGroupEntry{
.{
.binding = 0,
.buffer = uniform,
.offset = 0,
.size = @sizeOf(Material.Style),
},
},
}) orelse return error.BindGroup;
// --- RESULT ---
break :blk .{
.bind_group = undefined,
.buffer = uniform,
.bind_group = bind_group,
.dirty = false,
};
},
);
@ -111,25 +137,52 @@ pub fn getOrCreateMaterial(
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn getOrCreate(
pub fn getOrCreatePipeline(
self: *Self,
key: Material,
material: *const Material,
) !*GPUPipeline {
return try self.pipelines.getOrPut(key.unique, blk: {
// const layout = wgpu.wgpuDeviceCreatePipelineLayout(
// self.device,
// &wgpu.WGPUPipelineLayoutDescriptor{
// .bindGroupLayoutCount = 1,
// .bindGroupLayouts = &wgpu.WGPUBindGroupLayoutDescriptor{
// .entryCount = 1,
// },
// },
// ) orelse return error.Layout;
return try self.pipelines.getOrPut(material.unique, blk: {
// --- # ---
if (self.pipelines.getByKey(material.unique)) |v| return v;
// --- MATERIAL LAYOUT ---
const material_layout = wgpu.wgpuDeviceCreateBindGroupLayout(self.device, &wgpu.WGPUBindGroupLayoutDescriptor{
.entryCount = 1,
.entries = &[_]wgpu.WGPUBindGroupLayoutEntry{
.{
.binding = 0,
.visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment,
.buffer = .{
.type = wgpu.WGPUBufferBindingType_Uniform,
.minBindingSize = @sizeOf(Material.Style),
.hasDynamicOffset = 0,
},
},
},
}) orelse return error.BindGroupLayout;
// --- PIPELINE LAYOUT ---
const pipeline_layout = wgpu.wgpuDeviceCreatePipelineLayout(
self.device,
&wgpu.WGPUPipelineLayoutDescriptor{
.bindGroupLayoutCount = 1,
.bindGroupLayouts = &material_layout,
},
) orelse return error.Layout;
// --- CREATE PIPELINE ---
const pipeline = try self.createPipeline(
material.unique,
pipeline_layout,
);
// --- RESULT ---
break :blk .{
.raw = try self.createPipeline(key.unique, undefined),
.layout = undefined,
.raw = pipeline,
.layout = pipeline_layout,
.bind_group_layouts = .{
material_layout,
},
};
});
}
@ -141,8 +194,6 @@ fn createPipeline(
key: Material.Unique,
layout: *wgpu.WGPUPipelineLayoutImpl,
) !*wgpu.WGPURenderPipelineImpl {
_ = layout;
// --- ENSURE SHADER MODULE ---
const shader_module = try self.shader_cache.getOrCreate(
key.shader,
@ -151,6 +202,7 @@ fn createPipeline(
// --- RESULT ---
return wgpu.wgpuDeviceCreateRenderPipeline(self.device, &wgpu.WGPURenderPipelineDescriptor{
.label = .{ .data = @tagName(key.shader), .length = wgpu.WGPU_STRLEN },
.layout = layout,
.vertex = .{
.module = shader_module.raw,
.entryPoint = .{ .data = "vs_main", .length = wgpu.WGPU_STRLEN },

View file

@ -38,53 +38,55 @@ pub fn init(app: *App) !void {
res.device.queue,
app.alloc,
));
_ = meshes;
_ = pipelines;
// TODO: Remove or place it somewhere else, idk
// --- TEST ---
_ = try pipelines.getOrCreate(.{});
_ = try pipelines.getOrCreate(.{});
// _ = try pipelines.getOrCreatePipeline(.{});
// _ = try pipelines.getOrCreatePipeline(.{});
_ = try pipelines.getOrCreate(.{ .unique = .{ .shader = .unlit } });
_ = try pipelines.getOrCreate(.{ .unique = .{ .shader = .unlit } });
// _ = try pipelines.getOrCreatePipeline(.{ .unique = .{ .shader = .unlit } });
// _ = try pipelines.getOrCreatePipeline(.{ .unique = .{ .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 });
}
// { // 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 });
// }
}
/// ----------------------------------------------------

View file

@ -1,54 +1,5 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const gtl = @import("gtl");
const ShaderID = @import("../../cache/resource/shader_cache.zig").ShaderID;
const Material = @import("../../renderer/template/material.zig");
const Handle = gtl.Handle;
const Self = @This();
/// ----------------------------------------------------
/// ----------------------------------------------------
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 = .{},
value: ?Handle(Self) = null,
value: Handle(Material),

View file

@ -0,0 +1,54 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const gtl = @import("gtl");
const ShaderID = @import("../../cache/resource/shader_cache.zig").ShaderID;
const Handle = gtl.Handle;
const Self = @This();
/// ----------------------------------------------------
/// ----------------------------------------------------
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 = .{},
value: ?Handle(Self) = null,

View file

@ -29,7 +29,7 @@ fn build(
_: *App.plugin.Plugin,
app: *App,
) !void {
try app.schedules.add(App.stage.init, start);
try app.schedules.addAfter(App.stage.init, App.stage.init, start);
}
/// ----------------------------------------------------
@ -44,9 +44,26 @@ fn start(app: *App) !void {
try app.world.spawn(.{
Mesh{ .value = .square },
Material{
.style = .{},
.value = try pipeline_cache.materials.put(.{
.style = .{
.albedo = .{ 0.8, 0.2, 0.2, 1 },
},
.unique = .{},
.value = try pipeline_cache.materials.put(.{}),
}),
},
Transform3D{},
});
// --- # ---
try app.world.spawn(.{
Mesh{ .value = .triangle },
Material{
.value = try pipeline_cache.materials.put(.{
.style = .{
.albedo = .{ 0.2, 0.2, 0.8, 1 },
},
.unique = .{},
}),
},
Transform3D{},
});

View file

@ -16,12 +16,12 @@ const Camera = struct {};
pub const DrawCMD = union(enum) {
draw: struct {
mesh: Mesh,
material: Material,
material: Handle(Material),
},
draw_indexed: struct {
mesh: Mesh,
material: Material,
material: Handle(Material),
},
begin_pass: struct {
@ -79,33 +79,3 @@ pub fn draw(
cmd,
);
}
//
// TESTING
//
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn beginPass(self: *Self) void {
self.draw(.{ .begin_pass = .{
.camera = undefined,
} }) catch unreachable;
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn endPass(self: *Self) void {
self.draw(.end_pass) catch unreachable;
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn drawTriangle(self: *Self) void {
self.draw(.{ .draw = .{ .material = .{}, .mesh = .triangle } }) catch unreachable;
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn drawSquare(self: *Self) void {
self.draw(.{ .draw = .{ .material = .{}, .mesh = .square } }) catch unreachable;
}

View file

@ -1,9 +1,14 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const std = @import("std");
const App = @import("app");
const Renderer = @import("../resource/renderer.zig");
const Mesh = @import("../../common/component/mesh.zig");
const Material = @import("../../common/component/material.zig");
const Transform3D = @import("../../common/component/transform3D.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn begin(app: *App) !void {
@ -15,6 +20,30 @@ pub fn begin(app: *App) !void {
// --- # ---
res.renderer.clear();
// --- DRAW ---
try res.renderer.draw(.{
.begin_pass = .{
.camera = undefined,
.color = .{ 0.001, 0.001, 0.001, 1.0 },
},
});
defer res.renderer.draw(.end_pass) catch unreachable;
// --- QUERY ---
var query = app.world.query(struct {
mesh: *Mesh,
material: *Material,
transform3D: ?*Transform3D,
}, .{});
while (query.next()) |e| {
try res.renderer.draw(.{
.draw = .{
.material = e.material.value,
.mesh = e.mesh.value,
},
});
}
// { // TEST
// // --- DRAW ---
// try res.renderer.draw(.{

View file

@ -9,22 +9,9 @@ const Renderer = @import("../resource/renderer.zig");
/// ----------------------------------------------------
pub fn init(app: *App) !void {
// --- # ---
const zla = app.resources.getPtr(Zla) orelse return error.ZlaNotSet;
// --- # ---
const renderer = try app.resources.getOrSet(Renderer.init(
try app.resources.set(Renderer.init(
app.alloc,
));
// --- REGISTER ---
zla.registerMethods(Renderer, &.{
.{ .name = "beginPass", .func = Renderer.beginPass },
.{ .name = "endPass", .func = Renderer.endPass },
.{ .name = "drawTriangle", .func = Renderer.drawTriangle },
.{ .name = "drawSquare", .func = Renderer.drawSquare },
});
zla.pushUserdata(renderer);
zla.setGlobal("ren");
}
/// ----------------------------------------------------

View file

@ -25,7 +25,6 @@ pub fn draw(app: *App) !void {
});
{ // TODO: Move this | Gather Materials
}
// --- DO NONE ON WINDOW RESIZE ---
@ -121,15 +120,15 @@ pub fn draw(app: *App) !void {
},
.draw => |v| {
// --- ENSURE ---
const pipeline = try res.pipeline_cache.getOrCreate(v.material);
// const material = try res.pipeline_cache.getOrCreateMaterial(v.material);
const material = res.pipeline_cache.materials.get(v.material) orelse return error.MaterialNotFound;
const gpu_material = try res.pipeline_cache.getOrCreateMaterial(v.material);
const pipeline = try res.pipeline_cache.getOrCreatePipeline(material);
const mesh = try res.mesh_cache.getOrCreate(v.mesh);
// _ = material;
// --- BIND ---
wgpu.wgpuRenderPassEncoderSetPipeline(render_pass, pipeline.raw);
wgpu.wgpuRenderPassEncoderSetVertexBuffer(render_pass, 0, mesh.vbuf, 0, wgpu.wgpuBufferGetSize(mesh.vbuf));
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 0, gpu_material.bind_group, 0, null);
// --- DRAW ---
if (mesh.ibuf) |ibuf| {

View file

@ -0,0 +1,53 @@
//! ----------------------------------------------------
//! ----------------------------------------------------
const gtl = @import("gtl");
const ShaderID = @import("../../cache/resource/shader_cache.zig").ShaderID;
const Handle = gtl.Handle;
const Self = @This();
/// ----------------------------------------------------
/// ----------------------------------------------------
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 = .{},