render-zig

A 3D rendering engine written in Zig
git clone git://git.christianermann.dev/render-zig
Log | Files | Refs

line_render_pipeline.zig (4920B)


      1 const std = @import("std");
      2 const gpu = @import("mach_gpu");
      3 
      4 const App = @import("main.zig").App;
      5 const RenderData = @import("render_data.zig");
      6 const UniformData = @import("main.zig").UniformData;
      7 const f32x4 = @import("main.zig").f32x4;
      8 const mat4 = @import("main.zig").mat4;
      9 const CubeMap = @import("cubemap.zig");
     10 const Textures = @import("textures.zig");
     11 const RenderPipeline = @import("render_pipeline.zig").RenderPipeline;
     12 const Buffer = @import("main.zig").Buffer;
     13 
     14 const Self = @This();
     15 
     16 pub const Buffers = struct {
     17     positions: *const Buffer(f32x4),
     18     indices: *const Buffer(u32),
     19     object_data: *const Buffer(RenderData.ObjectData),
     20     indirect: *const Buffer([5]u32),
     21 };
     22 
     23 gpu_pipeline: *gpu.RenderPipeline,
     24 buffers: Buffers,
     25 bind_group: *gpu.BindGroup,
     26 uniform_buffer: *gpu.Buffer,
     27 
     28 pub fn init(
     29     app: *App,
     30     buffers: Buffers,
     31     comptime shader_path: []const u8,
     32 ) !Self {
     33     const src = @embedFile(shader_path);
     34 
     35     const module = app.device.createShaderModuleWGSL("line shader", src);
     36     defer module.release();
     37 
     38     const layouts = Self.bufferLayouts();
     39     const vertex = gpu.VertexState.init(.{
     40         .module = module,
     41         .entry_point = "vertex",
     42         .buffers = &layouts,
     43     });
     44 
     45     const blend: gpu.BlendState = .{};
     46     const color_target = gpu.ColorTargetState{
     47         .format = app.swap_chain.format,
     48         .blend = &blend,
     49         .write_mask = gpu.ColorWriteMaskFlags.all,
     50     };
     51     const fragment = gpu.FragmentState.init(.{
     52         .module = module,
     53         .entry_point = "fragment",
     54         .targets = &.{color_target},
     55     });
     56 
     57     const buffer_descriptor = gpu.Buffer.Descriptor{
     58         .size = @sizeOf(UniformData),
     59         .usage = .{ .uniform = true, .copy_dst = true },
     60         .mapped_at_creation = .false,
     61     };
     62     const uniform_buffer = app.device.createBuffer(&buffer_descriptor);
     63 
     64     const bind_group_layout = Self.bindGroupLayout(app.device);
     65     const bind_group_descriptor = gpu.BindGroup.Descriptor.init(.{
     66         .layout = bind_group_layout,
     67         .entries = &.{
     68             gpu.BindGroup.Entry.buffer(0, buffers.object_data.data, 0, buffers.object_data.size),
     69             gpu.BindGroup.Entry.buffer(1, uniform_buffer, 0, @sizeOf(UniformData)),
     70         },
     71     });
     72     const bind_group = app.device.createBindGroup(&bind_group_descriptor);
     73 
     74     const pipeline_layout_descriptor = gpu.PipelineLayout.Descriptor.init(.{
     75         .bind_group_layouts = &.{bind_group_layout},
     76     });
     77     const pipeline_layout = app.device.createPipelineLayout(&pipeline_layout_descriptor);
     78     defer pipeline_layout.release();
     79 
     80     const pipeline_descriptor = gpu.RenderPipeline.Descriptor{
     81         .label = "line render pipeline",
     82         .fragment = &fragment,
     83         .layout = pipeline_layout,
     84         .depth_stencil = &.{
     85             .format = .depth24_plus,
     86             .depth_write_enabled = .true,
     87             .depth_compare = .less,
     88         },
     89         .vertex = vertex,
     90         .multisample = .{},
     91         .primitive = .{
     92             .topology = .line_list,
     93             .front_face = .ccw,
     94             .cull_mode = .back,
     95         },
     96     };
     97 
     98     return .{
     99         .gpu_pipeline = app.device.createRenderPipeline(&pipeline_descriptor),
    100         .buffers = buffers,
    101         .bind_group = bind_group,
    102         .uniform_buffer = uniform_buffer,
    103     };
    104 }
    105 
    106 fn bufferLayouts() [1]gpu.VertexBufferLayout {
    107     const positions = gpu.VertexBufferLayout.init(.{
    108         .array_stride = @sizeOf(f32x4),
    109         .step_mode = .vertex,
    110         .attributes = &.{
    111             .{ .format = .float32x4, .shader_location = 0, .offset = 0 },
    112         },
    113     });
    114     return .{positions};
    115 }
    116 
    117 fn bindGroupLayout(device: *gpu.Device) *gpu.BindGroupLayout {
    118     const descriptor = gpu.BindGroupLayout.Descriptor.init(.{
    119         .entries = &.{
    120             gpu.BindGroupLayout.Entry.buffer(0, .{
    121                 .vertex = true,
    122                 .fragment = true,
    123             }, .read_only_storage, false, 0),
    124             gpu.BindGroupLayout.Entry.buffer(1, .{
    125                 .vertex = true,
    126                 .fragment = false,
    127             }, .uniform, false, 0),
    128         },
    129     });
    130     return device.createBindGroupLayout(&descriptor);
    131 }
    132 
    133 pub fn frame(ptr: *anyopaque, pass: *gpu.RenderPassEncoder) void {
    134     const self: *Self = @ptrCast(@alignCast(ptr));
    135     pass.setPipeline(self.gpu_pipeline);
    136 
    137     pass.setVertexBuffer(0, self.buffers.positions.data, 0, self.buffers.positions.size);
    138     pass.setIndexBuffer(self.buffers.indices.data, .uint32, 0, self.buffers.indices.size);
    139     pass.setBindGroup(0, self.bind_group, null);
    140 
    141     const num_indirect = self.buffers.indirect.count();
    142     for (0..num_indirect) |idx| {
    143         const offset = idx * self.buffers.indirect.attrib_size;
    144         pass.drawIndexedIndirect(self.buffers.indirect.data, offset);
    145     }
    146 }
    147 
    148 pub fn pipeline(self: *Self) RenderPipeline {
    149     return .{
    150         .ptr = self,
    151         .frameFn = frame,
    152     };
    153 }