From b03bb1a70a49770494ac0acd3e9e51c942a0ec9e Mon Sep 17 00:00:00 2001 From: abux Date: Fri, 31 Jul 2026 19:25:59 +0100 Subject: [PATCH] Let there be proper shader layouts n stuff \o/ --- build.zig.zon | 4 +- .../cache/resource/embeded/shaders/pbr.wgsl | 83 ----- src/plugins/cache/resource/mesh_cache.zig | 41 +++ .../cache/resource/pipeline_cache.zig.old | 332 ------------------ .../cache/resource/shader_cache.zig.old | 103 ------ src/plugins/common/component/camera.zig | 2 +- src/plugins/common/component/transform3D.zig | 2 +- src/plugins/playground/root.zig | 67 +++- .../resource/embeded/shaders/pbr.wgsl | 25 +- .../renderer/resource/render_layout.zig | 5 + .../renderer/resource/render_world.zig | 5 +- src/plugins/renderer/resource/renderer.zig | 1 + src/plugins/renderer/root.zig | 6 +- src/plugins/renderer/system/frame.zig | 47 +-- src/plugins/renderer/system/lifetime.zig | 80 +++++ src/plugins/renderer/system/prepare.zig | 292 +++++++++------ src/plugins/renderer/system/present.zig | 10 +- .../renderer/template/frame_object.zig | 1 + src/plugins/renderer/template/gpu_camera.zig | 10 +- src/plugins/renderer/template/gpu_object.zig | 10 + .../renderer/template/gpu_pipeline.zig | 1 - 21 files changed, 418 insertions(+), 709 deletions(-) delete mode 100644 src/plugins/cache/resource/embeded/shaders/pbr.wgsl delete mode 100644 src/plugins/cache/resource/pipeline_cache.zig.old delete mode 100644 src/plugins/cache/resource/shader_cache.zig.old create mode 100644 src/plugins/renderer/resource/render_layout.zig create mode 100644 src/plugins/renderer/template/gpu_object.zig diff --git a/build.zig.zon b/build.zig.zon index 5fab478..a37eee2 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -21,8 +21,8 @@ .hash = "gtl-0.0.0-e3QoJMRYAADChgXn2sogTxsbUpEBSHjOGZeoEx4ccMMD", }, .NYXMath = .{ - .url = "git+http://192.168.0.11:25569/abux/NYXMath.git#58d57b61f3fa25e234af1af3e1e56bb656f4d77d", - .hash = "NYXMath-0.0.0-BD6ST8zOAAB1dgmaGKShXtKmGTuYqgiDpAY2faHM_HnV", + .url = "git+http://192.168.0.11:25569/abux/NYXMath.git#cb7b54995bdb46321f112bba2a704d58cf53aeb1", + .hash = "NYXMath-0.0.0-BD6ST9rOAAA0uSpPK_woZrta3nTh0f5w7hFewJ-e2Kv1", }, }, diff --git a/src/plugins/cache/resource/embeded/shaders/pbr.wgsl b/src/plugins/cache/resource/embeded/shaders/pbr.wgsl deleted file mode 100644 index b9dc924..0000000 --- a/src/plugins/cache/resource/embeded/shaders/pbr.wgsl +++ /dev/null @@ -1,83 +0,0 @@ -// ---------------------------------------------------- -// ---------------------------------------------------- -struct VertexInput { - @location(0) position: vec3f, - @location(1) normal: vec3f, - @location(2) uv: vec2f, -}; - -// ---------------------------------------------------- -// ---------------------------------------------------- -struct VertexOutput { - @builtin(position) position: vec4f, - @location(0) uv: vec2f, - @location(1) normal: vec3f, -}; - -// ---------------------------------------------------- -// ---------------------------------------------------- -struct Material { - albedo: vec4f, - metallic: f32, - roughness: f32, - _pad0: vec2f, -}; - -// ---------------------------------------------------- -// ---------------------------------------------------- -struct CameraUniform { - view: mat4x4, - projection: mat4x4, - view_projection: mat4x4, - camera_position: vec3, - _pad: f32, -}; - -// ---------------------------------------------------- -// ---------------------------------------------------- -struct ModelUniform { - model: mat4x4, -}; - -// -// UNIFORMS -// - -@group(0) @binding(0) -var camera: CameraUniform; - -@group(1) @binding(0) -var model: ModelUniform; - -@group(2) @binding(0) -var material: Material; - -// -// VERTEX -// - -@vertex -fn vs_main(in: VertexInput) -> VertexOutput { - // --- # --- - var out: VertexOutput; - - // --- # --- - out.position = vec4f(in.position, 1.0); - out.uv = in.uv; - out.normal = in.normal; - - // --- # --- - return out; -} - -// -// FRAGMENT -// - -@fragment -fn fs_main(out: VertexOutput) -> @location(0) vec4f { - 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); -} diff --git a/src/plugins/cache/resource/mesh_cache.zig b/src/plugins/cache/resource/mesh_cache.zig index a344079..a14501d 100644 --- a/src/plugins/cache/resource/mesh_cache.zig +++ b/src/plugins/cache/resource/mesh_cache.zig @@ -127,6 +127,38 @@ pub fn getOrCreate( }, }, + .cube => &.{ + .{ .position = .{ -0.5, -0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 0, 1 } }, + .{ .position = .{ 0.5, -0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 1, 1 } }, + .{ .position = .{ 0.5, 0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 1, 0 } }, + .{ .position = .{ -0.5, 0.5, 0.5 }, .normal = .{ 0, 0, 1 }, .uv = .{ 0, 0 } }, + + .{ .position = .{ 0.5, -0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 0, 1 } }, + .{ .position = .{ -0.5, -0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 1, 1 } }, + .{ .position = .{ -0.5, 0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 1, 0 } }, + .{ .position = .{ 0.5, 0.5, -0.5 }, .normal = .{ 0, 0, -1 }, .uv = .{ 0, 0 } }, + + .{ .position = .{ -0.5, -0.5, -0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 0, 1 } }, + .{ .position = .{ -0.5, -0.5, 0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 1, 1 } }, + .{ .position = .{ -0.5, 0.5, 0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 1, 0 } }, + .{ .position = .{ -0.5, 0.5, -0.5 }, .normal = .{ -1, 0, 0 }, .uv = .{ 0, 0 } }, + + .{ .position = .{ 0.5, -0.5, 0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 0, 1 } }, + .{ .position = .{ 0.5, -0.5, -0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 1, 1 } }, + .{ .position = .{ 0.5, 0.5, -0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 1, 0 } }, + .{ .position = .{ 0.5, 0.5, 0.5 }, .normal = .{ 1, 0, 0 }, .uv = .{ 0, 0 } }, + + .{ .position = .{ -0.5, 0.5, 0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 0, 1 } }, + .{ .position = .{ 0.5, 0.5, 0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 1, 1 } }, + .{ .position = .{ 0.5, 0.5, -0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 1, 0 } }, + .{ .position = .{ -0.5, 0.5, -0.5 }, .normal = .{ 0, 1, 0 }, .uv = .{ 0, 0 } }, + + .{ .position = .{ -0.5, -0.5, -0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 0, 1 } }, + .{ .position = .{ 0.5, -0.5, -0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 1, 1 } }, + .{ .position = .{ 0.5, -0.5, 0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 1, 0 } }, + .{ .position = .{ -0.5, -0.5, 0.5 }, .normal = .{ 0, -1, 0 }, .uv = .{ 0, 0 } }, + }, + else => &.{}, }; @@ -141,6 +173,15 @@ pub fn getOrCreate( 0, 1, 2, }, + .cube => &.{ + 0, 1, 2, 0, 2, 3, + 4, 5, 6, 4, 6, 7, + 8, 9, 10, 8, 10, 11, + 12, 13, 14, 12, 14, 15, + 16, 17, 18, 16, 18, 19, + 20, 21, 22, 20, 22, 23, + }, + else => &.{}, }; diff --git a/src/plugins/cache/resource/pipeline_cache.zig.old b/src/plugins/cache/resource/pipeline_cache.zig.old deleted file mode 100644 index 57a377d..0000000 --- a/src/plugins/cache/resource/pipeline_cache.zig.old +++ /dev/null @@ -1,332 +0,0 @@ -//! ---------------------------------------------------- -//! TODO: Move [materials, materials_gpu and GPUMaterial somewhere else] -//! Depricated -//! ---------------------------------------------------- - -const std = @import("std"); -const gtl = @import("gtl"); -const wgpu = @import("wgpu"); -const Self = @This(); - -const Material = @import("../../renderer/template/material.zig"); -const ShaderCache = @import("shader_cache.zig"); -const ShaderID = ShaderCache.ShaderID; -const Vertex = @import("mesh_cache.zig").Vertex; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub const GPUPipeline = struct { - raw: *wgpu.WGPURenderPipelineImpl, - layout: *wgpu.WGPUPipelineLayoutImpl, - bind_group_layouts: [3]*wgpu.WGPUBindGroupLayoutImpl, -}; - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub const GPUMaterial = struct { - buffer: *wgpu.WGPUBufferImpl, - bind_group: *wgpu.WGPUBindGroupImpl, - dirty: bool = true, -}; - -/// ---------------------------------------------------- -/// TODO: Mabe mabe switch to it, someday -/// ---------------------------------------------------- -pub const GPUUniform = struct { - buffer: wgpu.WGPUBuffer, - bind_group: wgpu.WGPUBindGroup, - dirty: bool = true, -}; - -// -// FIELDS -// - -pipelines: gtl.KeyedSlotMap(Material.Unique, GPUPipeline), -materials: gtl.SlotMap(Material), -materials_gpu: gtl.KeyedSlotMap(gtl.Handle(Material), GPUMaterial), -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), - .materials = .init(alloc), - .materials_gpu = .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.wgpuPipelineLayoutRelease(entry.value.layout); - wgpu.wgpuRenderPipelineRelease(entry.value.raw); - } - - // --- FREE MATERIALS --- - for (self.materials_gpu.items()) |entry| { - wgpu.wgpuBufferRelease(entry.value.buffer); - wgpu.wgpuBindGroupRelease(entry.value.bind_group); - } - - // --- # --- - self.pipelines.deinit(); - self.materials.deinit(); - self.materials_gpu.deinit(); -} - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub fn getOrCreateMaterial( - self: *Self, - material_handle: gtl.Handle(Material), -) !*GPUMaterial { - 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, - 0, - &material.style, - @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 .{ - .buffer = uniform, - .bind_group = bind_group, - .dirty = false, - }; - }, - ); -} - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -pub fn getOrCreatePipeline( - self: *Self, - material: *const Material, -) !*GPUPipeline { - return try self.pipelines.getOrPut(material.unique, blk: { - // --- # --- - if (self.pipelines.getByKey(material.unique)) |v| return v; - - // - // LAYOUTS - // - - // --- CAMERA --- - const camera_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; - - // --- MODEL --- - const model_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; - - // --- MATERIAL --- - 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; - - var bind_group_layouts = [_]wgpu.WGPUBindGroupLayout{ - camera_layout, - model_layout, - material_layout, - }; - - // --- PIPELINE LAYOUT --- - const pipeline_layout = wgpu.wgpuDeviceCreatePipelineLayout( - self.device, - &wgpu.WGPUPipelineLayoutDescriptor{ - .bindGroupLayoutCount = 3, - .bindGroupLayouts = &bind_group_layouts, - }, - ) orelse return error.Layout; - - // --- CREATE PIPELINE --- - const pipeline = try self.createPipeline( - material.unique, - pipeline_layout, - ); - - // --- RESULT --- - break :blk .{ - .raw = pipeline, - .layout = pipeline_layout, - .bind_group_layouts = .{ - camera_layout, - model_layout, - material_layout, - }, - }; - }); -} - -/// ---------------------------------------------------- -/// ---------------------------------------------------- -fn createPipeline( - self: *Self, - key: Material.Unique, - layout: *wgpu.WGPUPipelineLayoutImpl, -) !*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 }, - .layout = layout, - .vertex = .{ - .module = shader_module.raw, - .entryPoint = .{ .data = "vs_main", .length = wgpu.WGPU_STRLEN }, - .bufferCount = 1, - .buffers = &wgpu.WGPUVertexBufferLayout{ - .attributeCount = 3, - .attributes = &[_]wgpu.WGPUVertexAttribute{ // TODO: Mabe mabe allow for custom, mabe mabe later tho - .{ - .format = wgpu.WGPUVertexFormat_Float32x3, - .offset = @offsetOf(Vertex, "position"), - .shaderLocation = 0, - }, - .{ - .format = wgpu.WGPUVertexFormat_Float32x3, - .offset = @offsetOf(Vertex, "normal"), - .shaderLocation = 1, - }, - .{ - .format = wgpu.WGPUVertexFormat_Float32x2, - .offset = @offsetOf(Vertex, "uv"), - .shaderLocation = 2, - }, - }, - .arrayStride = @sizeOf(Vertex), - .stepMode = wgpu.WGPUVertexStepMode_Vertex, - }, - }, - .fragment = &wgpu.WGPUFragmentState{ - .module = shader_module.raw, - .entryPoint = .{ .data = "fs_main", .length = wgpu.WGPU_STRLEN }, - .targetCount = 1, - .targets = &wgpu.WGPUColorTargetState{ - .format = 28, // FIX: Use proper format - .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; - }; -} diff --git a/src/plugins/cache/resource/shader_cache.zig.old b/src/plugins/cache/resource/shader_cache.zig.old deleted file mode 100644 index 3fd5e3c..0000000 --- a/src/plugins/cache/resource/shader_cache.zig.old +++ /dev/null @@ -1,103 +0,0 @@ -//! ---------------------------------------------------- -//! ---------------------------------------------------- - -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; - }; -} diff --git a/src/plugins/common/component/camera.zig b/src/plugins/common/component/camera.zig index c8eb186..260c265 100644 --- a/src/plugins/common/component/camera.zig +++ b/src/plugins/common/component/camera.zig @@ -11,7 +11,7 @@ projection: union(enum) { far: f32 = 4000.0, near: f32 = 0.05, }, -} = .{ .ortho = .{} }, +}, target: union(enum) { window, diff --git a/src/plugins/common/component/transform3D.zig b/src/plugins/common/component/transform3D.zig index 23cb847..a982495 100644 --- a/src/plugins/common/component/transform3D.zig +++ b/src/plugins/common/component/transform3D.zig @@ -2,4 +2,4 @@ const math = @import("math"); position: math.Vec3f = .as(0), rotation: math.Quat = .identity(), -scale: math.Vec3f = .as(0), +scale: math.Vec3f = .as(1), diff --git a/src/plugins/playground/root.zig b/src/plugins/playground/root.zig index 78c7baa..a928845 100644 --- a/src/plugins/playground/root.zig +++ b/src/plugins/playground/root.zig @@ -5,6 +5,7 @@ // PRIVATE // +const std = @import("std"); const App = @import("app"); const Camera = @import("../common/component/camera.zig"); @@ -34,6 +35,8 @@ fn build( try app.schedules.addAfter(App.stage.init, App.stage.init, start); } +const FlyCamera = struct {}; + /// ---------------------------------------------------- /// ---------------------------------------------------- fn start(app: *App) !void { @@ -44,36 +47,68 @@ fn start(app: *App) !void { // --- CAMERA --- try app.world.spawn(.{ - Camera{}, - Transform3D{}, + FlyCamera{}, + Camera{ + .projection = .{ + .perspective = .{}, + }, + }, + Transform3D{ + .position = .new(.{ 0, -2.5, -6.5 }), + .rotation = .fromEuler(.init( + -std.math.degreesToRadians(30), + 0, + 0, + )), + }, }); // --- # --- try app.world.spawn(.{ - Mesh{ .value = .square }, + Mesh{ .value = .cube }, Material{ .value = try render_world.materials.put(.{ .style = .{ .albedo = .{ 0.8, 0.2, 0.2, 1.0 }, }, .unique = .{ - .topology = .line_list, + .cull_mode = .none, }, }), }, Transform3D{}, }); - // --- # --- - try app.world.spawn(.{ - Mesh{ .value = .triangle }, - Material{ - .value = try render_world.materials.put(.{ - .style = .{ - .albedo = .{ 0.2, 0.2, 0.8, 1 }, - }, - }), - }, - Transform3D{}, - }); + const count: usize = 100; + const radius: f32 = 5.0; + + for (0..count) |i| { + const angle = (@as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(count))) * std.math.tau; + + try app.world.spawn(.{ + Mesh{ .value = .cube }, + Material{ + .value = try render_world.materials.put(.{ + .style = .{ + .albedo = .{ 0.2, 0.2, 0.8, 1 }, + }, + .unique = .{ + .cull_mode = .none, + }, + }), + }, + Transform3D{ + .position = .new(.{ + @cos(angle) * radius, + 0, + @sin(angle) * radius, + }), + .rotation = .fromEuler(.init( + std.math.degreesToRadians(180), + 0, + 0, + )), + }, + }); + } } diff --git a/src/plugins/renderer/resource/embeded/shaders/pbr.wgsl b/src/plugins/renderer/resource/embeded/shaders/pbr.wgsl index b9dc924..cb094f9 100644 --- a/src/plugins/renderer/resource/embeded/shaders/pbr.wgsl +++ b/src/plugins/renderer/resource/embeded/shaders/pbr.wgsl @@ -14,29 +14,26 @@ struct VertexOutput { @location(1) normal: vec3f, }; -// ---------------------------------------------------- -// ---------------------------------------------------- -struct Material { - albedo: vec4f, - metallic: f32, - roughness: f32, - _pad0: vec2f, -}; - // ---------------------------------------------------- // ---------------------------------------------------- struct CameraUniform { view: mat4x4, projection: mat4x4, - view_projection: mat4x4, - camera_position: vec3, - _pad: f32, }; // ---------------------------------------------------- // ---------------------------------------------------- struct ModelUniform { - model: mat4x4, + data: mat4x4, +}; + +// ---------------------------------------------------- +// ---------------------------------------------------- +struct Material { + albedo: vec4f, + metallic: f32, + roughness: f32, + _pad0: vec2f, }; // @@ -62,7 +59,7 @@ fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; // --- # --- - out.position = vec4f(in.position, 1.0); + out.position = camera.projection * camera.view * model.data * vec4f(in.position, 1.0); out.uv = in.uv; out.normal = in.normal; diff --git a/src/plugins/renderer/resource/render_layout.zig b/src/plugins/renderer/resource/render_layout.zig new file mode 100644 index 0000000..8eec691 --- /dev/null +++ b/src/plugins/renderer/resource/render_layout.zig @@ -0,0 +1,5 @@ +const wgpu = @import("wgpu"); + +camera: *wgpu.WGPUBindGroupLayoutImpl, +model: *wgpu.WGPUBindGroupLayoutImpl, +material: *wgpu.WGPUBindGroupLayoutImpl, diff --git a/src/plugins/renderer/resource/render_world.zig b/src/plugins/renderer/resource/render_world.zig index fb625ac..e347288 100644 --- a/src/plugins/renderer/resource/render_world.zig +++ b/src/plugins/renderer/resource/render_world.zig @@ -5,6 +5,7 @@ const std = @import("std"); const gtl = @import("gtl"); const wgpu = @import("wgpu"); +pub const Entity = u64; // TODO: You lazy retard // --- CAMERA --- pub const GPUCamera = @import("../template/gpu_camera.zig"); @@ -23,7 +24,8 @@ pub const Pipeline = Material.Unique; pub const GPUPipeline = @import("../template/gpu_pipeline.zig"); // --- OBJECT --- -pub const Entity = u64; // TODO: You lazy retard +pub const MeshID = @import("../../cache/resource/mesh_cache.zig").MeshID; +pub const GPUObject = @import("../template/gpu_object.zig"); pub const FrameObject = @import("../template/frame_object.zig"); // @@ -38,6 +40,7 @@ pub const UnlitCode = @embedFile("embeded/shaders/pbr.wgsl"); // gpu_cameras: gtl.KeyedSlotMap(Entity, GPUCamera), +gpu_objects: gtl.KeyedSlotMap(Entity, GPUObject), gpu_shaders: gtl.KeyedSlotMap(ShaderID, GPUShader), gpu_pipelines: gtl.KeyedSlotMap(Pipeline, GPUPipeline), gpu_materials: gtl.KeyedSlotMap(gtl.Handle(Material), GPUMaterial), diff --git a/src/plugins/renderer/resource/renderer.zig b/src/plugins/renderer/resource/renderer.zig index 7159454..8d45051 100644 --- a/src/plugins/renderer/resource/renderer.zig +++ b/src/plugins/renderer/resource/renderer.zig @@ -16,6 +16,7 @@ const Camera = struct {}; pub const DrawCMD = union(enum) { draw: struct { mesh: Mesh, + entity: u64, material: Handle(Material), }, diff --git a/src/plugins/renderer/root.zig b/src/plugins/renderer/root.zig index f021bd1..85c44f8 100644 --- a/src/plugins/renderer/root.zig +++ b/src/plugins/renderer/root.zig @@ -17,6 +17,8 @@ const present = @import("system/present.zig"); // const Renderer = @import("resource/renderer.zig"); +const RenderWorld = @import("resource/render_world.zig"); +const RenderLayout = @import("resource/render_layout.zig"); /// ---------------------------------------------------- /// ---------------------------------------------------- @@ -41,9 +43,11 @@ fn build( // --- PRE DRAW --- try app.schedules.addManyBefore(App.stage.draw, App.stage.draw, &.{ - prepare.cameras, prepare.shaders, prepare.pipelines, + + prepare.cameras, + prepare.objects, prepare.materials, }); diff --git a/src/plugins/renderer/system/frame.zig b/src/plugins/renderer/system/frame.zig index e2c0e3b..c011e33 100644 --- a/src/plugins/renderer/system/frame.zig +++ b/src/plugins/renderer/system/frame.zig @@ -22,7 +22,7 @@ pub fn begin(app: *App) !void { // --- # --- res.renderer.clear(); - // --- DRAW --- + // --- # --- for (res.render_world.frame_views.items) |view| { // --- NEW PASS --- try res.renderer.draw(.{ @@ -33,11 +33,12 @@ pub fn begin(app: *App) !void { }); defer res.renderer.draw(.end_pass) catch unreachable; - // --- # --- + // --- DRAW --- for (res.render_world.frame_objects.items) |obj| { try res.renderer.draw(.{ .draw = .{ .material = obj.material, + .entity = obj.entity, .mesh = obj.mesh, }, }); @@ -47,48 +48,6 @@ pub fn begin(app: *App) !void { // --- YES --- res.render_world.frame_views.clearRetainingCapacity(); res.render_world.frame_objects.clearRetainingCapacity(); - - // { // TEST - // // --- 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; - // - // // --- # --- - // try res.renderer.draw(.{ - // .draw = .{ - // .mesh = .square, - // .material = .{ - // .style = .{ - // .albedo = .{ 0.2, 0.8, 0.2, 1.0 }, - // }, - // }, - // }, - // }); - // } - // - // { // TEST - // // --- DRAW --- - // try res.renderer.draw(.{ - // .begin_pass = .{ - // .camera = undefined, - // .load_op = .load, - // }, - // }); - // defer res.renderer.draw(.end_pass) catch unreachable; - // - // // --- # --- - // try res.renderer.draw(.{ - // .draw = .{ - // .mesh = .triangle, - // .material = .{}, - // }, - // }); - // } } /// ---------------------------------------------------- diff --git a/src/plugins/renderer/system/lifetime.zig b/src/plugins/renderer/system/lifetime.zig index 7212f0a..e4f8e66 100644 --- a/src/plugins/renderer/system/lifetime.zig +++ b/src/plugins/renderer/system/lifetime.zig @@ -5,12 +5,24 @@ const wgpu = @import("wgpu"); const App = @import("app"); const Zla = @import("zla"); +const WGPUDevice = @import("../../device/resource/wgpu_device.zig"); const Renderer = @import("../resource/renderer.zig"); const RenderWorld = @import("../resource/render_world.zig"); +const RenderLayout = @import("../resource/render_layout.zig"); + +// --- TEMPLATES --- +const TMaterial = @import("../template/material.zig"); +const TCamera = @import("../template/gpu_camera.zig"); +const TMesh = @import("../template/gpu_object.zig"); /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn init(app: *App) !void { + // --- # --- + const res = try app.resources.getMany(struct { + device: *WGPUDevice, + }); + // --- # --- try app.resources.set(Renderer.init( app.alloc, @@ -19,6 +31,7 @@ pub fn init(app: *App) !void { // --- # --- try app.resources.set(RenderWorld{ .gpu_cameras = .init(app.alloc), + .gpu_objects = .init(app.alloc), .gpu_shaders = .init(app.alloc), .gpu_materials = .init(app.alloc), .gpu_pipelines = .init(app.alloc), @@ -28,6 +41,54 @@ pub fn init(app: *App) !void { .materials = .init(app.alloc), }); + + // --- # --- + try app.resources.set(RenderLayout{ + .camera = wgpu.wgpuDeviceCreateBindGroupLayout(res.device.raw, &wgpu.WGPUBindGroupLayoutDescriptor{ + .entryCount = 1, + .entries = &[_]wgpu.WGPUBindGroupLayoutEntry{ + .{ + .binding = 0, + .visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment, + .buffer = .{ + .type = wgpu.WGPUBufferBindingType_Uniform, + .minBindingSize = @sizeOf(TCamera.Uniform), + .hasDynamicOffset = 0, + }, + }, + }, + }) orelse return error.CameraBindGroupLayout, + + .model = wgpu.wgpuDeviceCreateBindGroupLayout(res.device.raw, &wgpu.WGPUBindGroupLayoutDescriptor{ + .entryCount = 1, + .entries = &[_]wgpu.WGPUBindGroupLayoutEntry{ + .{ + .binding = 0, + .visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment, + .buffer = .{ + .type = wgpu.WGPUBufferBindingType_Uniform, + .minBindingSize = @sizeOf(TMesh.Uniform), + .hasDynamicOffset = 0, + }, + }, + }, + }) orelse return error.ModelBindGroupLayout, + + .material = wgpu.wgpuDeviceCreateBindGroupLayout(res.device.raw, &wgpu.WGPUBindGroupLayoutDescriptor{ + .entryCount = 1, + .entries = &[_]wgpu.WGPUBindGroupLayoutEntry{ + .{ + .binding = 0, + .visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment, + .buffer = .{ + .type = wgpu.WGPUBufferBindingType_Uniform, + .minBindingSize = @sizeOf(TMaterial.Style), + .hasDynamicOffset = 0, + }, + }, + }, + }) orelse return error.MaterialBindGroupLayout, + }); } /// ---------------------------------------------------- @@ -37,6 +98,7 @@ pub fn deinit(app: *App) !void { const res = try app.resources.getMany(struct { ren: *Renderer, ren_world: *RenderWorld, + ren_layout: *RenderLayout, }); // --- FREE SHADERS --- @@ -56,11 +118,29 @@ pub fn deinit(app: *App) !void { wgpu.wgpuBindGroupRelease(entry.value.bind_group); } + // --- FREE CAMERAS --- + for (res.ren_world.gpu_cameras.items()) |entry| { + wgpu.wgpuBufferRelease(entry.value.buffer); + wgpu.wgpuBindGroupRelease(entry.value.bind_group); + } + + // --- FREE OBJECTS --- + for (res.ren_world.gpu_objects.items()) |entry| { + wgpu.wgpuBufferRelease(entry.value.buffer); + wgpu.wgpuBindGroupRelease(entry.value.bind_group); + } + + // --- FREE LAYOUTS --- + wgpu.wgpuBindGroupLayoutRelease(res.ren_layout.camera); + wgpu.wgpuBindGroupLayoutRelease(res.ren_layout.model); + wgpu.wgpuBindGroupLayoutRelease(res.ren_layout.material); + // --- # --- res.ren_world.materials.deinit(); res.ren_world.frame_views.deinit(app.alloc); res.ren_world.frame_objects.deinit(app.alloc); res.ren_world.gpu_cameras.deinit(); + res.ren_world.gpu_objects.deinit(); res.ren_world.gpu_shaders.deinit(); res.ren_world.gpu_materials.deinit(); res.ren_world.gpu_pipelines.deinit(); diff --git a/src/plugins/renderer/system/prepare.zig b/src/plugins/renderer/system/prepare.zig index 6113afd..cbc1c37 100644 --- a/src/plugins/renderer/system/prepare.zig +++ b/src/plugins/renderer/system/prepare.zig @@ -3,6 +3,7 @@ // --- # --- const std = @import("std"); +const math = @import("math"); const wgpu = @import("wgpu"); const App = @import("app"); const Zla = @import("zla"); @@ -11,6 +12,7 @@ const Zla = @import("zla"); const Vertex = @import("../../cache/resource/mesh_cache.zig").Vertex; const WGPUDevice = @import("../../device/resource/wgpu_device.zig"); const RenderWorld = @import("../resource/render_world.zig"); +const RenderLayout = @import("../resource/render_layout.zig"); // --- # --- const Transform2D = @import("../../common/component/transform2D.zig"); @@ -18,6 +20,7 @@ const Transform3D = @import("../../common/component/transform3D.zig"); // --- MESH --- const CMesh = @import("../../common/component/mesh.zig"); +const TMesh = @import("../template/gpu_object.zig"); // --- MATERIAL --- const CMaterial = @import("../../common/component/material.zig"); @@ -33,55 +36,180 @@ pub fn cameras(app: *App) !void { // --- # --- const res = try app.resources.getMany(struct { render_world: *RenderWorld, + render_layout: *RenderLayout, + device: *WGPUDevice, }); - { - // --- # --- - var query = app.world.query(struct { - camera: *const CCamera, - }, .{}); - while (query.next()) |e| { - // --- GPU --- - const raw = try res.render_world.gpu_cameras.getOrPut(query.entity(), blk: { - if (res.render_world.gpu_cameras.getByKey(query.entity())) |v| break :blk v.*; + // --- # --- + var query = app.world.query(struct { + camera: *const CCamera, + transform2D: ?*const Transform2D, + transform3D: ?*const Transform3D, + }, .{}); + while (query.next()) |e| { + // --- GPU --- + const raw = try res.render_world.gpu_cameras.getOrPut(query.entity(), blk: { + // --- # --- + if (res.render_world.gpu_cameras.getByKey( + query.entity(), + )) |v| break :blk v.*; - break :blk .{ - .projection = switch (e.camera.projection) { - .perspective => |v| .perspective(v.fov, 800.0 / 600.0, v.near, v.far), - .ortho => |v| .orthographic(800, 0, 600, 0, v.near, v.far), - }, - }; - }); + // --- UNIFORM --- + const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{ + .usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform, + .size = @sizeOf(TCamera.Uniform), + }) orelse return error.Buffer; - // --- FRAME --- - try res.render_world.frame_views.append(app.alloc, .{ - .order = e.camera.order, - .priority = e.camera.priority, - .camera = query.entity(), - .raw = raw, - }); - } - } + // --- VIEW --- + const view: math.Mat4x4 = if (e.transform3D) |t3| cmp: { // 3D + const eye = t3.position; + const forward = t3.rotation.rotate(math.Vec3f.new(.{ 0, 0, 1 })); + const up = t3.rotation.rotate(math.Vec3f.new(.{ 0, 1, 0 })); + break :cmp math.Mat4x4.lookAt(eye, eye.add(forward), up); + } else if (e.transform2D) |t2| cmp: { // 2D + const eye: math.Vec3f = .new(.{ t2.position.value[0], t2.position.value[1], 0 }); + break :cmp math.Mat4x4.rotateZ(-t2.angle) + .mul(math.Mat4x4.translate(-eye.value[0], -eye.value[1], 0)); + } else math.Mat4x4.identity(); - { - // --- # --- - var query = app.world.query(struct { - mesh: *const CMesh, - material: *const CMaterial, - transform2D: ?*const Transform2D, - transform3D: ?*const Transform3D, - }, .{}); - while (query.next()) |e| { - try res.render_world.frame_objects.append(app.alloc, .{ - .mesh = e.mesh.value, - .material = e.material.value, - .transform = blk: { - if (e.transform2D) |v| break :blk .{ .@"2D" = v.* }; - if (e.transform3D) |v| break :blk .{ .@"3D" = v.* }; - break :blk .{ .@"2D" = .{} }; + // --- PROJECTION --- + const projection: math.Mat4x4 = switch (e.camera.projection) { + .perspective => |v| .perspective(std.math.degreesToRadians(v.fov), 800.0 / 600.0, v.near, v.far), + .ortho => |v| .orthographic(800.0, 0, 600.0, 0, v.near, v.far), + }; + + // --- WRITE TO UNIFORM --- + wgpu.wgpuQueueWriteBuffer( + res.device.queue, + uniform, + 0, + &TCamera.Uniform{ + .view = view.transpose(), + .projection = projection.transpose(), }, - }); - } + @sizeOf(TCamera.Uniform), + ); + + // --- BIND GROUP --- + const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{ + .layout = res.render_layout.camera, + .entryCount = 1, + .entries = &[_]wgpu.WGPUBindGroupEntry{ + .{ + .binding = 0, + .buffer = uniform, + .offset = 0, + .size = @sizeOf(TCamera.Uniform), + }, + }, + }) orelse return error.BindGroup; + + break :blk .{ + .buffer = uniform, + .bind_group = bind_group, + .dirty = false, + }; + }); + + // --- FRAME --- + try res.render_world.frame_views.append(app.alloc, .{ + .order = e.camera.order, + .priority = e.camera.priority, + .camera = query.entity(), + .raw = raw, + }); + } +} + +/// ---------------------------------------------------- +/// ---------------------------------------------------- +pub fn objects(app: *App) !void { + // --- # --- + const res = try app.resources.getMany(struct { + render_world: *RenderWorld, + render_layout: *RenderLayout, + device: *WGPUDevice, + }); + + // --- # --- + var query = app.world.query(struct { + mesh: *const CMesh, + material: *const CMaterial, + transform2D: ?*const Transform2D, + transform3D: ?*const Transform3D, + }, .{}); + while (query.next()) |e| { + // --- ENSURE TRANSFORM --- + if (e.transform2D == null and + e.transform3D == null) continue; + + // --- GPU --- + _ = try res.render_world.gpu_objects.getOrPut(query.entity(), blk: { + // --- # --- + if (res.render_world.gpu_objects.getByKey( + query.entity(), + )) |v| break :blk v.*; + + // --- UNIFORM --- + const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{ + .usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform, + .size = @sizeOf(TMesh.Uniform), + }) orelse return error.Buffer; + + // --- MODEL --- + const pos: math.Vec3f = e.transform3D.?.position; + const scl: math.Vec3f = e.transform3D.?.scale; + const rot: math.Quat = e.transform3D.?.rotation; + + // --- FINAL MODEL --- + const model = + math.Mat4x4.translate(pos.value[0], pos.value[1], pos.value[2]) + .mul(rot.toMat4()) + .mul(math.Mat4x4.scale(scl.value[0], scl.value[1], scl.value[2])); + + // --- WRITE TO UNIFORM --- + wgpu.wgpuQueueWriteBuffer( + res.device.queue, + uniform, + 0, + &TMesh.Uniform{ + .data = model.transpose(), + }, + @sizeOf(TMesh.Uniform), + ); + + // --- BIND GROUP --- + const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{ + .layout = res.render_layout.model, + .entryCount = 1, + .entries = &[_]wgpu.WGPUBindGroupEntry{ + .{ + .binding = 0, + .buffer = uniform, + .offset = 0, + .size = @sizeOf(TMesh.Uniform), + }, + }, + }) orelse return error.BindGroup; + + break :blk .{ + .buffer = uniform, + .bind_group = bind_group, + .dirty = false, + }; + }); + + // --- FRAME --- + try res.render_world.frame_objects.append(app.alloc, .{ + .mesh = e.mesh.value, + .entity = query.entity(), + .material = e.material.value, + .transform = blk: { + if (e.transform2D) |v| break :blk .{ .@"2D" = v.* }; + if (e.transform3D) |v| break :blk .{ .@"3D" = v.* }; + break :blk .{ .@"2D" = .{} }; + }, + }); } } @@ -143,6 +271,7 @@ pub fn pipelines(app: *App) !void { // --- # --- const res = try app.resources.getMany(struct { render_world: *RenderWorld, + render_layout: *RenderLayout, device: *WGPUDevice, }); @@ -163,62 +292,11 @@ pub fn pipelines(app: *App) !void { material.unique, )) return; - // - // LAYOUTS - // - - // --- CAMERA --- - const camera_layout = wgpu.wgpuDeviceCreateBindGroupLayout(res.device.raw, &wgpu.WGPUBindGroupLayoutDescriptor{ - .entryCount = 1, - .entries = &[_]wgpu.WGPUBindGroupLayoutEntry{ - .{ - .binding = 0, - .visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment, - .buffer = .{ - .type = wgpu.WGPUBufferBindingType_Uniform, - .minBindingSize = @sizeOf(TMaterial.Style), - .hasDynamicOffset = 0, - }, - }, - }, - }) orelse return error.BindGroupLayout; - - // --- MODEL --- - const model_layout = wgpu.wgpuDeviceCreateBindGroupLayout(res.device.raw, &wgpu.WGPUBindGroupLayoutDescriptor{ - .entryCount = 1, - .entries = &[_]wgpu.WGPUBindGroupLayoutEntry{ - .{ - .binding = 0, - .visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment, - .buffer = .{ - .type = wgpu.WGPUBufferBindingType_Uniform, - .minBindingSize = @sizeOf(TMaterial.Style), - .hasDynamicOffset = 0, - }, - }, - }, - }) orelse return error.BindGroupLayout; - - // --- MATERIAL --- - const material_layout = wgpu.wgpuDeviceCreateBindGroupLayout(res.device.raw, &wgpu.WGPUBindGroupLayoutDescriptor{ - .entryCount = 1, - .entries = &[_]wgpu.WGPUBindGroupLayoutEntry{ - .{ - .binding = 0, - .visibility = wgpu.WGPUShaderStage_Vertex | wgpu.WGPUShaderStage_Fragment, - .buffer = .{ - .type = wgpu.WGPUBufferBindingType_Uniform, - .minBindingSize = @sizeOf(TMaterial.Style), - .hasDynamicOffset = 0, - }, - }, - }, - }) orelse return error.BindGroupLayout; - + // --- LAYOUT --- var bind_group_layouts = [_]wgpu.WGPUBindGroupLayout{ - camera_layout, - model_layout, - material_layout, + res.render_layout.camera, + res.render_layout.model, + res.render_layout.material, }; // --- PIPELINE LAYOUT --- @@ -234,7 +312,9 @@ pub fn pipelines(app: *App) !void { const pipeline = try createPipeline( material.unique, pipeline_layout, - if (res.render_world.gpu_shaders.getByKey(material.unique.shader)) |v| v.raw else return error.ShaderNotFound, + if (res.render_world.gpu_shaders.getByKey( + material.unique.shader, + )) |v| v.raw else return error.ShaderNotFound, res.device.raw, ); @@ -242,11 +322,6 @@ pub fn pipelines(app: *App) !void { break :blk .{ .raw = pipeline, .layout = pipeline_layout, - .bind_group_layouts = .{ - camera_layout, - model_layout, - material_layout, - }, }; }); } @@ -258,6 +333,7 @@ pub fn materials(app: *App) !void { // --- # --- const res = try app.resources.getMany(struct { render_world: *RenderWorld, + render_layout: *RenderLayout, device: *WGPUDevice, }); @@ -276,8 +352,9 @@ pub fn materials(app: *App) !void { )) return; // --- # --- - const material = res.render_world.materials.get(e.material.value) orelse return error.MaterialNotFound; - const pipeline = res.render_world.gpu_pipelines.getByKey(material.unique) orelse return error.PipelineNotFound; + const material = res.render_world.materials.get( + e.material.value, + ) orelse return error.MaterialNotFound; // --- UNIFORM --- const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{ @@ -296,7 +373,7 @@ pub fn materials(app: *App) !void { // --- BIND GROUP --- const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{ - .layout = pipeline.bind_group_layouts[0], + .layout = res.render_layout.material, .entryCount = 1, .entries = &[_]wgpu.WGPUBindGroupEntry{ .{ @@ -399,6 +476,7 @@ fn createPipeline( .mask = ~@as(u32, 0), .alphaToCoverageEnabled = 0, }, + .depthStencil = null, }) orelse { return error.PipelineCreationFailed; }; diff --git a/src/plugins/renderer/system/present.zig b/src/plugins/renderer/system/present.zig index 8abbdd5..a90a9df 100644 --- a/src/plugins/renderer/system/present.zig +++ b/src/plugins/renderer/system/present.zig @@ -71,6 +71,7 @@ pub fn draw(app: *App) !void { // --- FRAME --- var render_pass: ?*wgpu.WGPURenderPassEncoderImpl = null; + var camera: ?u64 = null; for (res.renderer.commands.items) |cmd| { switch (cmd) { @@ -107,6 +108,9 @@ pub fn draw(app: *App) !void { }, }, ); + + // --- SET CAMERA --- + camera = v.camera; }, .end_pass => { if (render_pass) |rp| { @@ -119,7 +123,9 @@ pub fn draw(app: *App) !void { // --- ENSURE --- const material = res.render_world.materials.get(v.material) orelse return error.MaterialNotFound; const gpu_material = res.render_world.gpu_materials.getByKey(v.material) orelse return error.GPUMaterialNotFound; + const gpu_camera = res.render_world.gpu_cameras.getByKey(camera orelse return error.CameraNotSet) orelse return error.GPUCameraNotFound; const pipeline = res.render_world.gpu_pipelines.getByKey(material.unique) orelse return error.GPUPipelineNotFound; + const gpu_mesh = res.render_world.gpu_objects.getByKey(v.entity) orelse return error.GPUMeshNotFound; const mesh = try res.mesh_cache.getOrCreate(v.mesh); // --- BIND --- @@ -127,8 +133,8 @@ pub fn draw(app: *App) !void { wgpu.wgpuRenderPassEncoderSetVertexBuffer(render_pass, 0, mesh.vbuf, 0, wgpu.wgpuBufferGetSize(mesh.vbuf)); // --- BIND SHADER GROUPS --- - wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 0, gpu_material.bind_group, 0, null); - wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 1, gpu_material.bind_group, 0, null); + wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 0, gpu_camera.bind_group, 0, null); + wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 1, gpu_mesh.bind_group, 0, null); wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 2, gpu_material.bind_group, 0, null); // --- DRAW --- diff --git a/src/plugins/renderer/template/frame_object.zig b/src/plugins/renderer/template/frame_object.zig index c89a3be..84e5571 100644 --- a/src/plugins/renderer/template/frame_object.zig +++ b/src/plugins/renderer/template/frame_object.zig @@ -13,6 +13,7 @@ const Handle = gtl.Handle; // mesh: MeshID, +entity: u64, // TODO: Change to Entity type material: Handle(Material), transform: union(enum) { @"2D": Transform2D, diff --git a/src/plugins/renderer/template/gpu_camera.zig b/src/plugins/renderer/template/gpu_camera.zig index 5ec6048..640842b 100644 --- a/src/plugins/renderer/template/gpu_camera.zig +++ b/src/plugins/renderer/template/gpu_camera.zig @@ -1,3 +1,11 @@ +const wgpu = @import("wgpu"); const math = @import("math"); -projection: math.Mat4x4, +pub const Uniform = struct { + view: math.Mat4x4, + projection: math.Mat4x4, +}; + +buffer: *wgpu.WGPUBufferImpl, +bind_group: *wgpu.WGPUBindGroupImpl, +dirty: bool = true, diff --git a/src/plugins/renderer/template/gpu_object.zig b/src/plugins/renderer/template/gpu_object.zig new file mode 100644 index 0000000..6d54f5f --- /dev/null +++ b/src/plugins/renderer/template/gpu_object.zig @@ -0,0 +1,10 @@ +const wgpu = @import("wgpu"); +const math = @import("math"); + +pub const Uniform = struct { + data: math.Mat4x4, +}; + +buffer: *wgpu.WGPUBufferImpl, +bind_group: *wgpu.WGPUBindGroupImpl, +dirty: bool = true, diff --git a/src/plugins/renderer/template/gpu_pipeline.zig b/src/plugins/renderer/template/gpu_pipeline.zig index 7e2e123..5a27da0 100644 --- a/src/plugins/renderer/template/gpu_pipeline.zig +++ b/src/plugins/renderer/template/gpu_pipeline.zig @@ -2,4 +2,3 @@ const wgpu = @import("wgpu"); raw: *wgpu.WGPURenderPipelineImpl, layout: *wgpu.WGPUPipelineLayoutImpl, -bind_group_layouts: [3]*wgpu.WGPUBindGroupLayoutImpl,