diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/gpu/demo_effects.h | 1 | ||||
| -rw-r--r-- | src/gpu/effects/cnn_v2_effect.cc | 170 | ||||
| -rw-r--r-- | src/gpu/effects/cnn_v2_effect.h | 41 | ||||
| -rw-r--r-- | src/tests/gpu/test_demo_effects.cc | 1 |
4 files changed, 213 insertions, 0 deletions
diff --git a/src/gpu/demo_effects.h b/src/gpu/demo_effects.h index 8cdf557..d0ae748 100644 --- a/src/gpu/demo_effects.h +++ b/src/gpu/demo_effects.h @@ -186,6 +186,7 @@ class DistortEffect : public PostProcessEffect { // (included above) #include "gpu/effects/cnn_effect.h" +#include "gpu/effects/cnn_v2_effect.h" // Auto-generated functions void LoadTimeline(MainSequence& main_seq, const GpuContext& ctx); diff --git a/src/gpu/effects/cnn_v2_effect.cc b/src/gpu/effects/cnn_v2_effect.cc new file mode 100644 index 0000000..04fa74e --- /dev/null +++ b/src/gpu/effects/cnn_v2_effect.cc @@ -0,0 +1,170 @@ +// 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 "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_features_tex_(nullptr), + static_features_view_(nullptr), + input_mip_tex_(nullptr), + 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; + + create_textures(); + create_pipelines(); + + initialized_ = true; +} + +void CNNv2Effect::resize(int width, int height) { + PostProcessEffect::resize(width, height); + cleanup(); + create_textures(); + create_pipelines(); +} + +void CNNv2Effect::create_textures() { + const WGPUExtent3D size = { + static_cast<uint32_t>(width_), + static_cast<uint32_t>(height_), + 1 + }; + + // Static features texture (8×f16 packed as 4×u32) + WGPUTextureDescriptor static_desc = {}; + static_desc.usage = WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding; + static_desc.dimension = WGPUTextureDimension_2D; + static_desc.size = size; + static_desc.format = WGPUTextureFormat_RGBA32Uint; + static_desc.mipLevelCount = 1; + static_desc.sampleCount = 1; + static_features_tex_ = wgpuDeviceCreateTexture(ctx_.device, &static_desc); + + WGPUTextureViewDescriptor view_desc = {}; + view_desc.format = WGPUTextureFormat_RGBA32Uint; + view_desc.dimension = WGPUTextureViewDimension_2D; + view_desc.baseMipLevel = 0; + view_desc.mipLevelCount = 1; + view_desc.baseArrayLayer = 0; + view_desc.arrayLayerCount = 1; + static_features_view_ = wgpuTextureCreateView(static_features_tex_, &view_desc); + + // Input texture with mips (for multi-scale features) + WGPUTextureDescriptor input_mip_desc = {}; + input_mip_desc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst; + input_mip_desc.dimension = WGPUTextureDimension_2D; + input_mip_desc.size = size; + input_mip_desc.format = WGPUTextureFormat_RGBA8Unorm; + input_mip_desc.mipLevelCount = 3; // Levels 0, 1, 2 + input_mip_desc.sampleCount = 1; + input_mip_tex_ = wgpuDeviceCreateTexture(ctx_.device, &input_mip_desc); + + for (int i = 0; i < 3; ++i) { + WGPUTextureViewDescriptor mip_view_desc = {}; + mip_view_desc.format = WGPUTextureFormat_RGBA8Unorm; + mip_view_desc.dimension = WGPUTextureViewDimension_2D; + mip_view_desc.baseMipLevel = i; + mip_view_desc.mipLevelCount = 1; + mip_view_desc.baseArrayLayer = 0; + mip_view_desc.arrayLayerCount = 1; + input_mip_view_[i] = wgpuTextureCreateView(input_mip_tex_, &mip_view_desc); + } + + // Layer textures (placeholder - will be created based on config) + // TODO: Create layer textures based on layer_configs_ +} + +void CNNv2Effect::create_pipelines() { + // 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; + + WGPUShaderModule static_module = wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc); + if (!static_module) { + return; + } + + WGPUComputePipelineDescriptor pipeline_desc = {}; + pipeline_desc.compute.module = static_module; + pipeline_desc.compute.entryPoint = str_view("main"); + + static_pipeline_ = wgpuDeviceCreateComputePipeline(ctx_.device, &pipeline_desc); + wgpuShaderModuleRelease(static_module); + + // TODO: Create layer pipelines + // TODO: Create bind groups +} + +void CNNv2Effect::update_bind_group(WGPUTextureView input_view) { + (void)input_view; + // TODO: Create bind groups for static features and layers +} + +void CNNv2Effect::render(WGPURenderPassEncoder pass, + const CommonPostProcessUniforms& uniforms) { + (void)pass; + (void)uniforms; + if (!initialized_) return; + + // TODO: Multi-pass execution + // 1. Compute static features + // 2. Execute CNN layers + // 3. Composite to output +} + +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_pipeline_) wgpuComputePipelineRelease(static_pipeline_); + + 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); + for (auto pipeline : layer_pipelines_) wgpuComputePipelineRelease(pipeline); + + layer_views_.clear(); + layer_textures_.clear(); + layer_bind_groups_.clear(); + layer_pipelines_.clear(); + + initialized_ = false; +} diff --git a/src/gpu/effects/cnn_v2_effect.h b/src/gpu/effects/cnn_v2_effect.h new file mode 100644 index 0000000..edf301e --- /dev/null +++ b/src/gpu/effects/cnn_v2_effect.h @@ -0,0 +1,41 @@ +// CNN v2 Effect - Parametric Static Features +// Multi-pass post-processing with 7D feature input + +#pragma once +#include "gpu/effect.h" +#include <vector> + +class CNNv2Effect : public PostProcessEffect { +public: + explicit CNNv2Effect(const GpuContext& ctx); + ~CNNv2Effect(); + + 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; + +private: + void create_textures(); + void create_pipelines(); + void cleanup(); + + // Static features compute + WGPUComputePipeline static_pipeline_; + WGPUBindGroup static_bind_group_; + WGPUTexture static_features_tex_; + WGPUTextureView static_features_view_; + + // CNN layers (opaque implementation) + std::vector<WGPUComputePipeline> layer_pipelines_; + std::vector<WGPUBindGroup> layer_bind_groups_; + std::vector<WGPUTexture> layer_textures_; + std::vector<WGPUTextureView> layer_views_; + + // Input mips + WGPUTexture input_mip_tex_; + WGPUTextureView input_mip_view_[3]; + + bool initialized_; +}; diff --git a/src/tests/gpu/test_demo_effects.cc b/src/tests/gpu/test_demo_effects.cc index 01e6678..169db91 100644 --- a/src/tests/gpu/test_demo_effects.cc +++ b/src/tests/gpu/test_demo_effects.cc @@ -90,6 +90,7 @@ static void test_post_process_effects() { std::make_shared<ThemeModulationEffect>(fixture.ctx())}, {"VignetteEffect", std::make_shared<VignetteEffect>(fixture.ctx())}, {"CNNEffect", std::make_shared<CNNEffect>(fixture.ctx())}, + {"CNNv2Effect", std::make_shared<CNNv2Effect>(fixture.ctx())}, }; int passed = 0; |
