|
|
|
@ -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", |
|
|
|
|
.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 = &fragment, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
app.app_timer = try core.Timer.start(); |
|
|
|
|
app.title_timer = try core.Timer.start(); |
|
|
|
|
|
|
|
|
|
app.pipeline = core.device.createRenderPipeline(&pipeline_descriptor); |
|
|
|
|
}), |
|
|
|
|
}, |
|
|
|
|
}), |
|
|
|
|
.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{ |
|
|
|
|
const render_pass_info = gpu.RenderPassDescriptor.init(.{ |
|
|
|
|
.color_attachments = &.{.{ |
|
|
|
|
.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}, |
|
|
|
|
}}, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// 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`. |
|
|
|
|