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 }