// WGPU render pipeline builder - implementation #include "gpu/pipeline_builder.h" #include "util/fatal_error.h" RenderPipelineBuilder::RenderPipelineBuilder(WGPUDevice device) : device_(device) { desc_.primitive.topology = WGPUPrimitiveTopology_TriangleList; desc_.primitive.cullMode = WGPUCullMode_None; desc_.multisample.count = 1; desc_.multisample.mask = 0xFFFFFFFF; } RenderPipelineBuilder& RenderPipelineBuilder::shader(const char* wgsl, bool compose) { shader_text_ = compose ? ShaderComposer::Get().Compose({}, wgsl) : wgsl; if (device_ == nullptr) return *this; WGPUShaderSourceWGSL wgsl_src{}; wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; wgsl_src.code = str_view(shader_text_.c_str()); WGPUShaderModuleDescriptor shader_desc{}; shader_desc.nextInChain = &wgsl_src.chain; shader_module_ = wgpuDeviceCreateShaderModule(device_, &shader_desc); desc_.vertex.module = shader_module_; desc_.vertex.entryPoint = str_view("vs_main"); return *this; } RenderPipelineBuilder& RenderPipelineBuilder::bind_group_layout(WGPUBindGroupLayout layout) { layouts_.push_back(layout); return *this; } RenderPipelineBuilder& RenderPipelineBuilder::format(WGPUTextureFormat fmt) { color_.format = fmt; return *this; } RenderPipelineBuilder& RenderPipelineBuilder::blend_alpha() { has_blend_ = true; blend_.color.operation = WGPUBlendOperation_Add; blend_.color.srcFactor = WGPUBlendFactor_SrcAlpha; blend_.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; blend_.alpha.operation = WGPUBlendOperation_Add; blend_.alpha.srcFactor = WGPUBlendFactor_One; blend_.alpha.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; return *this; } RenderPipelineBuilder& RenderPipelineBuilder::depth(WGPUTextureFormat depth_fmt) { has_depth_ = true; depth_.format = depth_fmt; depth_.depthWriteEnabled = WGPUOptionalBool_True; depth_.depthCompare = WGPUCompareFunction_Less; return *this; } RenderPipelineBuilder& RenderPipelineBuilder::cull_back() { desc_.primitive.cullMode = WGPUCullMode_Back; return *this; } WGPURenderPipeline RenderPipelineBuilder::build() { HEADLESS_RETURN_VAL_IF_NULL(device_, nullptr); color_.writeMask = WGPUColorWriteMask_All; if (has_blend_) color_.blend = &blend_; WGPUFragmentState fragment{}; fragment.module = shader_module_; fragment.entryPoint = str_view("fs_main"); fragment.targetCount = 1; fragment.targets = &color_; WGPUPipelineLayoutDescriptor pl_desc{}; pl_desc.bindGroupLayoutCount = layouts_.size(); pl_desc.bindGroupLayouts = layouts_.data(); WGPUPipelineLayout layout = wgpuDeviceCreatePipelineLayout(device_, &pl_desc); desc_.layout = layout; desc_.fragment = &fragment; if (has_depth_) desc_.depthStencil = &depth_; WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device_, &desc_); wgpuPipelineLayoutRelease(layout); return pipeline; }