summaryrefslogtreecommitdiff
path: root/tools/cnn_test.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-14 15:14:25 +0100
committerskal <pascal.massimino@gmail.com>2026-02-14 15:14:25 +0100
commit8ce27b7e15f0fc65c8ee78950c7501660b936178 (patch)
tree391f32111b9a30a0156709b6c1ed2fae7b435d57 /tools/cnn_test.cc
parente38be0dbf5816338ff97e2ee2f9adfff2902dc2b (diff)
style: Apply clang-format to codebase
Diffstat (limited to 'tools/cnn_test.cc')
-rw-r--r--tools/cnn_test.cc272
1 files changed, 155 insertions, 117 deletions
diff --git a/tools/cnn_test.cc b/tools/cnn_test.cc
index 740f41d..7d060ae 100644
--- a/tools/cnn_test.cc
+++ b/tools/cnn_test.cc
@@ -5,30 +5,30 @@
#error "cnn_test requires STRIP_ALL=OFF (tool builds only)"
#endif
-#include "platform/platform.h"
-#include "gpu/gpu.h"
+#include "effects/cnn_effect.h"
+#include "generated/assets.h"
#include "gpu/bind_group_builder.h"
+#include "gpu/gpu.h"
#include "gpu/pipeline_builder.h"
-#include "gpu/sampler_cache.h"
-#include "gpu/texture_readback.h"
#include "gpu/post_process_helper.h"
-#include "effects/cnn_effect.h"
+#include "gpu/sampler_cache.h"
#include "gpu/shader_composer.h"
#include "gpu/shaders.h"
-#include "tests/common/webgpu_test_fixture.h"
+#include "gpu/texture_readback.h"
+#include "platform/platform.h"
#include "tests/common/offscreen_render_target.h"
-#include "generated/assets.h"
+#include "tests/common/webgpu_test_fixture.h"
#include "util/asset_manager.h"
#include "util/mini_math.h"
#include "stb_image.h"
#include "wgpu-native/examples/capture/stb_image_write.h"
+#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
-#include <cmath>
// Helper to get asset string or empty string
static const char* SafeGetAsset(AssetId id) {
@@ -43,11 +43,12 @@ struct Args {
float blend = 1.0f;
bool output_png = true; // Default to PNG
const char* save_intermediates = nullptr;
- int num_layers = 3; // Default to 3 layers
- bool debug_hex = false; // Print first 8 pixels as hex
- int cnn_version = 1; // 1=CNNEffect, 2=CNNv2Effect
+ int num_layers = 3; // Default to 3 layers
+ bool debug_hex = false; // Print first 8 pixels as hex
+ int cnn_version = 1; // 1=CNNEffect, 2=CNNv2Effect
const char* weights_path = nullptr; // Optional .bin weights file
- bool cnn_version_explicit = false; // Track if --cnn-version was explicitly set
+ bool cnn_version_explicit =
+ false; // Track if --cnn-version was explicitly set
};
// Parse command-line arguments
@@ -107,14 +108,17 @@ static bool parse_args(int argc, char** argv, Args* args) {
// Force CNN v2 when --weights is specified
if (args->weights_path) {
if (args->cnn_version_explicit && args->cnn_version != 2) {
- fprintf(stderr, "WARNING: --cnn-version %d ignored (--weights forces CNN v2)\n",
+ fprintf(stderr,
+ "WARNING: --cnn-version %d ignored (--weights forces CNN v2)\n",
args->cnn_version);
}
args->cnn_version = 2;
// Warn if --layers was specified (binary file config takes precedence)
- if (args->num_layers != 3) { // 3 is the default
- fprintf(stderr, "WARNING: --layers %d ignored (--weights loads layer config from .bin)\n",
+ if (args->num_layers != 3) { // 3 is the default
+ fprintf(stderr,
+ "WARNING: --layers %d ignored (--weights loads layer config from "
+ ".bin)\n",
args->num_layers);
}
}
@@ -126,20 +130,30 @@ static bool parse_args(int argc, char** argv, Args* args) {
static void print_usage(const char* prog) {
fprintf(stderr, "Usage: %s input.png output.png [OPTIONS]\n", prog);
fprintf(stderr, "\nOPTIONS:\n");
- fprintf(stderr, " --blend F Final blend amount (0.0-1.0, default: 1.0)\n");
+ fprintf(stderr,
+ " --blend F Final blend amount (0.0-1.0, default: "
+ "1.0)\n");
fprintf(stderr, " --format ppm|png Output format (default: png)\n");
- fprintf(stderr, " --layers N Number of CNN layers (1-10, default: 3, ignored with --weights)\n");
- fprintf(stderr, " --save-intermediates DIR Save intermediate layers to directory\n");
- fprintf(stderr, " --debug-hex Print first 8 pixels as hex (debug)\n");
- fprintf(stderr, " --cnn-version N CNN version: 1 (default) or 2 (ignored with --weights)\n");
- fprintf(stderr, " --weights PATH Load weights from .bin (forces CNN v2, overrides layer config)\n");
+ fprintf(stderr,
+ " --layers N Number of CNN layers (1-10, default: 3, "
+ "ignored with --weights)\n");
+ fprintf(stderr,
+ " --save-intermediates DIR Save intermediate layers to directory\n");
+ fprintf(stderr,
+ " --debug-hex Print first 8 pixels as hex (debug)\n");
+ fprintf(stderr,
+ " --cnn-version N CNN version: 1 (default) or 2 (ignored "
+ "with --weights)\n");
+ fprintf(stderr,
+ " --weights PATH Load weights from .bin (forces CNN v2, "
+ "overrides layer config)\n");
fprintf(stderr, " --help Show this help\n");
}
// Load PNG and upload to GPU texture
static WGPUTexture load_texture(WGPUDevice device, WGPUQueue queue,
- const char* path, int* out_width,
- int* out_height) {
+ const char* path, int* out_width,
+ int* out_height) {
int width, height, channels;
uint8_t* data = stbi_load(path, &width, &height, &channels, 4);
if (!data) {
@@ -192,13 +206,14 @@ static WGPUTexture load_texture(WGPUDevice device, WGPUQueue queue,
// Load PNG alpha channel as depth texture (or 1.0 if no alpha)
static WGPUTexture load_depth_from_alpha(WGPUDevice device, WGPUQueue queue,
- const char* path, int width,
- int height) {
+ const char* path, int width,
+ int height) {
int w, h, channels;
uint8_t* data = stbi_load(path, &w, &h, &channels, 4);
if (!data || w != width || h != height) {
fprintf(stderr, "Error: failed to load depth from '%s'\n", path);
- if (data) stbi_image_free(data);
+ if (data)
+ stbi_image_free(data);
return nullptr;
}
@@ -228,19 +243,13 @@ static WGPUTexture load_depth_from_alpha(WGPUDevice device, WGPUQueue queue,
}
// Write depth data
- const WGPUTexelCopyTextureInfo dst = {
- .texture = depth_texture,
- .mipLevel = 0
- };
+ const WGPUTexelCopyTextureInfo dst = {.texture = depth_texture,
+ .mipLevel = 0};
const WGPUTexelCopyBufferLayout layout = {
.bytesPerRow = static_cast<uint32_t>(width * sizeof(float)),
- .rowsPerImage = static_cast<uint32_t>(height)
- };
- const WGPUExtent3D size = {
- static_cast<uint32_t>(width),
- static_cast<uint32_t>(height),
- 1
- };
+ .rowsPerImage = static_cast<uint32_t>(height)};
+ const WGPUExtent3D size = {static_cast<uint32_t>(width),
+ static_cast<uint32_t>(height), 1};
wgpuQueueWriteTexture(queue, &dst, depth_data.data(),
depth_data.size() * sizeof(float), &layout, &size);
@@ -253,8 +262,8 @@ static WGPUTexture load_depth_from_alpha(WGPUDevice device, WGPUQueue queue,
// Create CNN render pipeline (5 bindings)
// Takes both intermediate format (RGBA16Float) and final format (BGRA8Unorm)
static WGPURenderPipeline create_cnn_pipeline(WGPUDevice device,
- WGPUTextureFormat format,
- bool is_final_layer) {
+ WGPUTextureFormat format,
+ bool is_final_layer) {
const char* shader_code = SafeGetAsset(AssetId::ASSET_SHADER_CNN_LAYER);
// Debug: check if shader loaded
@@ -274,14 +283,16 @@ static WGPURenderPipeline create_cnn_pipeline(WGPUDevice device,
.build(device);
// Use appropriate format: RGBA16Float for intermediate, BGRA8Unorm for final
- WGPUTextureFormat output_format =
- is_final_layer ? WGPUTextureFormat_BGRA8Unorm : WGPUTextureFormat_RGBA16Float;
+ WGPUTextureFormat output_format = is_final_layer
+ ? WGPUTextureFormat_BGRA8Unorm
+ : WGPUTextureFormat_RGBA16Float;
- WGPURenderPipeline pipeline = RenderPipelineBuilder(device)
- .shader(shader_code) // compose=true by default
- .bind_group_layout(bgl)
- .format(output_format)
- .build();
+ WGPURenderPipeline pipeline =
+ RenderPipelineBuilder(device)
+ .shader(shader_code) // compose=true by default
+ .bind_group_layout(bgl)
+ .format(output_format)
+ .build();
wgpuBindGroupLayoutRelease(bgl);
return pipeline;
@@ -289,7 +300,7 @@ static WGPURenderPipeline create_cnn_pipeline(WGPUDevice device,
// Begin render pass with clear
static WGPURenderPassEncoder begin_render_pass(WGPUCommandEncoder encoder,
- WGPUTextureView view) {
+ WGPUTextureView view) {
const WGPURenderPassColorAttachment color_attachment = {
.view = view,
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
@@ -328,7 +339,8 @@ static bool save_png(const char* path, const std::vector<uint8_t>& pixels,
// Create horizontal grayscale composite of layer outputs
// Each layer is already 4x wide (showing 4 channels), stack them vertically
-static bool save_layer_composite(const char* dir, int width, int height, int num_layers) {
+static bool save_layer_composite(const char* dir, int width, int height,
+ int num_layers) {
// Each layer PNG is already 4x wide with 4 channels side-by-side
int layer_width = width * 4;
@@ -341,8 +353,11 @@ static bool save_layer_composite(const char* dir, int width, int height, int num
int w, h, channels;
uint8_t* data = stbi_load(path, &w, &h, &channels, 1); // Load as grayscale
if (!data || w != layer_width || h != height) {
- if (data) stbi_image_free(data);
- fprintf(stderr, "Warning: failed to load layer %d for composite (expected %dx%d, got %dx%d)\n",
+ if (data)
+ stbi_image_free(data);
+ fprintf(stderr,
+ "Warning: failed to load layer %d for composite (expected %dx%d, "
+ "got %dx%d)\n",
i, layer_width, height, w, h);
return false;
}
@@ -359,13 +374,15 @@ static bool save_layer_composite(const char* dir, int width, int height, int num
for (int y = 0; y < height; ++y) {
int src_row_offset = y * layer_width;
int dst_row_offset = (layer * height + y) * layer_width;
- memcpy(&composite[dst_row_offset], &layers[layer][src_row_offset], layer_width);
+ memcpy(&composite[dst_row_offset], &layers[layer][src_row_offset],
+ layer_width);
}
}
// Save as grayscale PNG (stacked vertically)
char composite_path[512];
- snprintf(composite_path, sizeof(composite_path), "%s/layers_composite.png", dir);
+ snprintf(composite_path, sizeof(composite_path), "%s/layers_composite.png",
+ dir);
if (!stbi_write_png(composite_path, layer_width, composite_height, 1,
composite.data(), layer_width)) {
fprintf(stderr, "Error: failed to write composite PNG\n");
@@ -388,8 +405,8 @@ static bool save_ppm(const char* path, const std::vector<uint8_t>& pixels,
fprintf(f, "P6\n%d %d\n255\n", width, height);
for (int i = 0; i < width * height; ++i) {
- const uint8_t rgb[3] = {pixels[i * 4 + 2], // R
- pixels[i * 4 + 1], // G
+ const uint8_t rgb[3] = {pixels[i * 4 + 2], // R
+ pixels[i * 4 + 1], // G
pixels[i * 4 + 0]}; // B
fwrite(rgb, 1, 3, f);
}
@@ -423,9 +440,9 @@ struct CNNv2StaticFeatureParams {
};
// Convert RGBA32Uint (packed f16) texture to BGRA8Unorm
-static std::vector<uint8_t> readback_rgba32uint_to_bgra8(
- WGPUDevice device, WGPUQueue queue, WGPUTexture texture,
- int width, int height) {
+static std::vector<uint8_t>
+readback_rgba32uint_to_bgra8(WGPUDevice device, WGPUQueue queue,
+ WGPUTexture texture, int width, int height) {
// Create staging buffer
const uint32_t bytes_per_row = width * 16; // 4×u32 per pixel
const uint32_t padded_bytes_per_row = (bytes_per_row + 255) & ~255;
@@ -450,10 +467,8 @@ static std::vector<uint8_t> readback_rgba32uint_to_bgra8(
dst.layout.bytesPerRow = padded_bytes_per_row;
dst.layout.rowsPerImage = height;
- WGPUExtent3D copy_size = {
- static_cast<uint32_t>(width),
- static_cast<uint32_t>(height),
- 1};
+ WGPUExtent3D copy_size = {static_cast<uint32_t>(width),
+ static_cast<uint32_t>(height), 1};
wgpuCommandEncoderCopyTextureToBuffer(encoder, &src, &dst, &copy_size);
@@ -527,7 +542,8 @@ static std::vector<uint8_t> readback_rgba32uint_to_bgra8(
uint32_t frac = h & 0x3FF;
if (exp == 0) {
- if (frac == 0) return sign ? -0.0f : 0.0f;
+ if (frac == 0)
+ return sign ? -0.0f : 0.0f;
// Denormal
float val = frac / 1024.0f / 16384.0f;
return sign ? -val : val;
@@ -548,8 +564,10 @@ static std::vector<uint8_t> readback_rgba32uint_to_bgra8(
// Clamp to [0,1] and convert to u8
auto clamp_u8 = [](float v) -> uint8_t {
- if (v <= 0.0f) return 0;
- if (v >= 1.0f) return 255;
+ if (v <= 0.0f)
+ return 0;
+ if (v >= 1.0f)
+ return 255;
return static_cast<uint8_t>(v * 255.0f + 0.5f);
};
@@ -566,14 +584,16 @@ static std::vector<uint8_t> readback_rgba32uint_to_bgra8(
return result;
}
-// Read RGBA32Uint and create 4x wide grayscale composite (each channel side-by-side)
-static std::vector<uint8_t> readback_rgba32uint_to_composite(
- WGPUDevice device, WGPUQueue queue, WGPUTexture texture,
- int width, int height) {
-
+// Read RGBA32Uint and create 4x wide grayscale composite (each channel
+// side-by-side)
+static std::vector<uint8_t>
+readback_rgba32uint_to_composite(WGPUDevice device, WGPUQueue queue,
+ WGPUTexture texture, int width, int height) {
// First get BGRA8 data
- std::vector<uint8_t> bgra = readback_rgba32uint_to_bgra8(device, queue, texture, width, height);
- if (bgra.empty()) return {};
+ std::vector<uint8_t> bgra =
+ readback_rgba32uint_to_bgra8(device, queue, texture, width, height);
+ if (bgra.empty())
+ return {};
// Create 4x wide grayscale image (one channel per horizontal strip)
int composite_width = width * 4;
@@ -591,10 +611,14 @@ static std::vector<uint8_t> readback_rgba32uint_to_composite(
auto to_gray = [](uint8_t val) -> uint8_t { return val; };
// Place each channel in its horizontal strip
- composite[y * composite_width + (0 * width + x)] = to_gray(r); // Channel 0
- composite[y * composite_width + (1 * width + x)] = to_gray(g); // Channel 1
- composite[y * composite_width + (2 * width + x)] = to_gray(b); // Channel 2
- composite[y * composite_width + (3 * width + x)] = to_gray(a); // Channel 3
+ composite[y * composite_width + (0 * width + x)] =
+ to_gray(r); // Channel 0
+ composite[y * composite_width + (1 * width + x)] =
+ to_gray(g); // Channel 1
+ composite[y * composite_width + (2 * width + x)] =
+ to_gray(b); // Channel 2
+ composite[y * composite_width + (3 * width + x)] =
+ to_gray(a); // Channel 3
}
}
@@ -610,14 +634,15 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
// Load weights (from file or asset system)
size_t weights_size = 0;
const uint8_t* weights_data = nullptr;
- std::vector<uint8_t> file_weights; // For file-based loading
+ std::vector<uint8_t> file_weights; // For file-based loading
if (args.weights_path) {
// Load from file
printf("Loading weights from '%s'...\n", args.weights_path);
FILE* f = fopen(args.weights_path, "rb");
if (!f) {
- fprintf(stderr, "Error: failed to open weights file '%s'\n", args.weights_path);
+ fprintf(stderr, "Error: failed to open weights file '%s'\n",
+ args.weights_path);
return false;
}
@@ -637,7 +662,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
weights_data = file_weights.data();
} else {
// Load from asset system
- weights_data = (const uint8_t*)GetAsset(AssetId::ASSET_WEIGHTS_CNN_V2, &weights_size);
+ weights_data =
+ (const uint8_t*)GetAsset(AssetId::ASSET_WEIGHTS_CNN_V2, &weights_size);
}
if (!weights_data || weights_size < 20) {
@@ -652,7 +678,7 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
uint32_t num_layers = header[2];
uint32_t total_weights = header[3];
- if (magic != 0x324e4e43) { // 'CNN2'
+ if (magic != 0x324e4e43) { // 'CNN2'
fprintf(stderr, "Error: Invalid CNN v2 weights magic\n");
return false;
}
@@ -684,9 +710,10 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
info.out_channels, info.weight_count);
}
- // Create weights storage buffer (skip header + layer info, upload only weights)
- size_t header_size = 20; // 5 u32
- size_t layer_info_size = 20 * layer_info.size(); // 5 u32 per layer
+ // Create weights storage buffer (skip header + layer info, upload only
+ // weights)
+ size_t header_size = 20; // 5 u32
+ size_t layer_info_size = 20 * layer_info.size(); // 5 u32 per layer
size_t weights_offset = header_size + layer_info_size;
size_t weights_only_size = weights_size - weights_offset;
@@ -697,7 +724,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
WGPUBuffer weights_buffer =
wgpuDeviceCreateBuffer(device, &weights_buffer_desc);
- wgpuQueueWriteBuffer(queue, weights_buffer, 0, weights_data + weights_offset, weights_only_size);
+ wgpuQueueWriteBuffer(queue, weights_buffer, 0, weights_data + weights_offset,
+ weights_only_size);
// Create input view
WGPUTextureView input_view =
@@ -705,7 +733,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
// Create static features texture (RGBA32Uint)
const WGPUTextureDescriptor static_desc = {
- .usage = WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc,
+ .usage = WGPUTextureUsage_StorageBinding |
+ WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc,
.dimension = WGPUTextureDimension_2D,
.size = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1},
.format = WGPUTextureFormat_RGBA32Uint,
@@ -740,10 +769,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
};
// Load shaders
- const char* static_shader =
- SafeGetAsset(AssetId::ASSET_SHADER_CNN_V2_STATIC);
- const char* layer_shader =
- SafeGetAsset(AssetId::ASSET_SHADER_CNN_V2_COMPUTE);
+ const char* static_shader = SafeGetAsset(AssetId::ASSET_SHADER_CNN_V2_STATIC);
+ const char* layer_shader = SafeGetAsset(AssetId::ASSET_SHADER_CNN_V2_COMPUTE);
if (!static_shader[0] || !layer_shader[0]) {
fprintf(stderr, "Error: CNN v2 shaders not available\n");
@@ -789,7 +816,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
linear_sampler_desc.lodMaxClamp = 32.0f;
linear_sampler_desc.maxAnisotropy = 1;
- WGPUSampler linear_sampler = wgpuDeviceCreateSampler(device, &linear_sampler_desc);
+ WGPUSampler linear_sampler =
+ wgpuDeviceCreateSampler(device, &linear_sampler_desc);
// Create static features compute pipeline
WGPUShaderSourceWGSL static_wgsl = {};
@@ -822,7 +850,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
static_bgl_entries[3].binding = 3;
static_bgl_entries[3].visibility = WGPUShaderStage_Compute;
- static_bgl_entries[3].texture.sampleType = WGPUTextureSampleType_UnfilterableFloat;
+ static_bgl_entries[3].texture.sampleType =
+ WGPUTextureSampleType_UnfilterableFloat;
static_bgl_entries[3].texture.viewDimension = WGPUTextureViewDimension_2D;
static_bgl_entries[4].binding = 4;
@@ -877,7 +906,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
static_bg_entries[2].binding = 2;
static_bg_entries[2].textureView = input_view;
static_bg_entries[3].binding = 3;
- static_bg_entries[3].textureView = depth_view; // Depth from alpha channel (matches training)
+ static_bg_entries[3].textureView =
+ depth_view; // Depth from alpha channel (matches training)
static_bg_entries[4].binding = 4;
static_bg_entries[4].textureView = static_features_view;
static_bg_entries[5].binding = 5;
@@ -992,7 +1022,7 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
uint32_t workgroups_x = (width + 7) / 8;
uint32_t workgroups_y = (height + 7) / 8;
wgpuComputePassEncoderDispatchWorkgroups(static_pass, workgroups_x,
- workgroups_y, 1);
+ workgroups_y, 1);
wgpuComputePassEncoderEnd(static_pass);
wgpuComputePassEncoderRelease(static_pass);
@@ -1014,7 +1044,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
printf("Saving static features to '%s'...\n", layer_path);
// Read back RGBA32Uint and create 8-channel grayscale composite
- // Static features has 8 channels (packed as 4×u32), create 8x wide composite
+ // Static features has 8 channels (packed as 4×u32), create 8x wide
+ // composite
std::vector<uint8_t> bgra = readback_rgba32uint_to_bgra8(
device, queue, static_features_tex, width, height);
@@ -1083,8 +1114,7 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
layer_bg_desc.entryCount = 6;
layer_bg_desc.entries = layer_bg_entries;
- WGPUBindGroup layer_bg =
- wgpuDeviceCreateBindGroup(device, &layer_bg_desc);
+ WGPUBindGroup layer_bg = wgpuDeviceCreateBindGroup(device, &layer_bg_desc);
WGPUComputePassEncoder layer_pass =
wgpuCommandEncoderBeginComputePass(encoder, nullptr);
@@ -1092,7 +1122,7 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
wgpuComputePassEncoderSetBindGroup(layer_pass, 0, layer_bg, 0, nullptr);
wgpuComputePassEncoderDispatchWorkgroups(layer_pass, workgroups_x,
- workgroups_y, 1);
+ workgroups_y, 1);
wgpuComputePassEncoderEnd(layer_pass);
wgpuComputePassEncoderRelease(layer_pass);
@@ -1138,7 +1168,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
// Create layer composite if intermediates were saved
if (args.save_intermediates) {
- save_layer_composite(args.save_intermediates, width, height, layer_info.size());
+ save_layer_composite(args.save_intermediates, width, height,
+ layer_info.size());
}
// Readback final result (from last layer's output texture)
@@ -1149,7 +1180,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
if (pixels.empty()) {
fprintf(stderr, "Error: GPU readback failed\n");
- for (auto buf : layer_params_buffers) wgpuBufferRelease(buf);
+ for (auto buf : layer_params_buffers)
+ wgpuBufferRelease(buf);
wgpuComputePipelineRelease(layer_pipeline);
wgpuBindGroupLayoutRelease(layer_bgl);
wgpuBindGroupRelease(static_bg);
@@ -1195,7 +1227,8 @@ static bool process_cnn_v2(WGPUDevice device, WGPUQueue queue,
}
// Cleanup
- for (auto buf : layer_params_buffers) wgpuBufferRelease(buf);
+ for (auto buf : layer_params_buffers)
+ wgpuBufferRelease(buf);
wgpuComputePipelineRelease(layer_pipeline);
wgpuBindGroupLayoutRelease(layer_bgl);
wgpuBindGroupRelease(static_bg);
@@ -1250,8 +1283,8 @@ int main(int argc, char** argv) {
// Branch based on CNN version
if (args.cnn_version == 2) {
- bool success = process_cnn_v2(device, queue, instance, input_texture,
- width, height, args);
+ bool success = process_cnn_v2(device, queue, instance, input_texture, width,
+ height, args);
wgpuTextureRelease(input_texture);
SamplerCache::Get().clear();
fixture.shutdown();
@@ -1274,8 +1307,10 @@ int main(int argc, char** argv) {
if (!pipeline_intermediate || !pipeline_final) {
fprintf(stderr, "Error: failed to create CNN pipelines\n");
- if (pipeline_intermediate) wgpuRenderPipelineRelease(pipeline_intermediate);
- if (pipeline_final) wgpuRenderPipelineRelease(pipeline_final);
+ if (pipeline_intermediate)
+ wgpuRenderPipelineRelease(pipeline_intermediate);
+ if (pipeline_final)
+ wgpuRenderPipelineRelease(pipeline_final);
wgpuTextureViewRelease(input_view);
wgpuTextureRelease(input_texture);
SamplerCache::Get().clear();
@@ -1284,7 +1319,8 @@ int main(int argc, char** argv) {
}
// Get bind group layout from intermediate pipeline (same for both)
- WGPUBindGroupLayout bgl = wgpuRenderPipelineGetBindGroupLayout(pipeline_intermediate, 0);
+ WGPUBindGroupLayout bgl =
+ wgpuRenderPipelineGetBindGroupLayout(pipeline_intermediate, 0);
// Create uniform buffers
const WGPUBufferDescriptor common_uniform_desc = {
@@ -1363,15 +1399,14 @@ int main(int argc, char** argv) {
sizeof(layer_params));
// Build bind group
- WGPUBindGroup bind_group = BindGroupBuilder()
- .sampler(0, sampler)
- .texture(1, current_input)
- .buffer(2, common_uniform_buffer,
- sizeof(CommonPostProcessUniforms))
- .buffer(3, layer_params_buffer,
- sizeof(CNNLayerParams))
- .texture(4, original_view)
- .build(device, bgl);
+ WGPUBindGroup bind_group =
+ BindGroupBuilder()
+ .sampler(0, sampler)
+ .texture(1, current_input)
+ .buffer(2, common_uniform_buffer, sizeof(CommonPostProcessUniforms))
+ .buffer(3, layer_params_buffer, sizeof(CNNLayerParams))
+ .texture(4, original_view)
+ .build(device, bgl);
// Render to appropriate output texture with correct pipeline
bool is_final = (layer == NUM_LAYERS - 1);
@@ -1379,7 +1414,8 @@ int main(int argc, char** argv) {
if (is_final) {
// Final layer: use OffscreenRenderTarget (known working readback)
OffscreenRenderTarget rt(instance, device, width, height);
- WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
+ WGPUCommandEncoder encoder =
+ wgpuDeviceCreateCommandEncoder(device, nullptr);
WGPURenderPassEncoder pass = begin_render_pass(encoder, rt.view());
wgpuRenderPassEncoderSetPipeline(pass, pipeline_final);
wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr);
@@ -1456,11 +1492,12 @@ int main(int argc, char** argv) {
}
printf("Done! Output saved to '%s'\n", args.output_path);
- break; // Exit loop after final layer
+ break; // Exit loop after final layer
} else {
// Intermediate layers: render to ping-pong textures
WGPUTextureView output_view = intermediate_views[dst_idx];
- WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
+ WGPUCommandEncoder encoder =
+ wgpuDeviceCreateCommandEncoder(device, nullptr);
WGPURenderPassEncoder pass = begin_render_pass(encoder, output_view);
wgpuRenderPassEncoderSetPipeline(pass, pipeline_intermediate);
wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr);
@@ -1501,7 +1538,8 @@ int main(int argc, char** argv) {
if (!pixels.empty()) {
save_png(layer_path, pixels, width, height);
} else {
- fprintf(stderr, "Warning: failed to read intermediate layer %d\n", layer);
+ fprintf(stderr, "Warning: failed to read intermediate layer %d\n",
+ layer);
}
}
}