diff options
Diffstat (limited to 'src/gpu')
42 files changed, 26 insertions, 2326 deletions
diff --git a/src/gpu/demo_effects.cc b/src/gpu/demo_effects.cc index 069d36c..3acf287 100644 --- a/src/gpu/demo_effects.cc +++ b/src/gpu/demo_effects.cc @@ -3,8 +3,8 @@ // Its content has been split into individual effect files and helper files. #include "gpu/demo_effects.h" -#include "gpu/effects/circle_mask_effect.h" -#include "gpu/effects/rotating_cube_effect.h" +#include "effects/circle_mask_effect.h" +#include "effects/rotating_cube_effect.h" // Auto-generated function to populate the timeline void LoadTimeline(MainSequence& main_seq, WGPUDevice device, WGPUQueue queue, diff --git a/src/gpu/demo_effects.h b/src/gpu/demo_effects.h index d0ae748..beadafb 100644 --- a/src/gpu/demo_effects.h +++ b/src/gpu/demo_effects.h @@ -6,16 +6,16 @@ #include "3d/renderer.h" #include "3d/scene.h" #include "effect.h" -#include "gpu/effects/circle_mask_effect.h" -#include "gpu/effects/fade_effect.h" // FadeEffect with full definition -#include "gpu/effects/flash_effect.h" // FlashEffect with params support -#include "gpu/effects/post_process_helper.h" -#include "gpu/effects/rotating_cube_effect.h" -#include "gpu/effects/shaders.h" -#include "gpu/effects/theme_modulation_effect.h" // ThemeModulationEffect with full definition -#include "gpu/effects/hybrid_3d_effect.h" -#include "gpu/effects/flash_cube_effect.h" -#include "gpu/effects/scene1_effect.h" +#include "effects/circle_mask_effect.h" +#include "effects/fade_effect.h" // FadeEffect with full definition +#include "effects/flash_effect.h" // FlashEffect with params support +#include "gpu/post_process_helper.h" +#include "effects/rotating_cube_effect.h" +#include "gpu/shaders.h" +#include "effects/theme_modulation_effect.h" // ThemeModulationEffect with full definition +#include "effects/hybrid_3d_effect.h" +#include "effects/flash_cube_effect.h" +#include "effects/scene1_effect.h" #include "gpu/gpu.h" #include "gpu/texture_manager.h" #include "gpu/uniform_helper.h" @@ -180,13 +180,9 @@ class DistortEffect : public PostProcessEffect { UniformBuffer<DistortParams> params_buffer_; }; -// ThemeModulationEffect now defined in gpu/effects/theme_modulation_effect.h -// (included above) FadeEffect now defined in gpu/effects/fade_effect.h -// (included above) FlashEffect now defined in gpu/effects/flash_effect.h -// (included above) -#include "gpu/effects/cnn_effect.h" -#include "gpu/effects/cnn_v2_effect.h" +#include "effects/cnn_effect.h" +#include "effects/cnn_v2_effect.h" // Auto-generated functions void LoadTimeline(MainSequence& main_seq, const GpuContext& ctx); diff --git a/src/gpu/effect.h b/src/gpu/effect.h index b9709a4..5d835ad 100644 --- a/src/gpu/effect.h +++ b/src/gpu/effect.h @@ -1,6 +1,6 @@ #pragma once #include "gpu/gpu.h" -#include "gpu/effects/post_process_helper.h" +#include "gpu/post_process_helper.h" #include "gpu/uniform_helper.h" #include <algorithm> #include <map> diff --git a/src/gpu/effects/chroma_aberration_effect.cc b/src/gpu/effects/chroma_aberration_effect.cc deleted file mode 100644 index 3a51965..0000000 --- a/src/gpu/effects/chroma_aberration_effect.cc +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the ChromaAberrationEffect with parameterization. - -#include "gpu/demo_effects.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" - -// --- ChromaAberrationEffect --- - -// Backward compatibility constructor (delegates to parameterized constructor) -ChromaAberrationEffect::ChromaAberrationEffect(const GpuContext& ctx) - : ChromaAberrationEffect(ctx, ChromaAberrationParams{}) { -} - -// Parameterized constructor -ChromaAberrationEffect::ChromaAberrationEffect( - const GpuContext& ctx, const ChromaAberrationParams& params) - : PostProcessEffect(ctx), params_(params) { - pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, - chroma_aberration_shader_wgsl); - params_buffer_.init(ctx_.device); -} - -void ChromaAberrationEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - // Update uniforms with current state and parameters - uniforms_.update(ctx_.queue, uniforms); - params_buffer_.update(ctx_.queue, params_); - - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} - -void ChromaAberrationEffect::update_bind_group(WGPUTextureView input_view) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - uniforms_.get(), params_buffer_.get()); -} diff --git a/src/gpu/effects/circle_mask_effect.cc b/src/gpu/effects/circle_mask_effect.cc deleted file mode 100644 index dfe7d03..0000000 --- a/src/gpu/effects/circle_mask_effect.cc +++ /dev/null @@ -1,219 +0,0 @@ -// This file is part of the 64k demo project. -// It implements CircleMaskEffect for auxiliary texture masking demonstration. -// Generates circular mask and renders green background outside circle. - -#include "gpu/effects/circle_mask_effect.h" -#include "generated/assets.h" -#include "gpu/bind_group_builder.h" -#include "gpu/effects/shader_composer.h" - -CircleMaskEffect::CircleMaskEffect(const GpuContext& ctx, float radius) - : Effect(ctx), radius_(radius) { -} - -CircleMaskEffect::~CircleMaskEffect() { - if (mask_sampler_) - wgpuSamplerRelease(mask_sampler_); - if (render_bind_group_) - wgpuBindGroupRelease(render_bind_group_); - if (render_pipeline_) - wgpuRenderPipelineRelease(render_pipeline_); - if (compute_bind_group_) - wgpuBindGroupRelease(compute_bind_group_); - if (compute_pipeline_) - wgpuRenderPipelineRelease(compute_pipeline_); -} - -void CircleMaskEffect::init(MainSequence* demo) { - demo_ = demo; - - // Register auxiliary texture (width_/height_ set by resize() before init()) - demo_->register_auxiliary_texture("circle_mask", width_, height_); - - compute_params_.init(ctx_.device); - - // Initialize uniforms BEFORE bind group creation - uniforms_.update(ctx_.queue, get_common_uniforms()); - - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; - sampler_desc.maxAnisotropy = 1; - mask_sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); - - size_t compute_size, render_size; - const char* compute_shader = (const char*)GetAsset( - AssetId::ASSET_CIRCLE_MASK_COMPUTE_SHADER, &compute_size); - const char* render_shader = (const char*)GetAsset( - AssetId::ASSET_CIRCLE_MASK_RENDER_SHADER, &render_size); - - // Compose shaders to resolve #include directives - std::string composed_compute = ShaderComposer::Get().Compose({}, compute_shader); - - WGPUShaderSourceWGSL compute_wgsl = {}; - compute_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL; - compute_wgsl.code = str_view(composed_compute.c_str()); - - WGPUShaderModuleDescriptor compute_desc = {}; - compute_desc.nextInChain = &compute_wgsl.chain; - WGPUShaderModule compute_module = - wgpuDeviceCreateShaderModule(ctx_.device, &compute_desc); - - const WGPUColorTargetState compute_target = { - .format = ctx_.format, // Match auxiliary texture format - .writeMask = WGPUColorWriteMask_All, - }; - WGPUFragmentState compute_frag = {}; - compute_frag.module = compute_module; - compute_frag.entryPoint = str_view("fs_main"); - compute_frag.targetCount = 1; - compute_frag.targets = &compute_target; - WGPURenderPipelineDescriptor compute_pipeline_desc = {}; - compute_pipeline_desc.label = label_view("CircleMaskEffect_compute"); - compute_pipeline_desc.vertex.module = compute_module; - compute_pipeline_desc.vertex.entryPoint = str_view("vs_main"); - compute_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; - compute_pipeline_desc.primitive.cullMode = WGPUCullMode_None; - compute_pipeline_desc.multisample.count = 1; - compute_pipeline_desc.multisample.mask = 0xFFFFFFFF; - compute_pipeline_desc.fragment = &compute_frag; - compute_pipeline_ = - wgpuDeviceCreateRenderPipeline(ctx_.device, &compute_pipeline_desc); - wgpuShaderModuleRelease(compute_module); - - WGPUBindGroupLayout compute_layout = - wgpuRenderPipelineGetBindGroupLayout(compute_pipeline_, 0); - compute_bind_group_ = - BindGroupBuilder() - .buffer(0, uniforms_.get().buffer, sizeof(CommonPostProcessUniforms)) - .buffer(1, compute_params_.get().buffer, sizeof(CircleMaskParams)) - .build(ctx_.device, compute_layout); - wgpuBindGroupLayoutRelease(compute_layout); - - std::string composed_render = ShaderComposer::Get().Compose({}, render_shader); - - WGPUShaderSourceWGSL render_wgsl = {}; - render_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL; - render_wgsl.code = str_view(composed_render.c_str()); - - WGPUShaderModuleDescriptor render_desc = {}; - render_desc.nextInChain = &render_wgsl.chain; - WGPUShaderModule render_module = - wgpuDeviceCreateShaderModule(ctx_.device, &render_desc); - - const WGPUColorTargetState render_target = { - .format = ctx_.format, - .writeMask = WGPUColorWriteMask_All, - }; - WGPUFragmentState render_frag = {}; - render_frag.module = render_module; - render_frag.entryPoint = str_view("fs_main"); - render_frag.targetCount = 1; - render_frag.targets = &render_target; - const WGPUDepthStencilState depth_stencil = { - .format = WGPUTextureFormat_Depth24Plus, - .depthWriteEnabled = WGPUOptionalBool_False, // Don't write depth - .depthCompare = WGPUCompareFunction_Always, // Always pass - }; - - WGPURenderPipelineDescriptor render_pipeline_desc = {}; - render_pipeline_desc.label = label_view("CircleMaskEffect_render"); - render_pipeline_desc.vertex.module = render_module; - render_pipeline_desc.vertex.entryPoint = str_view("vs_main"); - render_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; - render_pipeline_desc.primitive.cullMode = WGPUCullMode_None; - render_pipeline_desc.depthStencil = &depth_stencil; - render_pipeline_desc.multisample.count = 1; - render_pipeline_desc.multisample.mask = 0xFFFFFFFF; - render_pipeline_desc.fragment = &render_frag; - render_pipeline_ = - wgpuDeviceCreateRenderPipeline(ctx_.device, &render_pipeline_desc); - wgpuShaderModuleRelease(render_module); - - WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask"); - const WGPUBindGroupEntry render_entries[] = { - {.binding = 0, .textureView = mask_view}, - {.binding = 1, .sampler = mask_sampler_}, - {.binding = 2, - .buffer = uniforms_.get().buffer, - .size = sizeof(CommonPostProcessUniforms)}, - }; - const WGPUBindGroupDescriptor render_bg_desc = { - .layout = wgpuRenderPipelineGetBindGroupLayout(render_pipeline_, 0), - .entryCount = 3, - .entries = render_entries, - }; - render_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &render_bg_desc); -} - -void CircleMaskEffect::resize(int width, int height) { - if (width == width_ && height == height_) - return; - - Effect::resize(width, height); - - if (!demo_) - return; - - // Resize auxiliary texture - demo_->resize_auxiliary_texture("circle_mask", width, height); - - // Recreate render bind group with new texture view - if (render_bind_group_) - wgpuBindGroupRelease(render_bind_group_); - - WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask"); - WGPUBindGroupLayout render_layout = - wgpuRenderPipelineGetBindGroupLayout(render_pipeline_, 0); - render_bind_group_ = - BindGroupBuilder() - .texture(0, mask_view) - .sampler(1, mask_sampler_) - .buffer(2, uniforms_.get().buffer, sizeof(CommonPostProcessUniforms)) - .build(ctx_.device, render_layout); - wgpuBindGroupLayoutRelease(render_layout); -} - -void CircleMaskEffect::compute(WGPUCommandEncoder encoder, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - - const CircleMaskParams params = { - .radius = radius_, - }; - compute_params_.update(ctx_.queue, params); - - WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask"); - WGPURenderPassColorAttachment color_attachment = {}; - color_attachment.view = mask_view; - color_attachment.loadOp = WGPULoadOp_Clear; - color_attachment.storeOp = WGPUStoreOp_Store; - color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0}; -#if !defined(DEMO_CROSS_COMPILE_WIN32) - color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif - - WGPURenderPassDescriptor pass_desc = {}; - pass_desc.colorAttachmentCount = 1; - pass_desc.colorAttachments = &color_attachment; - - WGPURenderPassEncoder pass = - wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, compute_pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, compute_bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); - wgpuRenderPassEncoderEnd(pass); - wgpuRenderPassEncoderRelease(pass); -} - -void CircleMaskEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - - wgpuRenderPassEncoderSetPipeline(pass, render_pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, render_bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} diff --git a/src/gpu/effects/circle_mask_effect.h b/src/gpu/effects/circle_mask_effect.h deleted file mode 100644 index 6ebaca1..0000000 --- a/src/gpu/effects/circle_mask_effect.h +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of the 64k demo project. -// It defines the CircleMaskEffect class for masking system demonstration. -// Creates a circular mask and renders green outside the circle. - -#ifndef CIRCLE_MASK_EFFECT_H_ -#define CIRCLE_MASK_EFFECT_H_ - -#include "gpu/effect.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/uniform_helper.h" - -class CircleMaskEffect : public Effect { - public: - CircleMaskEffect(const GpuContext& ctx, float radius = 0.4f); - ~CircleMaskEffect() override; - - void init(MainSequence* demo) override; - void resize(int width, int height) override; - void compute(WGPUCommandEncoder encoder, - const CommonPostProcessUniforms& uniforms) override; - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - - private: - struct CircleMaskParams { - float radius; - float _pad[3]; - }; - static_assert(sizeof(CircleMaskParams) == 16, - "CircleMaskParams must be 16 bytes for WGSL alignment"); - - MainSequence* demo_ = nullptr; - float radius_; - - WGPURenderPipeline compute_pipeline_ = nullptr; - WGPUBindGroup compute_bind_group_ = nullptr; - UniformBuffer<CircleMaskParams> compute_params_; - - WGPURenderPipeline render_pipeline_ = nullptr; - WGPUBindGroup render_bind_group_ = nullptr; - WGPUSampler mask_sampler_ = nullptr; -}; - -#endif /* CIRCLE_MASK_EFFECT_H_ */ diff --git a/src/gpu/effects/cnn_effect.cc b/src/gpu/effects/cnn_effect.cc deleted file mode 100644 index 83a3365..0000000 --- a/src/gpu/effects/cnn_effect.cc +++ /dev/null @@ -1,126 +0,0 @@ -// CNN post-processing effect implementation -// Neural network-based stylization with modular WGSL - -#include "gpu/effects/cnn_effect.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/effects/shaders.h" -#include "gpu/effects/shader_composer.h" -#include "gpu/effect.h" -#include "gpu/bind_group_builder.h" -#include "gpu/sampler_cache.h" -#include "gpu/pipeline_builder.h" - -// Create custom pipeline with 5 bindings (includes original texture) -static WGPURenderPipeline create_cnn_pipeline(WGPUDevice device, - WGPUTextureFormat format, - const char* shader_code) { - WGPUBindGroupLayout bgl = BindGroupLayoutBuilder() - .sampler(0, WGPUShaderStage_Fragment) - .texture(1, WGPUShaderStage_Fragment) - .uniform(2, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment) - .uniform(3, WGPUShaderStage_Fragment) - .texture(4, WGPUShaderStage_Fragment) - .build(device); - - WGPURenderPipeline pipeline = RenderPipelineBuilder(device) - .shader(shader_code) - .bind_group_layout(bgl) - .format(format) - .build(); - - wgpuBindGroupLayoutRelease(bgl); - return pipeline; -} - -CNNEffect::CNNEffect(const GpuContext& ctx) - : PostProcessEffect(ctx), layer_index_(0), total_layers_(1), - blend_amount_(1.0f), input_view_(nullptr), original_view_(nullptr), - bind_group_(nullptr) { - pipeline_ = create_cnn_pipeline(ctx_.device, ctx_.format, - cnn_layer_shader_wgsl); -} - -CNNEffect::CNNEffect(const GpuContext& ctx, const CNNEffectParams& params) - : PostProcessEffect(ctx), layer_index_(params.layer_index), - total_layers_(params.total_layers), blend_amount_(params.blend_amount), - input_view_(nullptr), original_view_(nullptr), bind_group_(nullptr) { - pipeline_ = create_cnn_pipeline(ctx_.device, ctx_.format, - cnn_layer_shader_wgsl); -} - -void CNNEffect::init(MainSequence* demo) { - PostProcessEffect::init(demo); - demo_ = demo; - params_buffer_.init(ctx_.device); - - // Register auxiliary texture for layer 0 (width_/height_ set by resize()) - if (layer_index_ == 0) { - demo_->register_auxiliary_texture("captured_frame", width_, height_); - } - - // Initialize uniforms BEFORE any bind group creation - uniforms_.update(ctx_.queue, get_common_uniforms()); - - CNNLayerParams params = {layer_index_, blend_amount_, {0.0f, 0.0f}}; - params_buffer_.update(ctx_.queue, params); -} - -void CNNEffect::resize(int width, int height) { - if (width == width_ && height == height_) - return; - - PostProcessEffect::resize(width, height); - - // Only layer 0 owns the captured_frame texture - if (layer_index_ == 0 && demo_) { - demo_->resize_auxiliary_texture("captured_frame", width, height); - } -} - -void CNNEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - if (!bind_group_) { - fprintf(stderr, "CNN render: no bind_group\n"); - return; - } - - float effective_blend = blend_amount_; - if (beat_modulated_) { - effective_blend = blend_amount_ * uniforms.beat_phase * beat_scale_; - } - - CNNLayerParams params = {layer_index_, effective_blend, {0.0f, 0.0f}}; - params_buffer_.update(ctx_.queue, params); - - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} - -void CNNEffect::update_bind_group(WGPUTextureView input_view) { - input_view_ = input_view; - - // Update common uniforms (CRITICAL for UV calculation!) - uniforms_.update(ctx_.queue, get_common_uniforms()); - - // All layers: get captured frame (original input from layer 0) - if (demo_) { - original_view_ = demo_->get_auxiliary_view("captured_frame"); - } - - // Create bind group with original texture - if (bind_group_) - wgpuBindGroupRelease(bind_group_); - - WGPUBindGroupLayout bgl = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0); - // Use clamp (not repeat) to match PyTorch Conv2d zero-padding behavior - WGPUSampler sampler = SamplerCache::Get().get_or_create(ctx_.device, SamplerCache::clamp()); - - bind_group_ = BindGroupBuilder() - .sampler(0, sampler) - .texture(1, input_view_) - .buffer(2, uniforms_.get().buffer, uniforms_.get().size) - .buffer(3, params_buffer_.get().buffer, params_buffer_.get().size) - .texture(4, original_view_ ? original_view_ : input_view_) - .build(ctx_.device, bgl); -} diff --git a/src/gpu/effects/cnn_effect.h b/src/gpu/effects/cnn_effect.h deleted file mode 100644 index 3e2b7ca..0000000 --- a/src/gpu/effects/cnn_effect.h +++ /dev/null @@ -1,53 +0,0 @@ -// CNN post-processing effect header -// Multi-layer neural network stylization - -#pragma once -#include "gpu/effect.h" -#include "gpu/uniform_helper.h" - -struct CNNLayerParams { - int layer_index; - float blend_amount; // Blend: mix(input, output, blend_amount) - float _pad[2]; -}; -static_assert(sizeof(CNNLayerParams) == 16); - -struct CNNEffectParams { - int layer_index = 0; // Which layer to render (0-based) - int total_layers = 1; // Total number of layers in the CNN - float blend_amount = 1.0f; // Final blend with original input -}; - -class CNNEffect : public PostProcessEffect { - public: - explicit CNNEffect(const GpuContext& ctx); - explicit CNNEffect(const GpuContext& ctx, const CNNEffectParams& params); - - void init(MainSequence* demo) override; - void resize(int width, int height) override; - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - void update_bind_group(WGPUTextureView input_view) override; - - // Layer 0 needs framebuffer capture for original input - bool needs_framebuffer_capture() const override { - return layer_index_ == 0; - } - - void set_beat_modulation(bool enabled, float scale = 1.0f) { - beat_modulated_ = enabled; - beat_scale_ = scale; - } - - private: - int layer_index_; - int total_layers_; - float blend_amount_; - bool beat_modulated_ = false; - float beat_scale_ = 1.0f; - WGPUTextureView input_view_; - WGPUTextureView original_view_; - UniformBuffer<CNNLayerParams> params_buffer_; - WGPUBindGroup bind_group_; - MainSequence* demo_ = nullptr; -}; diff --git a/src/gpu/effects/cnn_v2_effect.cc b/src/gpu/effects/cnn_v2_effect.cc deleted file mode 100644 index be856a4..0000000 --- a/src/gpu/effects/cnn_v2_effect.cc +++ /dev/null @@ -1,463 +0,0 @@ -// CNN v2 Effect Implementation - -#include "gpu/effects/cnn_v2_effect.h" - -#if defined(USE_TEST_ASSETS) -#include "test_assets.h" -#else -#include "generated/assets.h" -#endif - -#include "gpu/bind_group_builder.h" -#include "gpu/gpu.h" -#include "util/asset_manager.h" -#include "util/fatal_error.h" -#include <cstring> - -CNNv2Effect::CNNv2Effect(const GpuContext& ctx) - : PostProcessEffect(ctx), - static_pipeline_(nullptr), - static_bind_group_(nullptr), - static_params_buffer_(nullptr), - static_features_tex_(nullptr), - static_features_view_(nullptr), - linear_sampler_(nullptr), - layer_pipeline_(nullptr), - weights_buffer_(nullptr), - input_mip_tex_(nullptr), - current_input_view_(nullptr), - blend_amount_(1.0f), - mip_level_(0), - initialized_(false) { - std::memset(input_mip_view_, 0, sizeof(input_mip_view_)); -} - -CNNv2Effect::CNNv2Effect(const GpuContext& ctx, const CNNv2EffectParams& params) - : PostProcessEffect(ctx), - static_pipeline_(nullptr), - static_bind_group_(nullptr), - static_params_buffer_(nullptr), - static_features_tex_(nullptr), - static_features_view_(nullptr), - linear_sampler_(nullptr), - layer_pipeline_(nullptr), - weights_buffer_(nullptr), - input_mip_tex_(nullptr), - current_input_view_(nullptr), - blend_amount_(params.blend_amount), - mip_level_(0), - initialized_(false) { - std::memset(input_mip_view_, 0, sizeof(input_mip_view_)); -} - -CNNv2Effect::~CNNv2Effect() { - cleanup(); -} - -void CNNv2Effect::init(MainSequence* demo) { - (void)demo; - if (initialized_) return; - - load_weights(); - create_textures(); - create_pipelines(); - - initialized_ = true; -} - -void CNNv2Effect::resize(int width, int height) { - PostProcessEffect::resize(width, height); - cleanup(); - create_textures(); - create_pipelines(); -} - -void CNNv2Effect::load_weights() { - // Load binary weights asset - size_t weights_size = 0; - const uint8_t* weights_data = (const uint8_t*)GetAsset(AssetId::ASSET_WEIGHTS_CNN_V2, &weights_size); - - if (!weights_data || weights_size < 20) { - // Weights not available - effect will skip - return; - } - - // Parse header - const uint32_t* header = (const uint32_t*)weights_data; - uint32_t magic = header[0]; - uint32_t version = header[1]; - uint32_t num_layers = header[2]; - uint32_t total_weights = header[3]; - - FATAL_CHECK(magic != 0x324e4e43, "Invalid CNN v2 weights magic\n"); // 'CNN2' - - // Support both version 1 (16-byte header) and version 2 (20-byte header with mip_level) - // TODO: Version 3 should include feature descriptor for arbitrary layout/ordering - if (version == 1) { - mip_level_ = 0; // Default for v1 - } else if (version == 2) { - mip_level_ = header[4]; - } else { - FATAL_ERROR("Unsupported CNN v2 weights version: %u\n", version); - } - - // Parse layer info (20 bytes per layer) - // Offset depends on version: v1=16 bytes (4 u32), v2=20 bytes (5 u32) - const uint32_t header_u32_count = (version == 1) ? 4 : 5; - const uint32_t* layer_data = header + header_u32_count; - for (uint32_t i = 0; i < num_layers; ++i) { - LayerInfo info; - info.kernel_size = layer_data[i * 5 + 0]; - info.in_channels = layer_data[i * 5 + 1]; - info.out_channels = layer_data[i * 5 + 2]; - info.weight_offset = layer_data[i * 5 + 3]; - info.weight_count = layer_data[i * 5 + 4]; - layer_info_.push_back(info); - } - - // Create GPU storage buffer for weights (skip header + layer info, upload only weights) - size_t header_size = 20; // 5 u32 - size_t layer_info_size = 20 * num_layers; // 5 u32 per layer - size_t weights_offset = header_size + layer_info_size; - size_t weights_only_size = weights_size - weights_offset; - - WGPUBufferDescriptor buffer_desc = {}; - buffer_desc.size = weights_only_size; - buffer_desc.usage = WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst; - buffer_desc.mappedAtCreation = false; - - weights_buffer_ = wgpuDeviceCreateBuffer(ctx_.device, &buffer_desc); - - // Upload only weights (skip header + layer info) - wgpuQueueWriteBuffer(ctx_.queue, weights_buffer_, 0, weights_data + weights_offset, weights_only_size); - - // Create uniform buffers for layer params (one per layer) - for (uint32_t i = 0; i < num_layers; ++i) { - WGPUBufferDescriptor params_desc = {}; - params_desc.size = sizeof(LayerParams); - params_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; - params_desc.mappedAtCreation = false; - - WGPUBuffer buf = wgpuDeviceCreateBuffer(ctx_.device, ¶ms_desc); - layer_params_buffers_.push_back(buf); - } -} - -void CNNv2Effect::create_textures() { - // Static features texture (8×f16 packed as 4×u32) - TextureWithView static_tex = gpu_create_storage_texture_2d( - ctx_.device, width_, height_, WGPUTextureFormat_RGBA32Uint); - static_features_tex_ = static_tex.texture; - static_features_view_ = static_tex.view; - - // Input texture with mips (for multi-scale features) - TextureWithView input_mip = gpu_create_texture_2d( - ctx_.device, width_, height_, WGPUTextureFormat_RGBA8Unorm, - WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst, 3); - input_mip_tex_ = input_mip.texture; - - for (int i = 0; i < 3; ++i) { - input_mip_view_[i] = - gpu_create_mip_view(input_mip_tex_, WGPUTextureFormat_RGBA8Unorm, i); - } - - // Create 2 layer textures (ping-pong buffers for intermediate results) - // Each stores 8×f16 channels packed as 4×u32 - for (int i = 0; i < 2; ++i) { - TextureWithView layer = gpu_create_storage_texture_2d( - ctx_.device, width_, height_, WGPUTextureFormat_RGBA32Uint); - layer_textures_.push_back(layer.texture); - layer_views_.push_back(layer.view); - } - - // Create uniform buffer for static feature params - WGPUBufferDescriptor params_desc = {}; - params_desc.size = sizeof(StaticFeatureParams); - params_desc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst; - params_desc.mappedAtCreation = false; - static_params_buffer_ = wgpuDeviceCreateBuffer(ctx_.device, ¶ms_desc); -} - -void CNNv2Effect::create_pipelines() { - // Create linear sampler for bilinear interpolation - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; - sampler_desc.lodMinClamp = 0.0f; - sampler_desc.lodMaxClamp = 32.0f; - sampler_desc.maxAnisotropy = 1; - - linear_sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); - - // Static features compute pipeline - size_t shader_size = 0; - const char* static_code = (const char*)GetAsset(AssetId::ASSET_SHADER_CNN_V2_STATIC, &shader_size); - - if (!static_code || shader_size == 0) { - // Shader not available (e.g., in test mode) - skip pipeline creation - return; - } - - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(static_code); - - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; - - // Create bind group layout for static features compute - // Bindings: 0=input_tex, 1=input_mip1, 2=input_mip2, 3=depth_tex, 4=output, 5=params, 6=linear_sampler - WGPUBindGroupLayout static_bgl = - BindGroupLayoutBuilder() - .texture(0, WGPUShaderStage_Compute) - .texture(1, WGPUShaderStage_Compute) - .texture(2, WGPUShaderStage_Compute) - .texture(3, WGPUShaderStage_Compute) - .storage_texture(4, WGPUShaderStage_Compute, - WGPUTextureFormat_RGBA32Uint) - .uniform(5, WGPUShaderStage_Compute, sizeof(StaticFeatureParams)) - .sampler(6, WGPUShaderStage_Compute) - .build(ctx_.device); - - // Update pipeline layout - WGPUPipelineLayoutDescriptor pl_desc = {}; - pl_desc.bindGroupLayoutCount = 1; - pl_desc.bindGroupLayouts = &static_bgl; - WGPUPipelineLayout pipeline_layout = wgpuDeviceCreatePipelineLayout(ctx_.device, &pl_desc); - - // Recreate pipeline with proper layout - WGPUComputePipelineDescriptor pipeline_desc2 = {}; - pipeline_desc2.compute.module = wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc); - pipeline_desc2.compute.entryPoint = str_view("main"); - pipeline_desc2.layout = pipeline_layout; - - if (static_pipeline_) wgpuComputePipelineRelease(static_pipeline_); - static_pipeline_ = wgpuDeviceCreateComputePipeline(ctx_.device, &pipeline_desc2); - - wgpuShaderModuleRelease(pipeline_desc2.compute.module); - wgpuPipelineLayoutRelease(pipeline_layout); - wgpuBindGroupLayoutRelease(static_bgl); - - // CNN layer compute pipeline (storage buffer version) - if (layer_info_.empty()) return; // No weights loaded - - size_t layer_shader_size = 0; - const char* layer_code = (const char*)GetAsset(AssetId::ASSET_SHADER_CNN_V2_COMPUTE, &layer_shader_size); - - if (!layer_code || layer_shader_size == 0) return; - - WGPUShaderSourceWGSL layer_wgsl = {}; - layer_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL; - layer_wgsl.code = str_view(layer_code); - - WGPUShaderModuleDescriptor layer_shader_desc = {}; - layer_shader_desc.nextInChain = &layer_wgsl.chain; - - WGPUShaderModule layer_module = wgpuDeviceCreateShaderModule(ctx_.device, &layer_shader_desc); - if (!layer_module) return; - - // Create bind group layout for layer compute - // 0=static_features, 1=layer_input, 2=output, 3=weights, 4=params, 5=original_input - WGPUBindGroupLayout layer_bgl = - BindGroupLayoutBuilder() - .uint_texture(0, WGPUShaderStage_Compute) - .uint_texture(1, WGPUShaderStage_Compute) - .storage_texture(2, WGPUShaderStage_Compute, - WGPUTextureFormat_RGBA32Uint) - .storage(3, WGPUShaderStage_Compute) - .uniform(4, WGPUShaderStage_Compute, sizeof(LayerParams)) - .texture(5, WGPUShaderStage_Compute) - .build(ctx_.device); - - WGPUPipelineLayoutDescriptor layer_pl_desc = {}; - layer_pl_desc.bindGroupLayoutCount = 1; - layer_pl_desc.bindGroupLayouts = &layer_bgl; - - WGPUPipelineLayout layer_pipeline_layout = wgpuDeviceCreatePipelineLayout(ctx_.device, &layer_pl_desc); - - WGPUComputePipelineDescriptor layer_pipeline_desc = {}; - layer_pipeline_desc.compute.module = layer_module; - layer_pipeline_desc.compute.entryPoint = str_view("main"); - layer_pipeline_desc.layout = layer_pipeline_layout; - - layer_pipeline_ = wgpuDeviceCreateComputePipeline(ctx_.device, &layer_pipeline_desc); - - wgpuShaderModuleRelease(layer_module); - wgpuPipelineLayoutRelease(layer_pipeline_layout); - wgpuBindGroupLayoutRelease(layer_bgl); -} - -void CNNv2Effect::update_bind_group(WGPUTextureView input_view) { - if (!static_pipeline_) return; - - // Cache input view - current_input_view_ = input_view; - - // Release old bind group - if (static_bind_group_) { - wgpuBindGroupRelease(static_bind_group_); - static_bind_group_ = nullptr; - } - - // Create bind group for static features compute (manual for storage texture binding) - WGPUBindGroupEntry bg_entries[7] = {}; - bg_entries[0].binding = 0; - bg_entries[0].textureView = input_view; - bg_entries[1].binding = 1; - bg_entries[1].textureView = input_mip_view_[0]; - bg_entries[2].binding = 2; - bg_entries[2].textureView = - input_mip_view_[1] ? input_mip_view_[1] : input_mip_view_[0]; - bg_entries[3].binding = 3; - bg_entries[3].textureView = input_view; - bg_entries[4].binding = 4; - bg_entries[4].textureView = static_features_view_; - bg_entries[5].binding = 5; - bg_entries[5].buffer = static_params_buffer_; - bg_entries[5].size = sizeof(StaticFeatureParams); - bg_entries[6].binding = 6; - bg_entries[6].sampler = linear_sampler_; - - WGPUBindGroupLayout layout = - wgpuComputePipelineGetBindGroupLayout(static_pipeline_, 0); - WGPUBindGroupDescriptor bg_desc = {}; - bg_desc.layout = layout; - bg_desc.entryCount = 7; - bg_desc.entries = bg_entries; - static_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); - wgpuBindGroupLayoutRelease(layout); - - // Create layer bind groups - if (!layer_pipeline_ || layer_info_.empty()) return; - - // Release old layer bind groups - for (auto bg : layer_bind_groups_) { - wgpuBindGroupRelease(bg); - } - layer_bind_groups_.clear(); - - // Get bind group layout from layer pipeline - WGPUBindGroupLayout layer_bgl = wgpuComputePipelineGetBindGroupLayout(layer_pipeline_, 0); - - // Create bind group for each layer - for (size_t i = 0; i < layer_info_.size(); ++i) { - WGPUTextureView layer_input = - (i == 0) ? static_features_view_ : layer_views_[i % 2]; - - WGPUBindGroup layer_bg = - BindGroupBuilder() - .texture(0, static_features_view_) - .texture(1, layer_input) - .texture(2, layer_views_[(i + 1) % 2]) - .buffer(3, weights_buffer_, wgpuBufferGetSize(weights_buffer_)) - .buffer(4, layer_params_buffers_[i], sizeof(LayerParams)) - .texture(5, input_view) - .build(ctx_.device, layer_bgl); - - layer_bind_groups_.push_back(layer_bg); - } - - wgpuBindGroupLayoutRelease(layer_bgl); -} - -void CNNv2Effect::compute(WGPUCommandEncoder encoder, - const CommonPostProcessUniforms& uniforms) { - if (!initialized_ || !static_pipeline_ || !static_bind_group_) return; - - float effective_blend = blend_amount_; - if (beat_modulated_) { - effective_blend = blend_amount_ * uniforms.beat_phase * beat_scale_; - } - - // Update static feature params - StaticFeatureParams static_params; - static_params.mip_level = mip_level_; - static_params.padding[0] = 0; - static_params.padding[1] = 0; - static_params.padding[2] = 0; - wgpuQueueWriteBuffer(ctx_.queue, static_params_buffer_, 0, &static_params, sizeof(static_params)); - - // Pass 1: Compute static features - WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); - - wgpuComputePassEncoderSetPipeline(pass, static_pipeline_); - wgpuComputePassEncoderSetBindGroup(pass, 0, static_bind_group_, 0, nullptr); - - // Dispatch workgroups (8×8 threads per group) - uint32_t workgroups_x = (width_ + 7) / 8; - uint32_t workgroups_y = (height_ + 7) / 8; - wgpuComputePassEncoderDispatchWorkgroups(pass, workgroups_x, workgroups_y, 1); - - wgpuComputePassEncoderEnd(pass); - wgpuComputePassEncoderRelease(pass); - - // Execute CNN layer passes - if (!layer_pipeline_ || layer_bind_groups_.empty()) return; - - // Update layer params (each layer has own buffer) - for (size_t i = 0; i < layer_info_.size(); ++i) { - const LayerInfo& info = layer_info_[i]; - - LayerParams params; - params.kernel_size = info.kernel_size; - params.in_channels = info.in_channels; - params.out_channels = info.out_channels; - params.weight_offset = info.weight_offset; - params.is_output_layer = (i == layer_info_.size() - 1) ? 1 : 0; - params.blend_amount = effective_blend; - params.is_layer_0 = (i == 0) ? 1 : 0; - - wgpuQueueWriteBuffer(ctx_.queue, layer_params_buffers_[i], 0, ¶ms, sizeof(params)); - - WGPUComputePassEncoder layer_pass = wgpuCommandEncoderBeginComputePass(encoder, nullptr); - - wgpuComputePassEncoderSetPipeline(layer_pass, layer_pipeline_); - wgpuComputePassEncoderSetBindGroup(layer_pass, 0, layer_bind_groups_[i], 0, nullptr); - - wgpuComputePassEncoderDispatchWorkgroups(layer_pass, workgroups_x, workgroups_y, 1); - - wgpuComputePassEncoderEnd(layer_pass); - wgpuComputePassEncoderRelease(layer_pass); - } -} - -void CNNv2Effect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - (void)pass; - (void)uniforms; - // Compute-only effect, rendering is done by default composite pass -} - -void CNNv2Effect::cleanup() { - if (static_features_view_) wgpuTextureViewRelease(static_features_view_); - if (static_features_tex_) wgpuTextureRelease(static_features_tex_); - if (static_bind_group_) wgpuBindGroupRelease(static_bind_group_); - if (static_params_buffer_) wgpuBufferRelease(static_params_buffer_); - if (static_pipeline_) wgpuComputePipelineRelease(static_pipeline_); - if (linear_sampler_) wgpuSamplerRelease(linear_sampler_); - - if (layer_pipeline_) wgpuComputePipelineRelease(layer_pipeline_); - if (weights_buffer_) wgpuBufferRelease(weights_buffer_); - for (auto buf : layer_params_buffers_) wgpuBufferRelease(buf); - layer_params_buffers_.clear(); - - for (int i = 0; i < 3; ++i) { - if (input_mip_view_[i]) wgpuTextureViewRelease(input_mip_view_[i]); - } - if (input_mip_tex_) wgpuTextureRelease(input_mip_tex_); - - for (auto view : layer_views_) wgpuTextureViewRelease(view); - for (auto tex : layer_textures_) wgpuTextureRelease(tex); - for (auto bg : layer_bind_groups_) wgpuBindGroupRelease(bg); - - layer_views_.clear(); - layer_textures_.clear(); - layer_bind_groups_.clear(); - layer_info_.clear(); - - initialized_ = false; -} diff --git a/src/gpu/effects/cnn_v2_effect.h b/src/gpu/effects/cnn_v2_effect.h deleted file mode 100644 index d530d3b..0000000 --- a/src/gpu/effects/cnn_v2_effect.h +++ /dev/null @@ -1,88 +0,0 @@ -// CNN v2 Effect - Parametric Static Features -// Multi-pass post-processing with 7D feature input -// Supports per-layer kernel sizes (e.g., 1×1, 3×3, 5×5) - -#pragma once -#include "gpu/effect.h" -#include <vector> - -struct CNNv2EffectParams { - float blend_amount = 1.0f; -}; - -class CNNv2Effect : public PostProcessEffect { -public: - explicit CNNv2Effect(const GpuContext& ctx); - explicit CNNv2Effect(const GpuContext& ctx, const CNNv2EffectParams& params); - ~CNNv2Effect(); - - void init(MainSequence* demo) override; - void resize(int width, int height) override; - void compute(WGPUCommandEncoder encoder, - const CommonPostProcessUniforms& uniforms) override; - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - void update_bind_group(WGPUTextureView input_view) override; - - void set_beat_modulation(bool enabled, float scale = 1.0f) { - beat_modulated_ = enabled; - beat_scale_ = scale; - } - -private: - struct LayerInfo { - uint32_t kernel_size; - uint32_t in_channels; - uint32_t out_channels; - uint32_t weight_offset; - uint32_t weight_count; - }; - - struct LayerParams { - uint32_t kernel_size; - uint32_t in_channels; - uint32_t out_channels; - uint32_t weight_offset; - uint32_t is_output_layer; - float blend_amount; - uint32_t is_layer_0; - }; - - struct StaticFeatureParams { - uint32_t mip_level; - uint32_t padding[3]; - }; - - void create_textures(); - void create_pipelines(); - void load_weights(); - void cleanup(); - - // Static features compute - WGPUComputePipeline static_pipeline_; - WGPUBindGroup static_bind_group_; - WGPUBuffer static_params_buffer_; - WGPUTexture static_features_tex_; - WGPUTextureView static_features_view_; - WGPUSampler linear_sampler_; - - // CNN layers (storage buffer architecture) - WGPUComputePipeline layer_pipeline_; // Single pipeline for all layers - WGPUBuffer weights_buffer_; // Storage buffer for weights - std::vector<WGPUBuffer> layer_params_buffers_; // Uniform buffers (one per layer) - std::vector<LayerInfo> layer_info_; // Layer metadata - std::vector<WGPUBindGroup> layer_bind_groups_; // Per-layer bind groups - std::vector<WGPUTexture> layer_textures_; // Ping-pong buffers - std::vector<WGPUTextureView> layer_views_; - - // Input mips - WGPUTexture input_mip_tex_; - WGPUTextureView input_mip_view_[3]; - WGPUTextureView current_input_view_; - - float blend_amount_ = 1.0f; - bool beat_modulated_ = false; - float beat_scale_ = 1.0f; - uint32_t mip_level_ = 0; - bool initialized_; -}; diff --git a/src/gpu/effects/distort_effect.cc b/src/gpu/effects/distort_effect.cc deleted file mode 100644 index 97622b2..0000000 --- a/src/gpu/effects/distort_effect.cc +++ /dev/null @@ -1,36 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the DistortEffect. - -#include "gpu/demo_effects.h" -#include "gpu/gpu.h" - -// --- DistortEffect --- -DistortEffect::DistortEffect(const GpuContext& ctx) - : DistortEffect(ctx, DistortParams()) { -} - -DistortEffect::DistortEffect(const GpuContext& ctx, const DistortParams& params) - : PostProcessEffect(ctx), params_(params) { - params_buffer_.init(ctx_.device); - pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, - distort_shader_wgsl); -} - -void DistortEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - // Populate CommonPostProcessUniforms - uniforms_.update(ctx_.queue, uniforms); - - // Populate DistortParams - const DistortParams distort_p = { - .strength = params_.strength, - .speed = params_.speed, - }; - params_buffer_.update(ctx_.queue, distort_p); - - PostProcessEffect::render(pass, uniforms); -} - -void DistortEffect::update_bind_group(WGPUTextureView v) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_.get(), params_buffer_); -}
\ No newline at end of file diff --git a/src/gpu/effects/fade_effect.cc b/src/gpu/effects/fade_effect.cc deleted file mode 100644 index 93684d8..0000000 --- a/src/gpu/effects/fade_effect.cc +++ /dev/null @@ -1,98 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the FadeEffect - fades to/from black based on time. - -#include "gpu/effects/fade_effect.h" -#include "gpu/effects/post_process_helper.h" -#include <cmath> - -struct FadeParams { - float fade_amount; - float _pad[3]; -}; -static_assert(sizeof(FadeParams) == 16, "FadeParams must be 16 bytes for WGSL alignment"); - -FadeEffect::FadeEffect(const GpuContext& ctx) : PostProcessEffect(ctx) { - const char* shader_code = R"( - struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, - }; - - struct CommonUniforms { - resolution: vec2<f32>, - _pad0: f32, - _pad1: f32, - aspect_ratio: f32, - time: f32, - beat: f32, - audio_intensity: f32, - }; - - struct FadeParams { - fade_amount: f32, - _pad0: f32, - _pad1: f32, - _pad2: f32, - }; - - @group(0) @binding(0) var inputSampler: sampler; - @group(0) @binding(1) var inputTexture: texture_2d<f32>; - @group(0) @binding(2) var<uniform> uniforms: CommonUniforms; - @group(0) @binding(3) var<uniform> params: FadeParams; - - @vertex - fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput { - var output: VertexOutput; - var pos = array<vec2<f32>, 3>( - vec2<f32>(-1.0, -1.0), - vec2<f32>(3.0, -1.0), - vec2<f32>(-1.0, 3.0) - ); - output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0); - output.uv = pos[vertexIndex] * 0.5 + 0.5; - return output; - } - - @fragment - fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> { - let color = textureSample(inputTexture, inputSampler, input.uv); - // Fade to black: 0.0 = black, 1.0 = full color - return vec4<f32>(color.rgb * params.fade_amount, color.a); - } - )"; - - pipeline_ = - create_post_process_pipeline(ctx_.device, ctx_.format, shader_code); - params_buffer_ = gpu_create_buffer( - ctx_.device, 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); -} - -void FadeEffect::update_bind_group(WGPUTextureView input_view) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - uniforms_.get(), params_buffer_); -} - -void FadeEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - - // Example fade pattern: fade in at start, fade out at end - // Customize this based on your needs - float fade_amount = 1.0f; - if (uniforms.time < 2.0f) { - // Fade in from black over first 2 seconds - fade_amount = uniforms.time / 2.0f; - } else if (uniforms.time > 36.0f) { - // Fade out to black after 36 seconds - fade_amount = 1.0f - ((uniforms.time - 36.0f) / 4.0f); - fade_amount = fmaxf(fade_amount, 0.0f); - } - - FadeParams params = {fade_amount, {0.0f, 0.0f, 0.0f}}; - wgpuQueueWriteBuffer(ctx_.queue, params_buffer_.buffer, 0, ¶ms, - sizeof(params)); - - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} diff --git a/src/gpu/effects/fade_effect.h b/src/gpu/effects/fade_effect.h deleted file mode 100644 index 3360a5f..0000000 --- a/src/gpu/effects/fade_effect.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the 64k demo project. -// It declares the FadeEffect - fades to/from black. - -#pragma once - -#include "gpu/effect.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" -#include "gpu/uniform_helper.h" - -class FadeEffect : public PostProcessEffect { - public: - FadeEffect(const GpuContext& ctx); - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - void update_bind_group(WGPUTextureView input_view) override; - - private: - GpuBuffer params_buffer_; -}; diff --git a/src/gpu/effects/flash_cube_effect.cc b/src/gpu/effects/flash_cube_effect.cc deleted file mode 100644 index 506f11c..0000000 --- a/src/gpu/effects/flash_cube_effect.cc +++ /dev/null @@ -1,104 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the FlashCubeEffect - a flashing background cube with Perlin -// noise. - -#include "gpu/effects/flash_cube_effect.h" -#include "generated/assets.h" -#include "util/asset_manager_utils.h" -#include <cmath> -#include <iostream> - -FlashCubeEffect::FlashCubeEffect(const GpuContext& ctx) : Effect(ctx) { -} - -void FlashCubeEffect::resize(int width, int height) { - if (width == width_ && height == height_) - return; - - Effect::resize(width, height); - - if (!initialized_) - return; - - renderer_.resize(width_, height_); -} - -void FlashCubeEffect::init(MainSequence* demo) { - (void)demo; - WGPUTextureFormat format = demo->gpu_ctx.format; - - renderer_.init(ctx_.device, ctx_.queue, ctx_.format); - renderer_.resize(width_, height_); - initialized_ = true; - - // Texture Manager - texture_manager_.init(ctx_.device, ctx_.queue); - - // Load Perlin noise texture - TextureAsset noise_tex = GetTextureAsset(AssetId::ASSET_NOISE_TEX); - if (noise_tex.pixels && noise_tex.width == 256 && noise_tex.height == 256) { - texture_manager_.create_texture("noise", noise_tex.width, noise_tex.height, - noise_tex.pixels); - renderer_.set_noise_texture(texture_manager_.get_texture_view("noise")); - } else { - std::cerr << "Failed to load NOISE_TEX asset for FlashCubeEffect." - << std::endl; - } - - // Create a very large background cube - // Scale and distance ensure it's clearly behind foreground objects - scene_.clear(); - Object3D cube(ObjectType::BOX); - cube.position = vec3(0, 0, 0); - cube.scale = vec3(100.0f, 100.0f, 100.0f); // Much larger cube - cube.color = vec4(0.3f, 0.3f, 0.5f, 1.0f); // Dark blue base color - scene_.add_object(cube); -} - -void FlashCubeEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - // Detect beat changes for flash trigger (using intensity as proxy for beat - // hits) Intensity spikes on beats, so we can use it to trigger flashes - if (uniforms.audio_intensity > 0.5f && - flash_intensity_ < 0.3f) { // High intensity + flash cooled down - flash_intensity_ = 1.0f; // Trigger full flash - } - - // Exponential decay of flash - flash_intensity_ *= 0.90f; // Slower fade for more visible effect - - // Always have base brightness, add flash on top - float base_brightness = 0.2f; - float flash_boost = - base_brightness + flash_intensity_ * 0.8f; // 0.2 to 1.0 range - - scene_.objects[0].color = - vec4(0.4f * flash_boost, // Reddish tint - 0.6f * flash_boost, // More green - 1.0f * flash_boost, // Strong blue for background feel - 1.0f); - - // Slowly rotate the cube for visual interest - scene_.objects[0].rotation = - quat::from_axis(vec3(0.3f, 1, 0.2f), uniforms.time * 0.05f); - - // Position camera OUTSIDE the cube looking at it from a distance - // This way we see the cube as a background element - float cam_distance = 150.0f; // Much farther to ensure it's behind everything - float orbit_angle = uniforms.time * 0.1f; - - camera_.set_look_at( - vec3(std::sin(orbit_angle) * cam_distance, - std::cos(orbit_angle * 0.3f) * 30.0f, - std::cos(orbit_angle) * cam_distance), // Camera orbits around - vec3(0, 0, 0), // Look at cube center - vec3(0, 1, 0)); - - camera_.aspect_ratio = uniforms.aspect_ratio; - // Extend far plane to accommodate distant camera position (150 units + cube - // size) - camera_.far_plane = 300.0f; - - // Draw the cube - renderer_.draw(pass, scene_, camera_, uniforms.time); -} diff --git a/src/gpu/effects/flash_cube_effect.h b/src/gpu/effects/flash_cube_effect.h deleted file mode 100644 index df30b5b..0000000 --- a/src/gpu/effects/flash_cube_effect.h +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of the 64k demo project. -// It implements a flashing cube effect with Perlin noise texture. -// The cube is large and we're inside it, flashing in sync with the beat. - -#pragma once -#include "3d/camera.h" -#include "3d/renderer.h" -#include "3d/scene.h" -#include "gpu/effect.h" -#include "gpu/texture_manager.h" - -class FlashCubeEffect : public Effect { - public: - FlashCubeEffect(const GpuContext& ctx); - void init(MainSequence* demo) override; - void resize(int width, int height) override; - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - - private: - Renderer3D renderer_; - TextureManager texture_manager_; - Scene scene_; - Camera camera_; - float last_beat_ = 0.0f; - float flash_intensity_ = 0.0f; - bool initialized_ = false; -}; diff --git a/src/gpu/effects/flash_effect.cc b/src/gpu/effects/flash_effect.cc deleted file mode 100644 index e53cbce..0000000 --- a/src/gpu/effects/flash_effect.cc +++ /dev/null @@ -1,94 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the FlashEffect - brief flash on u.beat hits. -// Now supports parameterized color with per-frame animation. - -#include "gpu/effects/flash_effect.h" -#include "gpu/effects/post_process_helper.h" -#include <cmath> - -// Backward compatibility constructor (delegates to parameterized constructor) -FlashEffect::FlashEffect(const GpuContext& ctx) - : FlashEffect(ctx, FlashEffectParams{}) { -} - -// Parameterized constructor -FlashEffect::FlashEffect(const GpuContext& ctx, const FlashEffectParams& params) - : PostProcessEffect(ctx), params_(params) { - const char* shader_code = R"( - struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, - }; - - struct Uniforms { - flash_intensity: f32, - audio_intensity: f32, - flash_color: vec3<f32>, // Parameterized color - _pad: f32, - }; - - @group(0) @binding(0) var inputSampler: sampler; - @group(0) @binding(1) var inputTexture: texture_2d<f32>; - @group(0) @binding(2) var<uniform> uniforms: Uniforms; - - @vertex - fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput { - var output: VertexOutput; - var pos = array<vec2<f32>, 3>( - vec2<f32>(-1.0, -1.0), - vec2<f32>(3.0, -1.0), - vec2<f32>(-1.0, 3.0) - ); - output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0); - output.uv = pos[vertexIndex] * 0.5 + 0.5; - return output; - } - - @fragment - fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> { - let color = textureSample(inputTexture, inputSampler, input.uv); - // Use parameterized flash color instead of hardcoded white - var flashed = mix(color.rgb, uniforms.flash_color, uniforms.flash_intensity); - return vec4<f32>(flashed, color.a); - } - )"; - - pipeline_ = - create_post_process_pipeline(ctx_.device, ctx_.format, shader_code); - flash_uniforms_.init(ctx_.device); -} - -void FlashEffect::update_bind_group(WGPUTextureView input_view) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - flash_uniforms_.get(), {}); -} - -void FlashEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - // Trigger flash based on configured threshold - if (uniforms.audio_intensity > params_.trigger_threshold && flash_intensity_ < 0.2f) { - flash_intensity_ = 0.8f; // Trigger flash - } - - // Decay based on configured rate - flash_intensity_ *= params_.decay_rate; - - // *** PER-FRAME PARAMETER COMPUTATION *** - // Animate color based on time and beat - const float r = params_.color[0] * (0.5f + 0.5f * sinf(uniforms.time * 0.5f)); - const float g = params_.color[1] * (0.5f + 0.5f * cosf(uniforms.time * 0.7f)); - const float b = params_.color[2] * (1.0f + 0.3f * uniforms.beat_phase); - - // Update uniforms with computed (animated) values - const FlashUniforms u = { - .flash_intensity = flash_intensity_, - .intensity = uniforms.audio_intensity, - ._pad1 = {0.0f, 0.0f}, // Padding for vec3 alignment - .color = {r, g, b}, // Time-dependent, computed every frame - ._pad2 = 0.0f}; - flash_uniforms_.update(ctx_.queue, u); - - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} diff --git a/src/gpu/effects/flash_effect.h b/src/gpu/effects/flash_effect.h deleted file mode 100644 index 1ac75a4..0000000 --- a/src/gpu/effects/flash_effect.h +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of the 64k demo project. -// It declares the FlashEffect - brief white flash on beat hits. - -#pragma once - -#include "gpu/effect.h" -#include "gpu/gpu.h" -#include "gpu/uniform_helper.h" - -// Parameters for FlashEffect (set at construction time) -struct FlashEffectParams { - float color[3] = {1.0f, 1.0f, 1.0f}; // Default: white - float decay_rate = 0.98f; // Default: fast decay - float trigger_threshold = 0.7f; // Default: trigger on strong beats -}; - -// Uniform data sent to GPU shader -// IMPORTANT: Must match WGSL struct layout with proper alignment -// vec3<f32> in WGSL has 16-byte alignment, not 12-byte! -struct FlashUniforms { - float flash_intensity; // offset 0 - float intensity; // offset 4 - float _pad1[2]; // offset 8-15 (padding for vec3 alignment) - float color[3]; // offset 16-27 (vec3 aligned to 16 bytes) - float _pad2; // offset 28-31 -}; -static_assert(sizeof(FlashUniforms) == 32, - "FlashUniforms must be 32 bytes for WGSL alignment"); - -class FlashEffect : public PostProcessEffect { - public: - // Backward compatibility constructor (uses default params) - FlashEffect(const GpuContext& ctx); - // New parameterized constructor - FlashEffect(const GpuContext& ctx, const FlashEffectParams& params); - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - void update_bind_group(WGPUTextureView input_view) override; - - private: - FlashEffectParams params_; - UniformBuffer<FlashUniforms> flash_uniforms_; - UniformBuffer<FlashEffectParams> params_buffer_; - float flash_intensity_ = 0.0f; -}; diff --git a/src/gpu/effects/gaussian_blur_effect.cc b/src/gpu/effects/gaussian_blur_effect.cc deleted file mode 100644 index 4421e33..0000000 --- a/src/gpu/effects/gaussian_blur_effect.cc +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the GaussianBlurEffect with parameterization. - -#include "gpu/demo_effects.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" - -// --- GaussianBlurEffect --- - -// Backward compatibility constructor (delegates to parameterized constructor) -GaussianBlurEffect::GaussianBlurEffect(const GpuContext& ctx) - : GaussianBlurEffect(ctx, GaussianBlurParams{}) { -} - -// Parameterized constructor -GaussianBlurEffect::GaussianBlurEffect(const GpuContext& ctx, - const GaussianBlurParams& params) - : PostProcessEffect(ctx), params_(params) { - pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, - gaussian_blur_shader_wgsl); - params_buffer_.init(ctx_.device); -} - -void GaussianBlurEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - // Update uniforms with current state and parameters - uniforms_.update(ctx_.queue, uniforms); - params_buffer_.update(ctx_.queue, params_); - - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} - -void GaussianBlurEffect::update_bind_group(WGPUTextureView input_view) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - uniforms_.get(), params_buffer_.get()); -} diff --git a/src/gpu/effects/heptagon_effect.cc b/src/gpu/effects/heptagon_effect.cc deleted file mode 100644 index 724eabb..0000000 --- a/src/gpu/effects/heptagon_effect.cc +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the HeptagonEffect. - -#include "gpu/demo_effects.h" -#include "gpu/gpu.h" -#include "util/mini_math.h" - -// --- HeptagonEffect --- -HeptagonEffect::HeptagonEffect(const GpuContext& ctx) : Effect(ctx) { - // uniforms_ is initialized by Effect base class - ResourceBinding bindings[] = {{uniforms_.get(), WGPUBufferBindingType_Uniform}}; - pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, main_shader_wgsl, - bindings, 1); - pass_.vertex_count = 21; -} -void HeptagonEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline); - wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, pass_.vertex_count, 1, 0, 0); -} diff --git a/src/gpu/effects/hybrid_3d_effect.cc b/src/gpu/effects/hybrid_3d_effect.cc deleted file mode 100644 index a46ab4c..0000000 --- a/src/gpu/effects/hybrid_3d_effect.cc +++ /dev/null @@ -1,147 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the Hybrid3DEffect. - -#include "gpu/effects/hybrid_3d_effect.h" -#include "generated/assets.h" -#include "util/asset_manager_utils.h" -#include <cassert> -#include <cmath> -#include <iostream> - -Hybrid3DEffect::Hybrid3DEffect(const GpuContext& ctx) : Effect(ctx) { -} - -void Hybrid3DEffect::resize(int width, int height) { - if (width == width_ && height == height_) - return; - - Effect::resize(width, height); - - if (!initialized_) - return; - - renderer_.resize(width_, height_); -} - -void Hybrid3DEffect::init(MainSequence* demo) { - (void)demo; - WGPUTextureFormat format = - demo->gpu_ctx.format; // Get current format from MainSequence (might be - // different than constructor if resized) - - renderer_.init(ctx_.device, ctx_.queue, ctx_.format); - renderer_.resize(width_, height_); - initialized_ = true; - - // Texture Manager - texture_manager_.init(ctx_.device, ctx_.queue); - - // Load Noise Asset - TextureAsset noise_tex = GetTextureAsset(AssetId::ASSET_NOISE_TEX); - if (noise_tex.pixels && noise_tex.width == 256 && noise_tex.height == 256) { - texture_manager_.create_texture("noise", noise_tex.width, noise_tex.height, - noise_tex.pixels); - renderer_.set_noise_texture(texture_manager_.get_texture_view("noise")); - } else { - std::cerr << "Failed to load NOISE_TEX asset." << std::endl; - } - - // Setup Scene - scene_.clear(); - Object3D center(ObjectType::BOX); // Use BOX for bumps - center.position = vec3(0, 0, 0); - center.color = vec4(1, 0, 0, 1); - scene_.add_object(center); - - for (int i = 0; i < 8; ++i) { - ObjectType type = ObjectType::SPHERE; - if (i % 3 == 1) - type = ObjectType::TORUS; - if (i % 3 == 2) - type = ObjectType::BOX; - - Object3D obj(type); - - float angle = (i / 8.0f) * 6.28318f; - - obj.position = vec3(std::cos(angle) * 4.0f, 0, std::sin(angle) * 4.0f); - - obj.scale = vec3(0.7f, 0.7f, 0.7f); // Increased scale by 40% - - if (type == ObjectType::SPHERE) - obj.color = vec4(0, 1, 0, 1); - - else if (type == ObjectType::TORUS) - obj.color = vec4(0, 0.5, 1, 1); - else - obj.color = vec4(1, 1, 0, 1); - - scene_.add_object(obj); - } -} - -// Cubic ease-in/out function for non-linear motion - -static float ease_in_out_cubic(float t) { - t *= 2.0f; - - if (t < 1.0f) { - return 0.5f * t * t * t; - } - - t -= 2.0f; - - return 0.5f * (t * t * t + 2.0f); -} - -void Hybrid3DEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - // Animate Objects - - for (size_t i = 1; i < scene_.objects.size(); ++i) { - scene_.objects[i].rotation = - quat::from_axis(vec3(0, 1, 0), uniforms.time * 2.0f + i); - - scene_.objects[i].position.y = std::sin(uniforms.time * 3.0f + i) * 1.5f; - } - - // Camera jumps every other pattern (2 seconds) for dramatic effect - int pattern_num = (int)(uniforms.time / 2.0f); - int camera_preset = pattern_num % 4; // Cycle through 4 different angles - - vec3 cam_pos, cam_target; - - switch (camera_preset) { - case 0: // High angle, orbiting - { - float angle = uniforms.time * 0.5f; - cam_pos = vec3(std::sin(angle) * 12.0f, 8.0f, std::cos(angle) * 12.0f); - cam_target = vec3(0, 0, 0); - } break; - case 1: // Low angle, close-up - { - float angle = uniforms.time * 0.3f + 1.57f; // Offset angle - cam_pos = vec3(std::sin(angle) * 6.0f, 2.0f, std::cos(angle) * 6.0f); - cam_target = vec3(0, 1, 0); - } break; - case 2: // Side view, sweeping - { - float sweep = std::sin(uniforms.time * 0.4f) * 10.0f; - cam_pos = vec3(sweep, 5.0f, 8.0f); - cam_target = vec3(0, 0, 0); - } break; - case 3: // Top-down, rotating - { - float angle = uniforms.time * 0.6f; - cam_pos = vec3(std::sin(angle) * 5.0f, 12.0f, std::cos(angle) * 5.0f); - cam_target = vec3(0, 0, 0); - } break; - } - - camera_.set_look_at(cam_pos, cam_target, vec3(0, 1, 0)); - camera_.aspect_ratio = uniforms.aspect_ratio; - - // Draw - - renderer_.draw(pass, scene_, camera_, uniforms.time); -} diff --git a/src/gpu/effects/hybrid_3d_effect.h b/src/gpu/effects/hybrid_3d_effect.h deleted file mode 100644 index 818b65c..0000000 --- a/src/gpu/effects/hybrid_3d_effect.h +++ /dev/null @@ -1,29 +0,0 @@ -// This file is part of the 64k demo project. -// It defines the Hybrid3DEffect, integrating the 3D renderer into the demo -// timeline. - -#pragma once - -#include "3d/camera.h" -#include "3d/renderer.h" -#include "3d/scene.h" -#include "gpu/effect.h" -#include "gpu/texture_manager.h" - -class Hybrid3DEffect : public Effect { - public: - Hybrid3DEffect(const GpuContext& ctx); - virtual ~Hybrid3DEffect() override = default; - - void init(MainSequence* demo) override; - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - void resize(int width, int height) override; - - private: - Renderer3D renderer_; - TextureManager texture_manager_; - Scene scene_; - Camera camera_; - bool initialized_ = false; -}; diff --git a/src/gpu/effects/moving_ellipse_effect.cc b/src/gpu/effects/moving_ellipse_effect.cc deleted file mode 100644 index bbd3c08..0000000 --- a/src/gpu/effects/moving_ellipse_effect.cc +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the MovingEllipseEffect. - -#include "gpu/demo_effects.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" - -// --- MovingEllipseEffect --- -MovingEllipseEffect::MovingEllipseEffect(const GpuContext& ctx) : Effect(ctx) { - // uniforms_ is initialized by Effect base class - ResourceBinding bindings[] = {{uniforms_.get(), WGPUBufferBindingType_Uniform}}; - pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, ellipse_shader_wgsl, - bindings, 1); - pass_.vertex_count = 3; -} -void MovingEllipseEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline); - wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} diff --git a/src/gpu/effects/particle_spray_effect.cc b/src/gpu/effects/particle_spray_effect.cc deleted file mode 100644 index 9b615d0..0000000 --- a/src/gpu/effects/particle_spray_effect.cc +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the ParticleSprayEffect. - -#include "gpu/demo_effects.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" -#include <vector> - -// --- ParticleSprayEffect --- -ParticleSprayEffect::ParticleSprayEffect(const GpuContext& ctx) : Effect(ctx) { - std::vector<Particle> init_p(NUM_PARTICLES); - for (Particle& p : init_p) - p.pos[3] = 0.0f; - particles_buffer_ = gpu_create_buffer( - ctx_.device, sizeof(Particle) * NUM_PARTICLES, - WGPUBufferUsage_Storage | WGPUBufferUsage_Vertex, init_p.data()); - ResourceBinding cb[] = {{particles_buffer_, WGPUBufferBindingType_Storage}, - {uniforms_.get(), WGPUBufferBindingType_Uniform}}; - compute_pass_ = - gpu_create_compute_pass(ctx_.device, particle_spray_compute_wgsl, cb, 2); - compute_pass_.workgroup_size_x = (NUM_PARTICLES + 63) / 64; - ResourceBinding rb[] = { - {particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage}, - {uniforms_.get(), WGPUBufferBindingType_Uniform}}; - render_pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, - particle_render_wgsl, rb, 2); - render_pass_.vertex_count = 6; - render_pass_.instance_count = NUM_PARTICLES; -} -void ParticleSprayEffect::compute(WGPUCommandEncoder e, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(e, nullptr); - wgpuComputePassEncoderSetPipeline(pass, compute_pass_.pipeline); - wgpuComputePassEncoderSetBindGroup(pass, 0, compute_pass_.bind_group, 0, - nullptr); - wgpuComputePassEncoderDispatchWorkgroups(pass, compute_pass_.workgroup_size_x, - 1, 1); - wgpuComputePassEncoderEnd(pass); -} -void ParticleSprayEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - (void)uniforms; - wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline); - wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0, - nullptr); - wgpuRenderPassEncoderDraw(pass, 6, NUM_PARTICLES, 0, 0); -} diff --git a/src/gpu/effects/particles_effect.cc b/src/gpu/effects/particles_effect.cc deleted file mode 100644 index f8c18f0..0000000 --- a/src/gpu/effects/particles_effect.cc +++ /dev/null @@ -1,47 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the ParticlesEffect. - -#include "gpu/demo_effects.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" -#include <vector> - -// --- ParticlesEffect --- -ParticlesEffect::ParticlesEffect(const GpuContext& ctx) : Effect(ctx) { - std::vector<Particle> init_p(NUM_PARTICLES); - particles_buffer_ = gpu_create_buffer( - ctx_.device, sizeof(Particle) * NUM_PARTICLES, - WGPUBufferUsage_Storage | WGPUBufferUsage_Vertex, init_p.data()); - ResourceBinding cb[] = {{particles_buffer_, WGPUBufferBindingType_Storage}, - {uniforms_.get(), WGPUBufferBindingType_Uniform}}; - compute_pass_ = - gpu_create_compute_pass(ctx_.device, particle_compute_wgsl, cb, 2); - compute_pass_.workgroup_size_x = (NUM_PARTICLES + 63) / 64; - ResourceBinding rb[] = { - {particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage}, - {uniforms_.get(), WGPUBufferBindingType_Uniform}}; - render_pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, - particle_render_wgsl, rb, 2); - render_pass_.vertex_count = 6; - render_pass_.instance_count = NUM_PARTICLES; -} -void ParticlesEffect::compute(WGPUCommandEncoder e, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(e, nullptr); - wgpuComputePassEncoderSetPipeline(pass, compute_pass_.pipeline); - wgpuComputePassEncoderSetBindGroup(pass, 0, compute_pass_.bind_group, 0, - nullptr); - wgpuComputePassEncoderDispatchWorkgroups(pass, compute_pass_.workgroup_size_x, - 1, 1); - wgpuComputePassEncoderEnd(pass); -} -void ParticlesEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - (void)uniforms; - wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline); - wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0, - nullptr); - wgpuRenderPassEncoderDraw(pass, render_pass_.vertex_count, - render_pass_.instance_count, 0, 0); -} diff --git a/src/gpu/effects/passthrough_effect.cc b/src/gpu/effects/passthrough_effect.cc deleted file mode 100644 index aedb387..0000000 --- a/src/gpu/effects/passthrough_effect.cc +++ /dev/null @@ -1,17 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the PassthroughEffect. - -#include "gpu/demo_effects.h" -#include "gpu/gpu.h" - -// --- PassthroughEffect --- -PassthroughEffect::PassthroughEffect(const GpuContext& ctx) - : PostProcessEffect(ctx) { - pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, - passthrough_shader_wgsl); -} -void PassthroughEffect::update_bind_group(WGPUTextureView input_view) { - uniforms_.update(ctx_.queue, get_common_uniforms()); - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - uniforms_.get(), {}); -} diff --git a/src/gpu/effects/rotating_cube_effect.cc b/src/gpu/effects/rotating_cube_effect.cc deleted file mode 100644 index 96b02f1..0000000 --- a/src/gpu/effects/rotating_cube_effect.cc +++ /dev/null @@ -1,200 +0,0 @@ -// This file is part of the 64k demo project. -// It implements RotatingCubeEffect for bump-mapped rotating cube rendering. -// Uses auxiliary texture masking to render only inside a circular region. - -#include "gpu/effects/rotating_cube_effect.h" -#include "generated/assets.h" -#include "gpu/bind_group_builder.h" -#include "gpu/effects/shader_composer.h" -#include "gpu/gpu.h" -#include "gpu/sampler_cache.h" -#include "util/asset_manager_utils.h" - -RotatingCubeEffect::RotatingCubeEffect(const GpuContext& ctx) : Effect(ctx) { -} - -RotatingCubeEffect::~RotatingCubeEffect() { - // Samplers owned by SamplerCache - don't release - if (noise_view_) - wgpuTextureViewRelease(noise_view_); - if (noise_texture_) - wgpuTextureRelease(noise_texture_); - if (bind_group_1_) - wgpuBindGroupRelease(bind_group_1_); - if (bind_group_0_) - wgpuBindGroupRelease(bind_group_0_); - if (pipeline_) - wgpuRenderPipelineRelease(pipeline_); -} - -void RotatingCubeEffect::init(MainSequence* demo) { - demo_ = demo; - - uniform_buffer_ = - gpu_create_buffer(ctx_.device, sizeof(Uniforms), - WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); - object_buffer_ = - gpu_create_buffer(ctx_.device, sizeof(ObjectData), - WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst); - - TextureWithView noise = gpu_create_texture_2d( - ctx_.device, 1, 1, WGPUTextureFormat_RGBA8Unorm, - WGPUTextureUsage_TextureBinding | WGPUTextureUsage_RenderAttachment, 1); - noise_texture_ = noise.texture; - noise_view_ = noise.view; - - noise_sampler_ = SamplerCache::Get().get_or_create(ctx_.device, SamplerCache::linear()); - mask_sampler_ = SamplerCache::Get().get_or_create(ctx_.device, SamplerCache::clamp()); - - size_t shader_size; - const char* shader_code = - (const char*)GetAsset(AssetId::ASSET_MASKED_CUBE_SHADER, &shader_size); - - ShaderComposer::CompositionMap composition_map; - composition_map["render/scene_query_mode"] = "render/scene_query_linear"; - composed_shader_ = ShaderComposer::Get().Compose( - {}, std::string(shader_code, shader_size), composition_map); - - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(composed_shader_.c_str()); - - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; - WGPUShaderModule shader_module = - wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc); - - WGPUBindGroupLayout bgl_0 = - BindGroupLayoutBuilder() - .uniform(0, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, - sizeof(Uniforms)) - .storage(1, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, - sizeof(ObjectData)) - .texture(3, WGPUShaderStage_Fragment) - .sampler(4, WGPUShaderStage_Fragment) - .build(ctx_.device); - - WGPUBindGroupLayout bgl_1 = BindGroupLayoutBuilder() - .texture(0, WGPUShaderStage_Fragment) - .sampler(1, WGPUShaderStage_Fragment) - .build(ctx_.device); - - const WGPUBindGroupLayout bgls[] = {bgl_0, bgl_1}; - const WGPUPipelineLayoutDescriptor pl_desc = { - .bindGroupLayoutCount = 2, - .bindGroupLayouts = bgls, - }; - WGPUPipelineLayout pipeline_layout = - wgpuDeviceCreatePipelineLayout(ctx_.device, &pl_desc); - - const WGPUColorTargetState color_target = { - .format = ctx_.format, - .writeMask = WGPUColorWriteMask_All, - }; - - const WGPUDepthStencilState depth_stencil = { - .format = WGPUTextureFormat_Depth24Plus, - .depthWriteEnabled = WGPUOptionalBool_True, - .depthCompare = WGPUCompareFunction_Less, - }; - - WGPUFragmentState fragment = {}; - fragment.module = shader_module; - fragment.entryPoint = str_view("fs_main"); - fragment.targetCount = 1; - fragment.targets = &color_target; - - WGPURenderPipelineDescriptor pipeline_desc = {}; - pipeline_desc.layout = pipeline_layout; - pipeline_desc.vertex.module = shader_module; - pipeline_desc.vertex.entryPoint = str_view("vs_main"); - pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; - pipeline_desc.primitive.cullMode = WGPUCullMode_None; - pipeline_desc.depthStencil = &depth_stencil; - pipeline_desc.multisample.count = 1; - pipeline_desc.multisample.mask = 0xFFFFFFFF; - pipeline_desc.fragment = &fragment; - - pipeline_ = wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc); - wgpuShaderModuleRelease(shader_module); - wgpuPipelineLayoutRelease(pipeline_layout); - - const WGPUBindGroupEntry entries_0[] = { - {.binding = 0, - .buffer = uniform_buffer_.buffer, - .size = sizeof(Uniforms)}, - {.binding = 1, - .buffer = object_buffer_.buffer, - .size = sizeof(ObjectData)}, - {.binding = 3, .textureView = noise_view_}, - {.binding = 4, .sampler = noise_sampler_}, - }; - - const WGPUBindGroupDescriptor bg_desc_0 = { - .layout = bgl_0, - .entryCount = 4, - .entries = entries_0, - }; - bind_group_0_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc_0); - wgpuBindGroupLayoutRelease(bgl_0); - - WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask"); - const WGPUBindGroupEntry entries_1[] = { - {.binding = 0, .textureView = mask_view}, - {.binding = 1, .sampler = mask_sampler_}, - }; - - const WGPUBindGroupDescriptor bg_desc_1 = { - .layout = bgl_1, - .entryCount = 2, - .entries = entries_1, - }; - bind_group_1_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc_1); - wgpuBindGroupLayoutRelease(bgl_1); -} - -void RotatingCubeEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& u) { - rotation_ += 0.016f * 1.5f; - - const vec3 camera_pos = vec3(0, 0, 5); - const vec3 target = vec3(0, 0, 0); - const vec3 up = vec3(0, 1, 0); - - const mat4 view = mat4::look_at(camera_pos, target, up); - const float fov = 60.0f * 3.14159f / 180.0f; - const mat4 proj = mat4::perspective(fov, u.aspect_ratio, 0.1f, 100.0f); - const mat4 view_proj = proj * view; - - const quat rot = quat::from_axis(vec3(0.3f, 1.0f, 0.2f), rotation_); - const mat4 T = mat4::translate(vec3(0, 0, 0)); - const mat4 R = rot.to_mat(); - const mat4 S = mat4::scale(vec3(1.5f, 1.5f, 1.5f)); - const mat4 model = T * R * S; - const mat4 inv_model = model.inverse(); - - const Uniforms uniforms = { - .view_proj = view_proj, - .inv_view_proj = view_proj.inverse(), - .camera_pos_time = vec4(camera_pos.x, camera_pos.y, camera_pos.z, u.time), - .params = vec4(1.0f, 0.0f, 0.0f, 0.0f), - .resolution = u.resolution, - }; - - const ObjectData obj_data = { - .model = model, - .inv_model = inv_model, - .color = vec4(0.8f, 0.4f, 0.2f, 1.0f), - .params = vec4(1.0f, 0.0f, 0.0f, 0.0f), - }; - - wgpuQueueWriteBuffer(ctx_.queue, uniform_buffer_.buffer, 0, &uniforms, - sizeof(Uniforms)); - wgpuQueueWriteBuffer(ctx_.queue, object_buffer_.buffer, 0, &obj_data, - sizeof(ObjectData)); - - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_0_, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(pass, 1, bind_group_1_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 36, 1, 0, 0); -} diff --git a/src/gpu/effects/rotating_cube_effect.h b/src/gpu/effects/rotating_cube_effect.h deleted file mode 100644 index fdf67ab..0000000 --- a/src/gpu/effects/rotating_cube_effect.h +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of the 64k demo project. -// It defines RotatingCubeEffect for rendering a bump-mapped rotating cube. -// Uses auxiliary texture masking to render only inside a circular region. - -#ifndef ROTATING_CUBE_EFFECT_H_ -#define ROTATING_CUBE_EFFECT_H_ - -#include "gpu/effect.h" -#include "gpu/gpu.h" -#include "util/mini_math.h" -#include <string> - -class RotatingCubeEffect : public Effect { - public: - RotatingCubeEffect(const GpuContext& ctx); - ~RotatingCubeEffect() override; - - void init(MainSequence* demo) override; - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - - private: - struct Uniforms { - mat4 view_proj; - mat4 inv_view_proj; - vec4 camera_pos_time; - vec4 params; - vec2 resolution; - vec2 padding; - }; - - struct ObjectData { - mat4 model; - mat4 inv_model; - vec4 color; - vec4 params; - }; - - MainSequence* demo_ = nullptr; - WGPURenderPipeline pipeline_ = nullptr; - WGPUBindGroup bind_group_0_ = nullptr; - WGPUBindGroup bind_group_1_ = nullptr; - GpuBuffer uniform_buffer_; - GpuBuffer object_buffer_; - WGPUTexture noise_texture_ = nullptr; - WGPUTextureView noise_view_ = nullptr; - WGPUSampler noise_sampler_ = nullptr; - WGPUSampler mask_sampler_ = nullptr; - float rotation_ = 0.0f; - - // Store composed shader to keep it alive for WebGPU - std::string composed_shader_; -}; - -#endif /* ROTATING_CUBE_EFFECT_H_ */ diff --git a/src/gpu/effects/scene1_effect.cc b/src/gpu/effects/scene1_effect.cc deleted file mode 100644 index c75e511..0000000 --- a/src/gpu/effects/scene1_effect.cc +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the 64k demo project. -// Scene1 effect - ShaderToy conversion (raymarching scene) - -#include "gpu/demo_effects.h" -#include "gpu/gpu.h" - -Scene1Effect::Scene1Effect(const GpuContext& ctx) : Effect(ctx) { - ResourceBinding bindings[] = {{uniforms_.get(), WGPUBufferBindingType_Uniform}}; - pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, scene1_shader_wgsl, - bindings, 1); - pass_.vertex_count = 3; -} - -void Scene1Effect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline); - wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, pass_.vertex_count, 1, 0, 0); -} diff --git a/src/gpu/effects/scene1_effect.h b/src/gpu/effects/scene1_effect.h deleted file mode 100644 index 190ffa9..0000000 --- a/src/gpu/effects/scene1_effect.h +++ /dev/null @@ -1,19 +0,0 @@ -// This file is part of the 64k demo project. -// Scene1 effect - ShaderToy conversion (raymarching scene) - -#ifndef SCENE1_EFFECT_H_ -#define SCENE1_EFFECT_H_ - -#include "gpu/effect.h" - -class Scene1Effect : public Effect { - public: - Scene1Effect(const GpuContext& ctx); - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - - private: - RenderPass pass_; -}; - -#endif /* SCENE1_EFFECT_H_ */ diff --git a/src/gpu/effects/solarize_effect.cc b/src/gpu/effects/solarize_effect.cc deleted file mode 100644 index cdb9354..0000000 --- a/src/gpu/effects/solarize_effect.cc +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the SolarizeEffect. - -#include "gpu/demo_effects.h" -#include "gpu/gpu.h" - -// --- SolarizeEffect --- -SolarizeEffect::SolarizeEffect(const GpuContext& ctx) : PostProcessEffect(ctx) { - pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, - solarize_shader_wgsl); -} -void SolarizeEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - PostProcessEffect::render(pass, uniforms); -} -void SolarizeEffect::update_bind_group(WGPUTextureView v) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_.get(), - {}); -} diff --git a/src/gpu/effects/theme_modulation_effect.cc b/src/gpu/effects/theme_modulation_effect.cc deleted file mode 100644 index aff6bce..0000000 --- a/src/gpu/effects/theme_modulation_effect.cc +++ /dev/null @@ -1,105 +0,0 @@ -// This file is part of the 64k demo project. -// It implements theme modulation (bright/dark alternation). - -#include "gpu/effects/theme_modulation_effect.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/effects/shaders.h" -#include <cmath> - -struct ThemeModulationParams { - float theme_brightness; - float _pad[3]; -}; -static_assert(sizeof(ThemeModulationParams) == 16, "ThemeModulationParams must be 16 bytes for WGSL alignment"); - -ThemeModulationEffect::ThemeModulationEffect(const GpuContext& ctx) - : PostProcessEffect(ctx) { - const char* shader_code = R"( - struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, - }; - - struct CommonUniforms { - resolution: vec2<f32>, - _pad0: f32, - _pad1: f32, - aspect_ratio: f32, - time: f32, - beat: f32, - audio_intensity: f32, - }; - - struct ThemeModulationParams { - theme_brightness: f32, - _pad0: f32, - _pad1: f32, - _pad2: f32, - }; - - @group(0) @binding(0) var inputSampler: sampler; - @group(0) @binding(1) var inputTexture: texture_2d<f32>; - @group(0) @binding(2) var<uniform> uniforms: CommonUniforms; - @group(0) @binding(3) var<uniform> params: ThemeModulationParams; - - @vertex - fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput { - var output: VertexOutput; - // Large triangle trick for fullscreen coverage - var pos = array<vec2<f32>, 3>( - vec2<f32>(-1.0, -1.0), - vec2<f32>(3.0, -1.0), - vec2<f32>(-1.0, 3.0) - ); - output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0); - output.uv = pos[vertexIndex] * 0.5 + 0.5; - return output; - } - - @fragment - fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> { - let color = textureSample(inputTexture, inputSampler, input.uv); - // Apply theme brightness modulation - return vec4<f32>(color.rgb * params.theme_brightness, color.a); - } - )"; - - pipeline_ = - create_post_process_pipeline(ctx_.device, ctx_.format, shader_code); - - params_buffer_ = gpu_create_buffer( - ctx_.device, 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); -} - -void ThemeModulationEffect::update_bind_group(WGPUTextureView input_view) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, - uniforms_.get(), params_buffer_); -} - -void ThemeModulationEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - - // Alternate between bright and dark every 4 seconds (2 pattern changes) - // Music patterns change every 2 seconds at 120 BPM - float cycle_time = fmodf(uniforms.time, 8.0f); // 8 second cycle (4 patterns) - bool is_dark_section = (cycle_time >= 4.0f); // Dark for second half - - // Smooth transition between themes using a sine wave - float transition = - (std::sin(uniforms.time * 3.14159f / 4.0f) + 1.0f) * 0.5f; // 0.0 to 1.0 - float bright_value = 1.0f; - float dark_value = 0.35f; - float theme_brightness = - bright_value + (dark_value - bright_value) * transition; - - // Update params buffer - ThemeModulationParams params = {theme_brightness, {0.0f, 0.0f, 0.0f}}; - wgpuQueueWriteBuffer(ctx_.queue, params_buffer_.buffer, 0, ¶ms, - sizeof(params)); - - // Render - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); - wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); -} diff --git a/src/gpu/effects/theme_modulation_effect.h b/src/gpu/effects/theme_modulation_effect.h deleted file mode 100644 index 31e96e6..0000000 --- a/src/gpu/effects/theme_modulation_effect.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the 64k demo project. -// It implements a theme modulation effect that alternates between bright and -// dark. Pattern changes every 2 seconds, so we alternate every 4 seconds (2 -// patterns). - -#pragma once -#include "gpu/effect.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/uniform_helper.h" - -class ThemeModulationEffect : public PostProcessEffect { - public: - ThemeModulationEffect(const GpuContext& ctx); - void render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) override; - void update_bind_group(WGPUTextureView input_view) override; - - private: - GpuBuffer params_buffer_; -}; diff --git a/src/gpu/effects/vignette_effect.cc b/src/gpu/effects/vignette_effect.cc deleted file mode 100644 index 4b0ffe2..0000000 --- a/src/gpu/effects/vignette_effect.cc +++ /dev/null @@ -1,30 +0,0 @@ -// This file is part of the 64k demo project. -// It implements the VignetteEffect. - -#include "gpu/demo_effects.h" -#include "gpu/effects/post_process_helper.h" -#include "gpu/gpu.h" - -VignetteEffect::VignetteEffect(const GpuContext& ctx) - : VignetteEffect(ctx, VignetteParams()) { -} - -VignetteEffect::VignetteEffect(const GpuContext& ctx, - const VignetteParams& params) - : PostProcessEffect(ctx), params_(params) { - params_buffer_.init(ctx_.device); - pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, - vignette_shader_wgsl); -} - -void VignetteEffect::render(WGPURenderPassEncoder pass, - const CommonPostProcessUniforms& uniforms) { - uniforms_.update(ctx_.queue, uniforms); - params_buffer_.update(ctx_.queue, params_); - PostProcessEffect::render(pass, uniforms); -} - -void VignetteEffect::update_bind_group(WGPUTextureView v) { - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_.get(), - params_buffer_.get()); -} diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc index afbba90..929a063 100644 --- a/src/gpu/gpu.cc +++ b/src/gpu/gpu.cc @@ -4,8 +4,8 @@ #include "gpu.h" #include "effect.h" -#include "gpu/effects/shaders.h" -#include "gpu/effects/shader_composer.h" +#include "gpu/shaders.h" +#include "gpu/shader_composer.h" #include "platform/platform.h" #include <cassert> @@ -81,7 +81,7 @@ TextureWithView gpu_create_storage_texture_2d(WGPUDevice device, uint32_t width, WGPUTextureFormat format) { return gpu_create_texture_2d( device, width, height, format, - WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding, 1); + (WGPUTextureUsage)(WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding), 1); } TextureWithView gpu_create_post_process_texture(WGPUDevice device, @@ -89,8 +89,7 @@ TextureWithView gpu_create_post_process_texture(WGPUDevice device, WGPUTextureFormat format) { return gpu_create_texture_2d( device, width, height, format, - WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | - WGPUTextureUsage_CopySrc, + (WGPUTextureUsage)(WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc), 1); } diff --git a/src/gpu/pipeline_builder.h b/src/gpu/pipeline_builder.h index 06b4ceb..68e34ea 100644 --- a/src/gpu/pipeline_builder.h +++ b/src/gpu/pipeline_builder.h @@ -14,7 +14,7 @@ struct WGPUShaderModuleImpl; typedef struct WGPUShaderModuleImpl* WGPUShaderModule; #include "platform/platform.h" -#include "gpu/effects/shader_composer.h" +#include "gpu/shader_composer.h" class RenderPipelineBuilder { WGPUDevice device_; diff --git a/src/gpu/effects/post_process_helper.cc b/src/gpu/post_process_helper.cc index 0c339c7..4ffa9c1 100644 --- a/src/gpu/effects/post_process_helper.cc +++ b/src/gpu/post_process_helper.cc @@ -2,9 +2,9 @@ // It implements helper functions for post-processing effects. #include "post_process_helper.h" -#include "../demo_effects.h" +#include "demo_effects.h" #include "gpu/gpu.h" -#include "gpu/effects/shader_composer.h" +#include "gpu/shader_composer.h" #include "gpu/bind_group_builder.h" #include "gpu/sampler_cache.h" #include "gpu/pipeline_builder.h" diff --git a/src/gpu/effects/post_process_helper.h b/src/gpu/post_process_helper.h index 1c649e7..1c649e7 100644 --- a/src/gpu/effects/post_process_helper.h +++ b/src/gpu/post_process_helper.h diff --git a/src/gpu/effects/shader_composer.cc b/src/gpu/shader_composer.cc index 9234b7a..fce6de4 100644 --- a/src/gpu/effects/shader_composer.cc +++ b/src/gpu/shader_composer.cc @@ -1,7 +1,7 @@ // This file is part of the 64k demo project. // It implements the ShaderComposer class. -#include "gpu/effects/shader_composer.h" +#include "gpu/shader_composer.h" #include <set> #include <sstream> diff --git a/src/gpu/effects/shader_composer.h b/src/gpu/shader_composer.h index d0972f2..d0972f2 100644 --- a/src/gpu/effects/shader_composer.h +++ b/src/gpu/shader_composer.h diff --git a/src/gpu/effects/shaders.cc b/src/gpu/shaders.cc index d79f3d3..903b96e 100644 --- a/src/gpu/effects/shaders.cc +++ b/src/gpu/shaders.cc @@ -1,7 +1,7 @@ // This file is part of the 64k demo project. // It defines WGSL shader code for various effects. -#include "../demo_effects.h" +#include "demo_effects.h" #if defined(USE_TEST_ASSETS) @@ -13,7 +13,7 @@ #endif -#include "gpu/effects/shader_composer.h" +#include "gpu/shader_composer.h" #include "util/asset_manager.h" diff --git a/src/gpu/effects/shaders.h b/src/gpu/shaders.h index 03fa48c..03fa48c 100644 --- a/src/gpu/effects/shaders.h +++ b/src/gpu/shaders.h diff --git a/src/gpu/texture_manager.cc b/src/gpu/texture_manager.cc index d5821ee..7889283 100644 --- a/src/gpu/texture_manager.cc +++ b/src/gpu/texture_manager.cc @@ -2,7 +2,7 @@ // It implements the TextureManager. #include "gpu/texture_manager.h" -#include "gpu/effects/shader_composer.h" +#include "gpu/shader_composer.h" #include "platform/platform.h" #include <cstdio> #include <cstring> |
