#include "webgpu/wgpu_common.h" #include /* -------------------------------------------------------------------------- * * WebGPU Example - Minimal * * Minimalistic render pipeline demonstrating how to render a full-screen * colored quad. * * Ref: * https://github.com/Palats/webgpu/blob/main/demos/demos/minimal.ts * -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- * * WGSL Shaders * -------------------------------------------------------------------------- */ static const char* vertex_shader_wgsl; static const char* fragment_shader_wgsl; /* -------------------------------------------------------------------------- * * Minimal example * -------------------------------------------------------------------------- */ static struct { WGPURenderPipeline pipeline; WGPURenderPassColorAttachment color_attachment; WGPURenderPassDescriptor render_pass_descriptor; WGPUBool initialized; } state = { .color_attachment = { .loadOp = WGPULoadOp_Clear, .storeOp = WGPUStoreOp_Store, .clearValue = {0.0, 0.0, 0.0, 1.0}, .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, }, .render_pass_descriptor = { .colorAttachmentCount = 1, .colorAttachments = &state.color_attachment, }, }; static void init_pipeline(wgpu_context_t* wgpu_context) { WGPUShaderModule vert_shader_module = wgpu_create_shader_module(wgpu_context->device, vertex_shader_wgsl); WGPUShaderModule frag_shader_module = wgpu_create_shader_module(wgpu_context->device, fragment_shader_wgsl); WGPURenderPipelineDescriptor rp_desc = { .label = STRVIEW("Quad - Render pipeline"), .vertex = { .module = vert_shader_module, .entryPoint = STRVIEW("main"), }, .fragment = &(WGPUFragmentState) { .entryPoint = STRVIEW("main"), .module = frag_shader_module, .targetCount = 1, .targets = &(WGPUColorTargetState) { .format = wgpu_context->render_format, .writeMask = WGPUColorWriteMask_All, }, }, .primitive = { .topology = WGPUPrimitiveTopology_TriangleList, .frontFace = WGPUFrontFace_CCW, .cullMode = WGPUCullMode_None, }, .multisample = { .count = 1, .mask = 0xffffffff }, }; state.pipeline = wgpuDeviceCreateRenderPipeline(wgpu_context->device, &rp_desc); ASSERT(state.pipeline != NULL); wgpuShaderModuleRelease(vert_shader_module); wgpuShaderModuleRelease(frag_shader_module); } static int init(struct wgpu_context_t* wgpu_context) { if (wgpu_context) { init_pipeline(wgpu_context); state.initialized = 1; return EXIT_SUCCESS; } return EXIT_FAILURE; } static int frame(struct wgpu_context_t* wgpu_context) { if (!state.initialized) { return EXIT_FAILURE; } WGPUDevice device = wgpu_context->device; WGPUQueue queue = wgpu_context->queue; state.color_attachment.view = wgpu_context->swapchain_view; WGPUCommandEncoder cmd_enc = wgpuDeviceCreateCommandEncoder(device, NULL); WGPURenderPassEncoder rpass_enc = wgpuCommandEncoderBeginRenderPass(cmd_enc, &state.render_pass_descriptor); /* Record render commands. */ wgpuRenderPassEncoderSetPipeline(rpass_enc, state.pipeline); wgpuRenderPassEncoderSetViewport(rpass_enc, 0.0f, 0.0f, (float)wgpu_context->width, (float)wgpu_context->height, 0.0f, 1.0f); wgpuRenderPassEncoderSetScissorRect(rpass_enc, 0u, 0u, wgpu_context->width, wgpu_context->height); wgpuRenderPassEncoderDraw(rpass_enc, 6, 1, 0, 0); wgpuRenderPassEncoderEnd(rpass_enc); WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(cmd_enc, NULL); /* Submit and present. */ wgpuQueueSubmit(queue, 1, &cmd_buffer); /* Cleanup */ wgpuRenderPassEncoderRelease(rpass_enc); wgpuCommandBufferRelease(cmd_buffer); wgpuCommandEncoderRelease(cmd_enc); return EXIT_SUCCESS; } static void shutdown(struct wgpu_context_t* wgpu_context) { UNUSED_VAR(wgpu_context); WGPU_RELEASE_RESOURCE(RenderPipeline, state.pipeline) } int main(void) { wgpu_start(&(wgpu_desc_t){ .title = "Minimal", .init_cb = init, .frame_cb = frame, .shutdown_cb = shutdown, }); return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- * * WGSL Shaders * -------------------------------------------------------------------------- */ // clang-format off static const char* vertex_shader_wgsl = CODE( struct VSOut { @builtin(position) pos: vec4, @location(0) coord: vec2 }; @vertex fn main(@builtin(vertex_index) idx : u32) -> VSOut { var data = array, 6>( vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(1.0, 1.0), vec2(-1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0), ); var pos = data[idx]; var out : VSOut; out.pos = vec4(pos, 0.0, 1.0); out.coord.x = (pos.x + 1.0) / 2.0; out.coord.y = (1.0 - pos.y) / 2.0; return out; } ); static const char* fragment_shader_wgsl = CODE( @fragment fn main(@location(0) coord: vec2) -> @location(0) vec4 { return vec4(coord.x, coord.y, 0.5, 1.0); } ); // clang-format on