diff options
Diffstat (limited to 'cnn_v3/src')
| -rw-r--r-- | cnn_v3/src/cnn_v3_effect.cc | 26 | ||||
| -rw-r--r-- | cnn_v3/src/gbuf_view_effect.cc | 144 | ||||
| -rw-r--r-- | cnn_v3/src/gbuf_view_effect.h | 25 |
3 files changed, 190 insertions, 5 deletions
diff --git a/cnn_v3/src/cnn_v3_effect.cc b/cnn_v3/src/cnn_v3_effect.cc index 759e7ef..bfbb17b 100644 --- a/cnn_v3/src/cnn_v3_effect.cc +++ b/cnn_v3/src/cnn_v3_effect.cc @@ -2,8 +2,16 @@ // See cnn_v3/docs/CNN_V3.md for architecture, HOWTO.md §7 for shader details. #include "cnn_v3_effect.h" + +#if defined(USE_TEST_ASSETS) +#include "test_assets.h" +#else +#include "generated/assets.h" +#endif + #include "gpu/gpu.h" #include "gpu/shader_composer.h" +#include "util/asset_manager.h" #include "util/fatal_error.h" #include <cstdint> #include <cstring> @@ -180,6 +188,14 @@ CNNv3Effect::CNNv3Effect(const GpuContext& ctx, for (int i = 0; i < 4; ++i) { dec0_params_.gamma[i] = 1.0f; } create_pipelines(); + + // Load trained weights from asset system (zero-initialized if absent). + size_t weights_size = 0; + const void* weights_data = + GetAsset(AssetId::ASSET_WEIGHTS_CNN_V3, &weights_size); + if (weights_data && weights_size == kWeightsBufBytes) { + upload_weights(ctx_.queue, weights_data, (uint32_t)weights_size); + } } // --------------------------------------------------------------------------- @@ -429,7 +445,7 @@ void CNNv3Effect::update_bind_groups(NodeRegistry& nodes) { bg_buf(e[2], 2, wb, kWeightsBufBytes); bg_buf(e[3], 3, enc0_params_buf_.get().buffer, sizeof(CnnV3Params4ch)); bg_tex(e[4], 4, enc0_view); - enc0_bg_.set(make_bg(enc0_pipeline_.get(), e, 5)); + enc0_bg_.replace(make_bg(enc0_pipeline_.get(), e, 5)); } // enc1: enc0_tex(B0), weights(B1), params(B2), enc1_out(B3) @@ -439,7 +455,7 @@ void CNNv3Effect::update_bind_groups(NodeRegistry& nodes) { bg_buf(e[1], 1, wb, kWeightsBufBytes); bg_buf(e[2], 2, enc1_params_buf_.get().buffer, sizeof(CnnV3ParamsEnc1)); bg_tex(e[3], 3, enc1_view); - enc1_bg_.set(make_bg(enc1_pipeline_.get(), e, 4)); + enc1_bg_.replace(make_bg(enc1_pipeline_.get(), e, 4)); } // bottleneck: enc1_tex(B0), weights(B1), params(B2), bn_out(B3) @@ -449,7 +465,7 @@ void CNNv3Effect::update_bind_groups(NodeRegistry& nodes) { bg_buf(e[1], 1, wb, kWeightsBufBytes); bg_buf(e[2], 2, bn_params_buf_.get().buffer, sizeof(CnnV3ParamsBn)); bg_tex(e[3], 3, bn_view); - bn_bg_.set(make_bg(bn_pipeline_.get(), e, 4)); + bn_bg_.replace(make_bg(bn_pipeline_.get(), e, 4)); } // dec1: bn_tex(B0), enc1_tex(B1), weights(B2), params(B3), dec1_out(B4) @@ -460,7 +476,7 @@ void CNNv3Effect::update_bind_groups(NodeRegistry& nodes) { bg_buf(e[2], 2, wb, kWeightsBufBytes); bg_buf(e[3], 3, dec1_params_buf_.get().buffer, sizeof(CnnV3Params4ch)); bg_tex(e[4], 4, dec1_view); - dec1_bg_.set(make_bg(dec1_pipeline_.get(), e, 5)); + dec1_bg_.replace(make_bg(dec1_pipeline_.get(), e, 5)); } // dec0: dec1_tex(B0), enc0_tex(B1), weights(B2), params(B3), output(B4) @@ -471,6 +487,6 @@ void CNNv3Effect::update_bind_groups(NodeRegistry& nodes) { bg_buf(e[2], 2, wb, kWeightsBufBytes); bg_buf(e[3], 3, dec0_params_buf_.get().buffer, sizeof(CnnV3Params4ch)); bg_tex(e[4], 4, out_view); - dec0_bg_.set(make_bg(dec0_pipeline_.get(), e, 5)); + dec0_bg_.replace(make_bg(dec0_pipeline_.get(), e, 5)); } } diff --git a/cnn_v3/src/gbuf_view_effect.cc b/cnn_v3/src/gbuf_view_effect.cc new file mode 100644 index 0000000..180919d --- /dev/null +++ b/cnn_v3/src/gbuf_view_effect.cc @@ -0,0 +1,144 @@ +// GBufViewEffect — G-buffer channel grid visualization +// Renders 20 feature channels from feat_tex0/feat_tex1 in a 4×5 tiled layout. + +#include "gbuf_view_effect.h" + +#if defined(USE_TEST_ASSETS) +#include "test_assets.h" +#else +#include "generated/assets.h" +#endif + +#include "gpu/gpu.h" +#include "util/asset_manager.h" +#include "util/fatal_error.h" + +extern const char* gbuf_view_wgsl; + +// BGL entry: texture_2d<u32> read binding (fragment stage) +static WGPUBindGroupLayoutEntry bgl_uint_tex_frag(uint32_t binding) { + WGPUBindGroupLayoutEntry e = {}; + e.binding = binding; + e.visibility = WGPUShaderStage_Fragment; + e.texture.sampleType = WGPUTextureSampleType_Uint; + e.texture.viewDimension = WGPUTextureViewDimension_2D; + return e; +} + +// BGL entry: uniform buffer (fragment stage) +static WGPUBindGroupLayoutEntry bgl_uniform_frag(uint32_t binding, + uint64_t min_size) { + WGPUBindGroupLayoutEntry e = {}; + e.binding = binding; + e.visibility = WGPUShaderStage_Fragment; + e.buffer.type = WGPUBufferBindingType_Uniform; + e.buffer.minBindingSize = min_size; + return e; +} + +GBufViewEffect::GBufViewEffect(const GpuContext& ctx, + const std::vector<std::string>& inputs, + const std::vector<std::string>& outputs, + float start_time, float end_time) + : Effect(ctx, inputs, outputs, start_time, end_time) { + HEADLESS_RETURN_IF_NULL(ctx_.device); + + // Build BGL: binding 0 = feat0 (u32 tex), 1 = feat1 (u32 tex), 2 = uniforms + WGPUBindGroupLayoutEntry entries[3] = { + bgl_uint_tex_frag(0), + bgl_uint_tex_frag(1), + bgl_uniform_frag(2, 8), // only resolution (vec2f = 8 bytes) is read + }; + WGPUBindGroupLayoutDescriptor bgl_desc = {}; + bgl_desc.entryCount = 3; + bgl_desc.entries = entries; + WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(ctx_.device, &bgl_desc); + + // Pipeline layout + WGPUPipelineLayoutDescriptor pl_desc = {}; + pl_desc.bindGroupLayoutCount = 1; + pl_desc.bindGroupLayouts = &bgl; + WGPUPipelineLayout pl = wgpuDeviceCreatePipelineLayout(ctx_.device, &pl_desc); + + // Shader module + WGPUShaderSourceWGSL wgsl_src = {}; + wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; + wgsl_src.code = str_view(gbuf_view_wgsl); + WGPUShaderModuleDescriptor shader_desc = {}; + shader_desc.nextInChain = &wgsl_src.chain; + WGPUShaderModule shader = + wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc); + + // Render pipeline + WGPUColorTargetState target = {}; + target.format = WGPUTextureFormat_RGBA8Unorm; + target.writeMask = WGPUColorWriteMask_All; + + WGPUFragmentState frag = {}; + frag.module = shader; + frag.entryPoint = str_view("fs_main"); + frag.targetCount = 1; + frag.targets = ⌖ + + WGPURenderPipelineDescriptor pipe_desc = {}; + pipe_desc.layout = pl; + pipe_desc.vertex.module = shader; + pipe_desc.vertex.entryPoint = str_view("vs_main"); + pipe_desc.fragment = &frag; + pipe_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; + pipe_desc.multisample.count = 1; + pipe_desc.multisample.mask = UINT32_MAX; + + pipeline_.set(wgpuDeviceCreateRenderPipeline(ctx_.device, &pipe_desc)); + + wgpuShaderModuleRelease(shader); + wgpuPipelineLayoutRelease(pl); + wgpuBindGroupLayoutRelease(bgl); +} + +void GBufViewEffect::render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) { + WGPUTextureView feat0_view = nodes.get_view(input_nodes_[0]); + WGPUTextureView feat1_view = nodes.get_view(input_nodes_[1]); + WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); + + // Rebuild bind group (views may change with ping-pong or resize) + WGPUBindGroupLayout bgl = + wgpuRenderPipelineGetBindGroupLayout(pipeline_.get(), 0); + + WGPUBindGroupEntry bg_entries[3] = {}; + bg_entries[0].binding = 0; + bg_entries[0].textureView = feat0_view; + bg_entries[1].binding = 1; + bg_entries[1].textureView = feat1_view; + bg_entries[2].binding = 2; + bg_entries[2].buffer = uniforms_buffer_.get().buffer; + bg_entries[2].size = sizeof(UniformsSequenceParams); + + WGPUBindGroupDescriptor bg_desc = {}; + bg_desc.layout = bgl; + bg_desc.entryCount = 3; + bg_desc.entries = bg_entries; + bind_group_.replace(wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc)); + wgpuBindGroupLayoutRelease(bgl); + + WGPURenderPassColorAttachment color_att = {}; + color_att.view = output_view; + color_att.loadOp = WGPULoadOp_Clear; + color_att.storeOp = WGPUStoreOp_Store; + color_att.clearValue = {0.0f, 0.0f, 0.0f, 1.0f}; + color_att.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; + + WGPURenderPassDescriptor pass_desc = {}; + pass_desc.colorAttachmentCount = 1; + pass_desc.colorAttachments = &color_att; + + WGPURenderPassEncoder pass = + wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_.get()); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_.get(), 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); + wgpuRenderPassEncoderEnd(pass); + wgpuRenderPassEncoderRelease(pass); +} diff --git a/cnn_v3/src/gbuf_view_effect.h b/cnn_v3/src/gbuf_view_effect.h new file mode 100644 index 0000000..d4d8139 --- /dev/null +++ b/cnn_v3/src/gbuf_view_effect.h @@ -0,0 +1,25 @@ +// GBufViewEffect: Visualizes G-buffer feature textures as a 4×5 channel grid. +// Inputs: feat_tex0 (rgba32uint, ch 0-7 f16), feat_tex1 (rgba32uint, ch 8-19 unorm8) +// Output: rgba8unorm tiled channel visualization (downscaled 4× per channel) + +#pragma once + +#include "gpu/effect.h" +#include "gpu/sequence.h" +#include "gpu/wgpu_resource.h" + +class GBufViewEffect : public Effect { + public: + GBufViewEffect(const GpuContext& ctx, + const std::vector<std::string>& inputs, + const std::vector<std::string>& outputs, + float start_time, float end_time); + + void render(WGPUCommandEncoder encoder, + const UniformsSequenceParams& params, + NodeRegistry& nodes) override; + + private: + RenderPipeline pipeline_; + BindGroup bind_group_; +}; |
