diff --git a/src/main.zig b/src/main.zig index 8731ce0..eb4290e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,6 +6,11 @@ const zm = @import("zmath"); const vec = zm.f32x4; const Mat = zm.Mat; +const VertexData = struct { + position: [3]f32, + color: [3]f32, +}; + pub const App = @This(); app_timer: core.Timer, @@ -14,37 +19,42 @@ title_timer: core.Timer, pipeline: *gpu.RenderPipeline, mvp_uniform_buffer: *gpu.Buffer, mvp_bind_group: *gpu.BindGroup, +vertex_count: u32, +vertex_buffer: *gpu.Buffer, pub fn init(app: *App) !void { try core.init(.{}); + app.app_timer = try core.Timer.start(); + app.title_timer = try core.Timer.start(); + const shader_module = core.device.createShaderModuleWGSL("shader.wgsl", @embedFile("shader.wgsl")); defer shader_module.release(); - const blend = gpu.BlendState{}; - const color_target = gpu.ColorTargetState{ - .format = core.descriptor.format, - .blend = &blend, - .write_mask = gpu.ColorWriteMaskFlags.all, - }; - const fragment = gpu.FragmentState.init(.{ - .module = shader_module, - .entry_point = "frag_main", - .targets = &.{color_target}, - }); - const pipeline_descriptor = gpu.RenderPipeline.Descriptor{ - .vertex = gpu.VertexState{ + // Set up rendering pipeline. + app.pipeline = core.device.createRenderPipeline(&.{ + .vertex = gpu.VertexState.init(.{ .module = shader_module, .entry_point = "vertex_main", - }, - .fragment = &fragment, - }; - - app.app_timer = try core.Timer.start(); - app.title_timer = try core.Timer.start(); - - app.pipeline = core.device.createRenderPipeline(&pipeline_descriptor); + .buffers = &.{ + gpu.VertexBufferLayout.init(.{ + .array_stride = @sizeOf(VertexData), + .step_mode = .vertex, + .attributes = &.{ + .{ .format = .float32x3, .shader_location = 0, .offset = @offsetOf(VertexData, "position") }, + .{ .format = .float32x3, .shader_location = 1, .offset = @offsetOf(VertexData, "color") }, + }, + }), + }, + }), + .fragment = &gpu.FragmentState.init(.{ + .module = shader_module, + .entry_point = "frag_main", + .targets = &.{.{ .format = core.descriptor.format }}, + }), + }); + // Set up uniform buffer and bind group. app.mvp_uniform_buffer = core.device.createBuffer(&.{ .usage = .{ .copy_dst = true, .uniform = true }, .size = @sizeOf(zm.Mat), @@ -59,13 +69,40 @@ pub fn init(app: *App) !void { }, }), ); + + // Set up vertex buffer, containing the vertex data we want to draw. + // `vertices` contains three separate triangles, each with a different color. + const vertices = [_]VertexData{ + .{ .position = .{ -1.0, 0.5 + 0.25, 0.0 }, .color = .{ 1.0, 0.0, 0.0 } }, + .{ .position = .{ -1.5, -0.5 + 0.25, 0.0 }, .color = .{ 1.0, 0.0, 0.0 } }, + .{ .position = .{ -0.5, -0.5 + 0.25, 0.0 }, .color = .{ 1.0, 0.0, 0.0 } }, + + .{ .position = .{ 0.0, 0.5 - 0.25, 0.0 }, .color = .{ 0.0, 1.0, 0.0 } }, + .{ .position = .{ -0.5, -0.5 - 0.25, 0.0 }, .color = .{ 0.0, 1.0, 0.0 } }, + .{ .position = .{ 0.5, -0.5 - 0.25, 0.0 }, .color = .{ 0.0, 1.0, 0.0 } }, + + .{ .position = .{ 1.0, 0.5, 0.0 }, .color = .{ 0.0, 0.0, 1.0 } }, + .{ .position = .{ 0.5, -0.5, 0.0 }, .color = .{ 0.0, 0.0, 1.0 } }, + .{ .position = .{ 1.5, -0.5, 0.0 }, .color = .{ 0.0, 0.0, 1.0 } }, + }; + app.vertex_count = vertices.len; + app.vertex_buffer = core.device.createBuffer(&.{ + .size = app.vertex_count * @sizeOf(VertexData), + .usage = .{ .vertex = true, .copy_dst = true }, + .mapped_at_creation = .false, + }); + // Upload vertex buffer to the GPU. + core.queue.writeBuffer(app.vertex_buffer, 0, &vertices); } pub fn deinit(app: *App) void { + // Using `defer` here, so we can specify them + // in the order they were created in `init`. defer core.deinit(); defer app.pipeline.release(); defer app.mvp_uniform_buffer.release(); defer app.mvp_bind_group.release(); + defer app.vertex_buffer.release(); } pub fn update(app: *App) !bool { @@ -101,14 +138,13 @@ pub fn update(app: *App) !bool { // Once rendering is done (hence `defer`), swap back buffer to the front to display. defer core.swap_chain.present(); - const color_attachment = gpu.RenderPassColorAttachment{ - .view = back_buffer_view, - .clear_value = std.mem.zeroes(gpu.Color), - .load_op = .clear, - .store_op = .store, - }; const render_pass_info = gpu.RenderPassDescriptor.init(.{ - .color_attachments = &.{color_attachment}, + .color_attachments = &.{.{ + .view = back_buffer_view, + .clear_value = std.mem.zeroes(gpu.Color), + .load_op = .clear, + .store_op = .store, + }}, }); // Create a `WGPUCommandEncoder` which provides an interface for recording GPU commands. @@ -124,9 +160,10 @@ pub fn update(app: *App) !bool { pass.setPipeline(app.pipeline); pass.setBindGroup(0, app.mvp_bind_group, &.{}); + pass.setVertexBuffer(0, app.vertex_buffer, 0, app.vertex_count * @sizeOf(VertexData)); - // Draw three triangles with the help of a specialized shader. - pass.draw(9, 1, 0, 0); + // Draw the vertices in `vertex_buffer`. + pass.draw(app.vertex_count, 1, 0, 0); } // Finish recording commands, creating a `WGPUCommandBuffer`. diff --git a/src/shader.wgsl b/src/shader.wgsl index 34bf84e..7350e45 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -1,5 +1,10 @@ @group(0) @binding(0) var mvp_matrix: mat4x4; +struct VertexInput { + @location(0) position: vec3, + @location(1) color: vec3, +}; + struct VertexOutput { @builtin(position) position: vec4, @location(0) color: vec4, @@ -9,31 +14,10 @@ struct FragmentOutput { @location(0) pixel_color: vec4 }; -@vertex fn vertex_main( - @builtin(vertex_index) index: u32 -) -> VertexOutput { - let color = array, 3>( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0), - ); - let pos = array, 9>( - vec2(-1.0, 0.5 + 0.25), - vec2(-1.5, -0.5 + 0.25), - vec2(-0.5, -0.5 + 0.25), - - vec2( 0.0, 0.5 - 0.25), - vec2(-0.5, -0.5 - 0.25), - vec2( 0.5, -0.5 - 0.25), - - vec2( 1.0, 0.5), - vec2( 0.5, -0.5), - vec2( 1.5, -0.5), - ); - +@vertex fn vertex_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = vec4(pos[index], 0.0, 1.0) * mvp_matrix; - out.color = vec4(color[index / 3], 1.0); + out.position = vec4(in.position, 1.0) * mvp_matrix; + out.color = vec4(in.color, 1.0); return out; }