render_pipeline.zig (8913B)
1 const std = @import("std"); 2 const gpu = @import("mach_gpu"); 3 4 const App = @import("main.zig").App; 5 const MeshBuffer = @import("main.zig").MeshBuffer; 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 12 pub const RenderPipeline = struct { 13 ptr: *anyopaque, 14 frameFn: *const fn (ptr: *anyopaque, pass: *gpu.RenderPassEncoder) void, 15 16 pub fn frame(self: *const RenderPipeline, pass: *gpu.RenderPassEncoder) void { 17 return self.frameFn(self.ptr, pass); 18 } 19 }; 20 21 pub const TriangleRenderPipeline = struct { 22 gpu_pipeline: *gpu.RenderPipeline, 23 24 pub fn init(app: *App) TriangleRenderPipeline { 25 const vs = 26 \\ @vertex fn main( 27 \\ @builtin(vertex_index) VertexIndex : u32 28 \\ ) -> @builtin(position) vec4<f32> { 29 \\ var pos = array<vec2<f32>, 3>( 30 \\ vec2<f32>( 0.0, 0.5), 31 \\ vec2<f32>(-0.5, -0.5), 32 \\ vec2<f32>( 0.5, -0.5) 33 \\ ); 34 \\ return vec4<f32>(pos[VertexIndex], 0.0, 1.0); 35 \\ } 36 ; 37 const vs_module = app.device.createShaderModuleWGSL("example vertex shader", vs); 38 defer vs_module.release(); 39 40 const vertex = gpu.VertexState{ 41 .module = vs_module, 42 .entry_point = "main", 43 }; 44 45 const fs = 46 \\ @fragment fn main() -> @location(0) vec4<f32> { 47 \\ return vec4<f32>(1.0, 0.0, 0.0, 1.0); 48 \\ } 49 ; 50 const fs_module = app.device.createShaderModuleWGSL("example fragment shader", fs); 51 defer fs_module.release(); 52 53 const blend: gpu.BlendState = .{}; 54 const color_target = gpu.ColorTargetState{ 55 .format = app.swap_chain.format, 56 .blend = &blend, 57 .write_mask = gpu.ColorWriteMaskFlags.all, 58 }; 59 const fragment = gpu.FragmentState.init(.{ 60 .module = fs_module, 61 .entry_point = "main", 62 .targets = &.{color_target}, 63 }); 64 65 const pipeline_descriptor = gpu.RenderPipeline.Descriptor{ 66 .label = "example render pipeline", 67 .fragment = &fragment, 68 .layout = null, 69 .depth_stencil = null, 70 .vertex = vertex, 71 .multisample = .{}, 72 .primitive = .{}, 73 }; 74 75 return .{ 76 .gpu_pipeline = app.device.createRenderPipeline(&pipeline_descriptor), 77 }; 78 } 79 80 pub fn frame(ptr: *anyopaque, pass: *gpu.RenderPassEncoder) void { 81 const self: *TriangleRenderPipeline = @ptrCast(@alignCast(ptr)); 82 pass.setPipeline(self.gpu_pipeline); 83 pass.draw(3, 1, 0, 0); 84 } 85 86 pub fn pipeline(self: *TriangleRenderPipeline) RenderPipeline { 87 return .{ 88 .ptr = self, 89 .frameFn = frame, 90 }; 91 } 92 }; 93 94 pub const SkyBoxRenderPipeline = struct { 95 gpu_pipeline: *gpu.RenderPipeline, 96 uniform_buffer: *gpu.Buffer, 97 bind_group: *gpu.BindGroup, 98 99 pub const UniformData = struct { 100 inv_view: mat4, 101 inv_proj: mat4, 102 }; 103 104 pub fn init(app: *App, cube_map: CubeMap) SkyBoxRenderPipeline { 105 const vs = 106 \\ struct VertexOutput { 107 \\ @builtin(position) clip_position: vec4<f32>, 108 \\ @location(0) position: vec4<f32>, 109 \\ }; 110 \\ 111 \\ @vertex fn main( 112 \\ @builtin(vertex_index) VertexIndex : u32 113 \\ ) -> VertexOutput { 114 \\ var pos = array<vec2<f32>, 3>( 115 \\ vec2<f32>(-1, 3), 116 \\ vec2<f32>(-1, -1), 117 \\ vec2<f32>( 3, -1), 118 \\ ); 119 \\ let vtx_pos = vec4<f32>(pos[VertexIndex], 1, 1); 120 \\ return VertexOutput(vtx_pos, vtx_pos); 121 \\ } 122 ; 123 const vs_module = app.device.createShaderModuleWGSL("skybox vertex shader", vs); 124 defer vs_module.release(); 125 126 const vertex = gpu.VertexState{ 127 .module = vs_module, 128 .entry_point = "main", 129 }; 130 131 const fs = 132 \\ @group(0) @binding(0) 133 \\ var<uniform> uniform_data: UniformData; 134 \\ struct UniformData { 135 \\ inv_view: mat4x4<f32>, 136 \\ inv_proj: mat4x4<f32>, 137 \\ }; 138 \\ 139 \\ @group(0) @binding(1) var cubemap_sampler: sampler; 140 \\ @group(0) @binding(2) var cubemap_texture: texture_cube<f32>; 141 \\ 142 \\ struct VertexOutput { 143 \\ @builtin(position) clip_position: vec4<f32>, 144 \\ @location(0) position: vec4<f32>, 145 \\ }; 146 \\ 147 \\ @fragment fn main(in: VertexOutput) -> @location(0) vec4<f32> { 148 \\ let inv_cam = uniform_data.inv_view * uniform_data.inv_proj; 149 \\ let pos_world = inv_cam * in.position; 150 \\ let dir = normalize(pos_world.xyz / pos_world.w) * vec3<f32>(-1, 1, 1); 151 \\ let sample = textureSample(cubemap_texture, cubemap_sampler, dir); 152 \\ //return vec4<f32>((dir + 1) * 0.5, 1.0); 153 \\ return sample; 154 \\ } 155 ; 156 const fs_module = app.device.createShaderModuleWGSL("skybox fragment shader", fs); 157 defer fs_module.release(); 158 159 const color_target = gpu.ColorTargetState{ 160 .format = app.swap_chain.format, 161 .blend = &.{}, 162 .write_mask = gpu.ColorWriteMaskFlags.all, 163 }; 164 const fragment = gpu.FragmentState.init(.{ 165 .module = fs_module, 166 .entry_point = "main", 167 .targets = &.{color_target}, 168 }); 169 170 const buffer_descriptor = gpu.Buffer.Descriptor{ 171 .size = @sizeOf(SkyBoxRenderPipeline.UniformData), 172 .usage = .{ .uniform = true, .copy_dst = true }, 173 .mapped_at_creation = .false, 174 }; 175 const uniform_buffer = app.device.createBuffer(&buffer_descriptor); 176 177 const bind_group_layout = SkyBoxRenderPipeline.bindGroupLayout(app.device); 178 const bind_group_descriptor = gpu.BindGroup.Descriptor.init(.{ 179 .layout = bind_group_layout, 180 .entries = &.{ 181 gpu.BindGroup.Entry.buffer(0, uniform_buffer, 0, @sizeOf(SkyBoxRenderPipeline.UniformData)), 182 gpu.BindGroup.Entry.sampler(1, cube_map.sampler), 183 gpu.BindGroup.Entry.textureView(2, cube_map.view), 184 }, 185 }); 186 const bind_group = app.device.createBindGroup(&bind_group_descriptor); 187 188 const pipeline_layout_descriptor = gpu.PipelineLayout.Descriptor.init(.{ 189 .bind_group_layouts = &.{bind_group_layout}, 190 }); 191 const pipeline_layout = app.device.createPipelineLayout(&pipeline_layout_descriptor); 192 defer pipeline_layout.release(); 193 194 const pipeline_descriptor = gpu.RenderPipeline.Descriptor{ 195 .label = "skybox render pipeline", 196 .fragment = &fragment, 197 .layout = pipeline_layout, 198 .depth_stencil = &.{ 199 .format = .depth24_plus, 200 .depth_write_enabled = .true, 201 .depth_compare = .less_equal, 202 }, 203 .vertex = vertex, 204 .multisample = .{}, 205 .primitive = .{}, 206 }; 207 208 return .{ 209 .gpu_pipeline = app.device.createRenderPipeline(&pipeline_descriptor), 210 .uniform_buffer = uniform_buffer, 211 .bind_group = bind_group, 212 }; 213 } 214 215 fn bindGroupLayout(device: *gpu.Device) *gpu.BindGroupLayout { 216 const descriptor = gpu.BindGroupLayout.Descriptor.init(.{ 217 .entries = &.{ 218 gpu.BindGroupLayout.Entry.buffer(0, .{ 219 .vertex = false, 220 .fragment = true, 221 }, .uniform, false, 0), 222 gpu.BindGroupLayout.Entry.sampler(1, .{ 223 .vertex = false, 224 .fragment = true, 225 }, .filtering), 226 gpu.BindGroupLayout.Entry.texture(2, .{ 227 .vertex = false, 228 .fragment = true, 229 }, .float, .dimension_cube, false), 230 }, 231 }); 232 return device.createBindGroupLayout(&descriptor); 233 } 234 235 pub fn frame(ptr: *anyopaque, pass: *gpu.RenderPassEncoder) void { 236 const self: *SkyBoxRenderPipeline = @ptrCast(@alignCast(ptr)); 237 pass.setPipeline(self.gpu_pipeline); 238 pass.setBindGroup(0, self.bind_group, null); 239 pass.draw(3, 1, 0, 0); 240 } 241 242 pub fn pipeline(self: *SkyBoxRenderPipeline) RenderPipeline { 243 return .{ 244 .ptr = self, 245 .frameFn = frame, 246 }; 247 } 248 };