summaryrefslogtreecommitdiff
path: root/cnn_v3/src
diff options
context:
space:
mode:
Diffstat (limited to 'cnn_v3/src')
-rw-r--r--cnn_v3/src/cnn_v3_effect.cc26
-rw-r--r--cnn_v3/src/gbuf_view_effect.cc144
-rw-r--r--cnn_v3/src/gbuf_view_effect.h25
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 = &target;
+
+ 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_;
+};