render-zig

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

mesh_render_pipeline.zig (7323B)


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