diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-10 17:27:34 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-10 17:27:34 +0100 |
| commit | e7cd4d65f9f55ccc14045cbcac9d61358ba0c2bf (patch) | |
| tree | c9365a3cb26953478a4bcaf684b7e2ec92442557 /src/gpu/pipeline_builder.h | |
| parent | 61104d5b9e1774c11f0dba3b6d6018dabc2bce8f (diff) | |
refactor: Factor WGPU boilerplate into builder pattern helpers
Add BindGroupLayoutBuilder, BindGroupBuilder, RenderPipelineBuilder,
and SamplerCache to reduce repetitive WGPU code. Refactor
post_process_helper, cnn_effect, and rotating_cube_effect.
Changes:
- Bind group creation: 19 instances, 14→4 lines each
- Pipeline creation: 30-50→8 lines
- Sampler deduplication: 6 instances → cached
- Total boilerplate reduction: -122 lines across 3 files
Builder pattern prevents binding index errors and consolidates
platform-specific #ifdef in fewer locations. Binary size unchanged
(6.3M debug). Tests pass.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/gpu/pipeline_builder.h')
| -rw-r--r-- | src/gpu/pipeline_builder.h | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/gpu/pipeline_builder.h b/src/gpu/pipeline_builder.h new file mode 100644 index 0000000..06b4ceb --- /dev/null +++ b/src/gpu/pipeline_builder.h @@ -0,0 +1,109 @@ +// WGPU render pipeline builder - reduces pipeline creation boilerplate +#pragma once +#include <vector> +#include <string> + +// Forward declarations (users must include gpu.h and shader_composer.h) +struct WGPUDeviceImpl; +typedef struct WGPUDeviceImpl* WGPUDevice; +struct WGPUBindGroupLayoutImpl; +typedef struct WGPUBindGroupLayoutImpl* WGPUBindGroupLayout; +struct WGPURenderPipelineImpl; +typedef struct WGPURenderPipelineImpl* WGPURenderPipeline; +struct WGPUShaderModuleImpl; +typedef struct WGPUShaderModuleImpl* WGPUShaderModule; + +#include "platform/platform.h" +#include "gpu/effects/shader_composer.h" + +class RenderPipelineBuilder { + WGPUDevice device_; + WGPURenderPipelineDescriptor desc_{}; + WGPUColorTargetState color_{}; + WGPUBlendState blend_{}; + WGPUDepthStencilState depth_{}; + std::vector<WGPUBindGroupLayout> layouts_; + std::string shader_text_; + WGPUShaderModule shader_module_ = nullptr; + bool has_blend_ = false; + bool has_depth_ = false; + +public: + explicit RenderPipelineBuilder(WGPUDevice device) : device_(device) { + desc_.primitive.topology = WGPUPrimitiveTopology_TriangleList; + desc_.primitive.cullMode = WGPUCullMode_None; + desc_.multisample.count = 1; + desc_.multisample.mask = 0xFFFFFFFF; + } + + RenderPipelineBuilder& shader(const char* wgsl, bool compose = true) { + shader_text_ = compose ? ShaderComposer::Get().Compose({}, wgsl) : wgsl; + 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& bind_group_layout(WGPUBindGroupLayout layout) { + layouts_.push_back(layout); + return *this; + } + + RenderPipelineBuilder& format(WGPUTextureFormat fmt) { + color_.format = fmt; + return *this; + } + + 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& depth(WGPUTextureFormat depth_fmt = WGPUTextureFormat_Depth24Plus) { + has_depth_ = true; + depth_.format = depth_fmt; + depth_.depthWriteEnabled = WGPUOptionalBool_True; + depth_.depthCompare = WGPUCompareFunction_Less; + return *this; + } + + RenderPipelineBuilder& cull_back() { + desc_.primitive.cullMode = WGPUCullMode_Back; + return *this; + } + + WGPURenderPipeline build() { + 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; + } +}; |
