zgpu

git clone git://git.electrosoup.com/zgpu
Log | Files | Refs | Submodules | README

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 };