// This file is part of the 64k demo project. // It implements helper functions for post-processing effects. #include "post_process_helper.h" #include "gpu/bind_group_builder.h" #include "gpu/gpu.h" #include "gpu/pipeline_builder.h" #include "gpu/sampler_cache.h" #include "gpu/shader_composer.h" #include "util/fatal_error.h" #include // Helper to create a standard post-processing pipeline WGPURenderPipeline create_post_process_pipeline(WGPUDevice device, WGPUTextureFormat format, const char* shader_code) { // Headless mode: skip pipeline creation (compiled out in STRIP_ALL) HEADLESS_RETURN_VAL_IF_NULL(device, nullptr); WGPUBindGroupLayout bgl = BindGroupLayoutBuilder() .sampler(PP_BINDING_SAMPLER, WGPUShaderStage_Fragment) .texture(PP_BINDING_TEXTURE, WGPUShaderStage_Fragment) .uniform(PP_BINDING_UNIFORMS, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment) .uniform(PP_BINDING_EFFECT_PARAMS, WGPUShaderStage_Fragment) .build(device); const std::string composed_shader = ShaderComposer::Get().Compose({}, shader_code); WGPURenderPipeline pipeline = RenderPipelineBuilder(device) .shader(composed_shader.c_str()) .bind_group_layout(bgl) .format(format) .build(); wgpuBindGroupLayoutRelease(bgl); return pipeline; } // NOTE: create_post_process_pipeline_simple() was removed (zero callers). // If a 3-binding pipeline is needed in the future, add a `bool // use_effect_params` parameter to create_post_process_pipeline() instead. // Example: // WGPURenderPipeline p = create_post_process_pipeline(device, format, code); // // Then pass {nullptr, 0} as effect_params to pp_update_bind_group — // // the dummy buffer fallback handles it automatically. void gpu_upload_mat4(WGPUQueue queue, WGPUBuffer buffer, size_t offset, const mat4& m) { const mat4 t = mat4::transpose(m); wgpuQueueWriteBuffer(queue, buffer, offset, &t, sizeof(mat4)); } // --- PostProcess Implementation Helper --- static GpuBuffer g_dummy_buffer = {nullptr, 0}; void pp_update_bind_group(WGPUDevice device, WGPURenderPipeline pipeline, WGPUBindGroup* bind_group, WGPUTextureView input_view, GpuBuffer uniforms, GpuBuffer effect_params) { // Headless mode: skip bind group creation (compiled out in STRIP_ALL) HEADLESS_RETURN_IF_NULL(device); HEADLESS_RETURN_IF_NULL(pipeline); if (!g_dummy_buffer.buffer) { g_dummy_buffer = gpu_create_buffer(device, 32, WGPUBufferUsage_Uniform); } if (*bind_group) wgpuBindGroupRelease(*bind_group); WGPUBindGroupLayout bgl = wgpuRenderPipelineGetBindGroupLayout(pipeline, 0); WGPUSampler sampler = SamplerCache::Get().get_or_create(device, SamplerCache::linear()); *bind_group = BindGroupBuilder() .sampler(PP_BINDING_SAMPLER, sampler) .texture(PP_BINDING_TEXTURE, input_view) .buffer(PP_BINDING_UNIFORMS, uniforms.buffer, uniforms.size) .buffer(PP_BINDING_EFFECT_PARAMS, effect_params.buffer ? effect_params.buffer : g_dummy_buffer.buffer, effect_params.buffer ? effect_params.size : g_dummy_buffer.size) .build(device, bgl); }