summaryrefslogtreecommitdiff
path: root/src/gpu/effects/cnn_v2_effect.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-14 12:38:59 +0100
committerskal <pascal.massimino@gmail.com>2026-02-14 12:38:59 +0100
commitc4cfc8459dbc6fde74d5553519dc3fcb1afccad0 (patch)
treea6869d1f3c14778345ab45b9c69763d07adcca45 /src/gpu/effects/cnn_v2_effect.cc
parent0f53ed1ed8ed7c07cd7ea8e88e21b5be5d5494e5 (diff)
Refactor: factorize common WGPU patterns into helper functions
Add texture creation helpers (gpu_create_texture_2d, gpu_create_storage_texture_2d, gpu_create_mip_view) and extend BindGroupLayoutBuilder with uint_texture and storage_texture methods. Refactored files: - cnn_v2_effect.cc: Use texture helpers (~70% code reduction in create_textures) - rotating_cube_effect.cc: Use BindGroupLayoutBuilder and texture helpers - circle_mask_effect.cc: Use BindGroupBuilder Benefits: - Improved code readability - Reduced boilerplate for texture/bind group creation - Consistent patterns across effects Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/gpu/effects/cnn_v2_effect.cc')
-rw-r--r--src/gpu/effects/cnn_v2_effect.cc260
1 files changed, 55 insertions, 205 deletions
diff --git a/src/gpu/effects/cnn_v2_effect.cc b/src/gpu/effects/cnn_v2_effect.cc
index d412154..be856a4 100644
--- a/src/gpu/effects/cnn_v2_effect.cc
+++ b/src/gpu/effects/cnn_v2_effect.cc
@@ -8,6 +8,8 @@
#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>
@@ -142,76 +144,30 @@ void CNNv2Effect::load_weights() {
}
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);
+ 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)
- 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);
+ 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) {
- 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);
+ 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) {
- WGPUTextureDescriptor layer_desc = {};
- layer_desc.usage = WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding;
- layer_desc.dimension = WGPUTextureDimension_2D;
- layer_desc.size = size;
- layer_desc.format = WGPUTextureFormat_RGBA32Uint;
- layer_desc.mipLevelCount = 1;
- layer_desc.sampleCount = 1;
-
- WGPUTexture tex = wgpuDeviceCreateTexture(ctx_.device, &layer_desc);
- layer_textures_.push_back(tex);
-
- 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;
-
- WGPUTextureView view = wgpuTextureCreateView(tex, &view_desc);
- layer_views_.push_back(view);
+ 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
@@ -255,55 +211,17 @@ void CNNv2Effect::create_pipelines() {
// 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
- WGPUBindGroupLayoutEntry bgl_entries[7] = {};
-
- // Binding 0: Input texture (mip 0)
- bgl_entries[0].binding = 0;
- bgl_entries[0].visibility = WGPUShaderStage_Compute;
- bgl_entries[0].texture.sampleType = WGPUTextureSampleType_Float;
- bgl_entries[0].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 1: Input texture (mip 1)
- bgl_entries[1].binding = 1;
- bgl_entries[1].visibility = WGPUShaderStage_Compute;
- bgl_entries[1].texture.sampleType = WGPUTextureSampleType_Float;
- bgl_entries[1].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 2: Input texture (mip 2)
- bgl_entries[2].binding = 2;
- bgl_entries[2].visibility = WGPUShaderStage_Compute;
- bgl_entries[2].texture.sampleType = WGPUTextureSampleType_Float;
- bgl_entries[2].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 3: Depth texture
- bgl_entries[3].binding = 3;
- bgl_entries[3].visibility = WGPUShaderStage_Compute;
- bgl_entries[3].texture.sampleType = WGPUTextureSampleType_Float;
- bgl_entries[3].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 4: Output (static features)
- bgl_entries[4].binding = 4;
- bgl_entries[4].visibility = WGPUShaderStage_Compute;
- bgl_entries[4].storageTexture.access = WGPUStorageTextureAccess_WriteOnly;
- bgl_entries[4].storageTexture.format = WGPUTextureFormat_RGBA32Uint;
- bgl_entries[4].storageTexture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 5: Params (mip_level)
- bgl_entries[5].binding = 5;
- bgl_entries[5].visibility = WGPUShaderStage_Compute;
- bgl_entries[5].buffer.type = WGPUBufferBindingType_Uniform;
- bgl_entries[5].buffer.minBindingSize = sizeof(StaticFeatureParams);
-
- // Binding 6: Linear sampler (for bilinear interpolation)
- bgl_entries[6].binding = 6;
- bgl_entries[6].visibility = WGPUShaderStage_Compute;
- bgl_entries[6].sampler.type = WGPUSamplerBindingType_Filtering;
-
- WGPUBindGroupLayoutDescriptor bgl_desc = {};
- bgl_desc.entryCount = 7;
- bgl_desc.entries = bgl_entries;
-
- WGPUBindGroupLayout static_bgl = wgpuDeviceCreateBindGroupLayout(ctx_.device, &bgl_desc);
+ 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 = {};
@@ -344,49 +262,16 @@ void CNNv2Effect::create_pipelines() {
// Create bind group layout for layer compute
// 0=static_features, 1=layer_input, 2=output, 3=weights, 4=params, 5=original_input
- WGPUBindGroupLayoutEntry layer_bgl_entries[6] = {};
-
- // Binding 0: Static features (texture)
- layer_bgl_entries[0].binding = 0;
- layer_bgl_entries[0].visibility = WGPUShaderStage_Compute;
- layer_bgl_entries[0].texture.sampleType = WGPUTextureSampleType_Uint;
- layer_bgl_entries[0].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 1: Layer input (texture)
- layer_bgl_entries[1].binding = 1;
- layer_bgl_entries[1].visibility = WGPUShaderStage_Compute;
- layer_bgl_entries[1].texture.sampleType = WGPUTextureSampleType_Uint;
- layer_bgl_entries[1].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 2: Output (storage texture)
- layer_bgl_entries[2].binding = 2;
- layer_bgl_entries[2].visibility = WGPUShaderStage_Compute;
- layer_bgl_entries[2].storageTexture.access = WGPUStorageTextureAccess_WriteOnly;
- layer_bgl_entries[2].storageTexture.format = WGPUTextureFormat_RGBA32Uint;
- layer_bgl_entries[2].storageTexture.viewDimension = WGPUTextureViewDimension_2D;
-
- // Binding 3: Weights (storage buffer)
- layer_bgl_entries[3].binding = 3;
- layer_bgl_entries[3].visibility = WGPUShaderStage_Compute;
- layer_bgl_entries[3].buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
-
- // Binding 4: Layer params (uniform buffer)
- layer_bgl_entries[4].binding = 4;
- layer_bgl_entries[4].visibility = WGPUShaderStage_Compute;
- layer_bgl_entries[4].buffer.type = WGPUBufferBindingType_Uniform;
- layer_bgl_entries[4].buffer.minBindingSize = sizeof(LayerParams);
-
- // Binding 5: Original input (for blending)
- layer_bgl_entries[5].binding = 5;
- layer_bgl_entries[5].visibility = WGPUShaderStage_Compute;
- layer_bgl_entries[5].texture.sampleType = WGPUTextureSampleType_Float;
- layer_bgl_entries[5].texture.viewDimension = WGPUTextureViewDimension_2D;
-
- WGPUBindGroupLayoutDescriptor layer_bgl_desc = {};
- layer_bgl_desc.entryCount = 6;
- layer_bgl_desc.entries = layer_bgl_entries;
-
- WGPUBindGroupLayout layer_bgl = wgpuDeviceCreateBindGroupLayout(ctx_.device, &layer_bgl_desc);
+ 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;
@@ -418,46 +303,33 @@ void CNNv2Effect::update_bind_group(WGPUTextureView input_view) {
static_bind_group_ = nullptr;
}
- // Create bind group for static features compute
+ // Create bind group for static features compute (manual for storage texture binding)
WGPUBindGroupEntry bg_entries[7] = {};
-
- // Binding 0: Input (mip 0)
bg_entries[0].binding = 0;
bg_entries[0].textureView = input_view;
-
- // Binding 1: Input (mip 1)
bg_entries[1].binding = 1;
bg_entries[1].textureView = input_mip_view_[0];
-
- // Binding 2: Input (mip 2)
bg_entries[2].binding = 2;
- bg_entries[2].textureView = (input_mip_view_[1]) ? input_mip_view_[1] : input_mip_view_[0];
-
- // Binding 3: Depth (use input for now, no depth available)
+ 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;
-
- // Binding 4: Output (static features)
bg_entries[4].binding = 4;
bg_entries[4].textureView = static_features_view_;
-
- // Binding 5: Params
bg_entries[5].binding = 5;
bg_entries[5].buffer = static_params_buffer_;
bg_entries[5].size = sizeof(StaticFeatureParams);
-
- // Binding 6: Linear sampler
bg_entries[6].binding = 6;
bg_entries[6].sampler = linear_sampler_;
+ WGPUBindGroupLayout layout =
+ wgpuComputePipelineGetBindGroupLayout(static_pipeline_, 0);
WGPUBindGroupDescriptor bg_desc = {};
- bg_desc.layout = wgpuComputePipelineGetBindGroupLayout(static_pipeline_, 0);
+ bg_desc.layout = layout;
bg_desc.entryCount = 7;
bg_desc.entries = bg_entries;
-
static_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc);
-
- wgpuBindGroupLayoutRelease(bg_desc.layout);
+ wgpuBindGroupLayoutRelease(layout);
// Create layer bind groups
if (!layer_pipeline_ || layer_info_.empty()) return;
@@ -473,41 +345,19 @@ void CNNv2Effect::update_bind_group(WGPUTextureView input_view) {
// Create bind group for each layer
for (size_t i = 0; i < layer_info_.size(); ++i) {
- WGPUBindGroupEntry layer_entries[6] = {};
-
- // Binding 0: Static features (constant)
- layer_entries[0].binding = 0;
- layer_entries[0].textureView = static_features_view_;
-
- // Binding 1: Layer input (ping-pong: use previous layer's output)
- // First layer uses static features as input, others use ping-pong buffers
- layer_entries[1].binding = 1;
- layer_entries[1].textureView = (i == 0) ? static_features_view_ : layer_views_[i % 2];
-
- // Binding 2: Output texture (ping-pong)
- layer_entries[2].binding = 2;
- layer_entries[2].textureView = layer_views_[(i + 1) % 2];
-
- // Binding 3: Weights buffer (constant)
- layer_entries[3].binding = 3;
- layer_entries[3].buffer = weights_buffer_;
- layer_entries[3].size = wgpuBufferGetSize(weights_buffer_);
-
- // Binding 4: Layer params (use dedicated buffer for this layer)
- layer_entries[4].binding = 4;
- layer_entries[4].buffer = layer_params_buffers_[i];
- layer_entries[4].size = sizeof(LayerParams);
-
- // Binding 5: Original input (for blending)
- layer_entries[5].binding = 5;
- layer_entries[5].textureView = input_view;
+ WGPUTextureView layer_input =
+ (i == 0) ? static_features_view_ : layer_views_[i % 2];
- WGPUBindGroupDescriptor layer_bg_desc = {};
- layer_bg_desc.layout = layer_bgl;
- layer_bg_desc.entryCount = 6;
- layer_bg_desc.entries = layer_entries;
+ 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);
- WGPUBindGroup layer_bg = wgpuDeviceCreateBindGroup(ctx_.device, &layer_bg_desc);
layer_bind_groups_.push_back(layer_bg);
}