render_pipeline.zig (7944B)
1 const std = @import("std"); 2 3 const wgpu = @import("wgpu"); 4 const math = @import("math"); 5 6 pub const RenderPipeline = struct { 7 ptr: *anyopaque, 8 frameFn: *const fn ( 9 ptr: *anyopaque, 10 render_pass_encoder: *wgpu.RenderPassEncoder, 11 ) void, 12 13 pub fn frame( 14 self: *const RenderPipeline, 15 render_pass_encoder: *wgpu.RenderPassEncoder, 16 ) void { 17 return self.frameFn(self.ptr, render_pass_encoder); 18 } 19 }; 20 21 pub const TriangleRenderPipeline = struct { 22 render_pipeline: *wgpu.RenderPipeline, 23 bind_group: *wgpu.BindGroup, 24 uniform_buffer: *wgpu.Buffer, 25 26 pub const UniformData = extern struct { 27 view_matrix: math.Mat4, 28 proj_matrix: math.Mat4, 29 }; 30 31 pub fn init(device: *wgpu.Device) !TriangleRenderPipeline { 32 const vs = 33 \\ @group(0) @binding(0) 34 \\ var<uniform> uniform_data: UniformData; 35 \\ struct UniformData { 36 \\ view: mat4x4<f32>, 37 \\ proj: mat4x4<f32>, 38 \\ }; 39 \\ 40 \\ @vertex fn main( 41 \\ @builtin(vertex_index) vtx_idx : u32 42 \\ ) -> @builtin(position) vec4<f32> { 43 \\ let camera_matrix = transpose( 44 \\ uniform_data.view * uniform_data.proj 45 \\ ); 46 \\ let x = f32(i32(vtx_idx) - 1); 47 \\ let y = f32(i32(vtx_idx & 1u) * 2 - 1); 48 \\ let position_ws = vec4<f32>(x, y, 50.0, 1.0); 49 \\ let position_cs = camera_matrix * position_ws; 50 \\ return position_cs; 51 \\ } 52 ; 53 const vs_module = device.createShaderModule(&.{ 54 .next = .{ .wgsl = &.{ .code = wgpu.StringView.fromSlice(vs) } }, 55 .label = wgpu.StringView.fromSlice("Triangle Vertex Shader"), 56 }) orelse { 57 return error.VertexShader; 58 }; 59 defer vs_module.release(); 60 61 const fs = 62 \\ @fragment fn main() -> @location(0) vec4<f32> { 63 \\ return vec4<f32>(1.0, 0.0, 0.0, 1.0); 64 \\ } 65 ; 66 const fs_module = device.createShaderModule(&.{ 67 .next = .{ .wgsl = &.{ .code = wgpu.StringView.fromSlice(fs) } }, 68 .label = wgpu.StringView.fromSlice("Triangle Fragment Shader"), 69 }) orelse { 70 return error.FragmentShader; 71 }; 72 defer fs_module.release(); 73 74 const uniform_buffer = device.createBuffer(&.{ 75 .label = wgpu.StringView.fromSlice("Triangle Uniform Buffer"), 76 .usage = .{ .uniform = true, .copy_dst = true }, 77 .size = @sizeOf(UniformData), 78 .mapped_at_creation = false, 79 }).?; 80 81 const bind_group_layout_entries = &[_]wgpu.BindGroupLayout.Entry{ 82 .{ 83 .binding = 0, 84 .visibility = .{ .vertex = true }, 85 .buffer = .{ 86 .type = .uniform, 87 .has_dynamic_offset = false, 88 .min_binding_size = 0, 89 }, 90 .sampler = .{ 91 .type = .binding_not_used, 92 }, 93 .texture = .{ 94 .sample_type = .binding_not_used, 95 .view_dimension = .undefined, 96 .multisampled = false, 97 }, 98 .storage_texture = .{ 99 .access = .binding_not_used, 100 .format = .undefined, 101 .view_dimension = .undefined, 102 }, 103 }, 104 }; 105 const bind_group_layout = device.createBindGroupLayout(&.{ 106 .label = wgpu.StringView.fromSlice("Triangle Bind Group Layout"), 107 .entry_count = bind_group_layout_entries.len, 108 .entries = bind_group_layout_entries.ptr, 109 }).?; 110 111 const bind_group_entries = &[_]wgpu.BindGroup.Entry{ 112 .{ 113 .binding = 0, 114 .buffer = uniform_buffer, 115 .offset = 0, 116 .size = @sizeOf(UniformData), 117 .sampler = null, 118 .texture_view = null, 119 }, 120 }; 121 const bind_group = device.createBindGroup(&.{ 122 .label = wgpu.StringView.fromSlice("Triangle Pipeline Bind Group"), 123 .layout = bind_group_layout, 124 .entry_count = bind_group_entries.len, 125 .entries = bind_group_entries.ptr, 126 }).?; 127 128 const bind_group_layouts = &[_]*wgpu.BindGroupLayout{ 129 bind_group_layout, 130 }; 131 const pipeline_layout = device.createPipelineLayout(&.{ 132 .label = wgpu.StringView.fromSlice("Triangle Pipeline Layout"), 133 .bind_group_layout_count = bind_group_layouts.len, 134 .bind_group_layouts = bind_group_layouts.ptr, 135 }); 136 137 const pipeline = device.createRenderPipeline(&.{ 138 .label = wgpu.StringView.fromSlice("Triangle Render Pipeline"), 139 .layout = pipeline_layout, 140 .vertex = .{ 141 .module = vs_module, 142 .entry_point = wgpu.StringView.fromSlice("main"), 143 .constant_count = 0, 144 .constants = null, 145 .buffer_count = 0, 146 .buffers = null, 147 }, 148 .primitive = .{ 149 .topology = .triangle_list, 150 .strip_index_format = .undefined, 151 .front_face = .ccw, 152 .cull_mode = .none, 153 .unclipped_depth = false, 154 }, 155 .depth_stencil = null, 156 .multisample = .{ 157 .count = 1, 158 .mask = 0xFFFFFFFF, 159 .alpha_to_coverage_enabled = false, 160 }, 161 .fragment_state = &.{ 162 .module = fs_module, 163 .entry_point = wgpu.StringView.fromSlice("main"), 164 .constant_count = 0, 165 .constants = null, 166 .target_count = 1, 167 .targets = &.{ 168 .{ 169 .format = .bgra8_unorm, 170 .blend = &.{ 171 .color = .{ 172 .operation = .add, 173 .src_factor = .one, 174 .dst_factor = .zero, 175 }, 176 .alpha = .{ 177 .operation = .add, 178 .src_factor = .one, 179 .dst_factor = .zero, 180 }, 181 }, 182 .write_mask = .{ 183 .red = true, 184 .green = true, 185 .blue = true, 186 .alpha = true, 187 }, 188 }, 189 }, 190 }, 191 }) orelse { 192 return error.RenderPipeline; 193 }; 194 195 return .{ 196 .render_pipeline = pipeline, 197 .bind_group = bind_group, 198 .uniform_buffer = uniform_buffer, 199 }; 200 } 201 202 pub fn setUniform( 203 self: *TriangleRenderPipeline, 204 queue: *wgpu.Queue, 205 uniform_data: *const UniformData, 206 ) void { 207 const bytes = std.mem.asBytes(uniform_data); 208 queue.writeBuffer(self.uniform_buffer, 0, bytes.ptr, bytes.len); 209 } 210 211 pub fn frame( 212 ptr: *anyopaque, 213 render_pass_encoder: *wgpu.RenderPassEncoder, 214 ) void { 215 const self: *TriangleRenderPipeline = @ptrCast(@alignCast(ptr)); 216 render_pass_encoder.setPipeline(self.render_pipeline); 217 render_pass_encoder.setBindGroup(0, self.bind_group, 0, null); 218 render_pass_encoder.draw(3, 1, 0, 0); 219 } 220 221 pub fn renderPipeline(self: *TriangleRenderPipeline) RenderPipeline { 222 return .{ 223 .ptr = self, 224 .frameFn = frame, 225 }; 226 } 227 };