summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-14 14:15:07 +0100
committerskal <pascal.massimino@gmail.com>2026-02-14 14:15:07 +0100
commit12f83d4615a38cb0b1ed8a3eb436c4acca170479 (patch)
treef9058b6e526ff3015b10da2d20ac5e0b15638706
parent61ced8aa1946cc32de4328cc75b5faf6b77723be (diff)
Refactor: add gpu_create_post_process_texture helper
Adds new helper for common post-process texture pattern (RenderAttachment | TextureBinding | CopySrc usage). Refactors test_post_process_helper.cc to use gpu_create_buffer() and gpu_create_post_process_texture(), eliminating 91 lines of boilerplate. - New: gpu_create_post_process_texture() in gpu.{h,cc} - Refactor: test_post_process_helper.cc uses helpers instead of raw WGPU - Doc: Updated WGPU_HELPERS.md with usage examples - Verified: All tests passing (test_post_process_helper, test_demo_effects) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
-rw-r--r--doc/WGPU_HELPERS.md39
-rw-r--r--src/gpu/gpu.cc10
-rw-r--r--src/gpu/gpu.h3
-rw-r--r--src/tests/gpu/test_post_process_helper.cc133
4 files changed, 95 insertions, 90 deletions
diff --git a/doc/WGPU_HELPERS.md b/doc/WGPU_HELPERS.md
index 5642eef..f1d83d5 100644
--- a/doc/WGPU_HELPERS.md
+++ b/doc/WGPU_HELPERS.md
@@ -133,6 +133,45 @@ TextureWithView output = gpu_create_storage_texture_2d(
---
+#### `gpu_create_post_process_texture`
+```cpp
+TextureWithView gpu_create_post_process_texture(
+ WGPUDevice device, uint32_t width, uint32_t height,
+ WGPUTextureFormat format);
+```
+
+**Purpose:** Create texture for post-processing effects (render target + input + readback).
+
+**Parameters:**
+- `device` - WGPU device handle
+- `width`, `height` - Texture dimensions
+- `format` - Pixel format (typically `WGPUTextureFormat_RGBA8Unorm`)
+
+**Returns:** `TextureWithView` with usage flags:
+- `WGPUTextureUsage_RenderAttachment` - Can render to it
+- `WGPUTextureUsage_TextureBinding` - Can sample from it
+- `WGPUTextureUsage_CopySrc` - Can read back pixels
+
+**Example:**
+```cpp
+// Create ping-pong buffers for multi-pass post-processing
+TextureWithView buffer_a = gpu_create_post_process_texture(
+ device, 1920, 1080, WGPUTextureFormat_RGBA8Unorm);
+TextureWithView buffer_b = gpu_create_post_process_texture(
+ device, 1920, 1080, WGPUTextureFormat_RGBA8Unorm);
+
+// Pass 1: Render to buffer_a
+// Pass 2: Sample buffer_a, render to buffer_b
+// Pass 3: Copy buffer_b to screen
+```
+
+**Common Use Cases:**
+- Post-process ping-pong buffers
+- Off-screen render targets that need sampling
+- Test fixtures requiring texture readback
+
+---
+
#### `gpu_create_mip_view`
```cpp
WGPUTextureView gpu_create_mip_view(WGPUTexture texture,
diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc
index 535de67..afbba90 100644
--- a/src/gpu/gpu.cc
+++ b/src/gpu/gpu.cc
@@ -84,6 +84,16 @@ TextureWithView gpu_create_storage_texture_2d(WGPUDevice device, uint32_t width,
WGPUTextureUsage_StorageBinding | WGPUTextureUsage_TextureBinding, 1);
}
+TextureWithView gpu_create_post_process_texture(WGPUDevice device,
+ uint32_t width, uint32_t height,
+ WGPUTextureFormat format) {
+ return gpu_create_texture_2d(
+ device, width, height, format,
+ WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding |
+ WGPUTextureUsage_CopySrc,
+ 1);
+}
+
WGPUTextureView gpu_create_mip_view(WGPUTexture texture,
WGPUTextureFormat format,
uint32_t mip_level) {
diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h
index 74e0eb7..0b0153b 100644
--- a/src/gpu/gpu.h
+++ b/src/gpu/gpu.h
@@ -97,6 +97,9 @@ TextureWithView gpu_create_texture_2d(WGPUDevice device, uint32_t width,
TextureWithView gpu_create_storage_texture_2d(WGPUDevice device, uint32_t width,
uint32_t height,
WGPUTextureFormat format);
+TextureWithView gpu_create_post_process_texture(WGPUDevice device,
+ uint32_t width, uint32_t height,
+ WGPUTextureFormat format);
WGPUTextureView gpu_create_mip_view(WGPUTexture texture,
WGPUTextureFormat format, uint32_t mip_level);
WGPUTextureView gpu_create_texture_view_2d(WGPUTexture texture,
diff --git a/src/tests/gpu/test_post_process_helper.cc b/src/tests/gpu/test_post_process_helper.cc
index 08b9e49..42b5d79 100644
--- a/src/tests/gpu/test_post_process_helper.cc
+++ b/src/tests/gpu/test_post_process_helper.cc
@@ -18,28 +18,7 @@ extern void pp_update_bind_group(WGPUDevice device, WGPURenderPipeline pipeline,
WGPUTextureView input_view,
GpuBuffer uniforms, GpuBuffer effect_params);
-// Helper: Create a texture suitable for post-processing (both render target and
-// texture binding)
-static WGPUTexture create_post_process_texture(WGPUDevice device, int width,
- int height,
- WGPUTextureFormat format) {
- const WGPUTextureDescriptor texture_desc = {
- .usage = WGPUTextureUsage_RenderAttachment |
- WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopySrc,
- .dimension = WGPUTextureDimension_2D,
- .size = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1},
- .format = format,
- .mipLevelCount = 1,
- .sampleCount = 1,
- };
- return wgpuDeviceCreateTexture(device, &texture_desc);
-}
-
-// Helper: Create texture view
-static WGPUTextureView create_texture_view(WGPUTexture texture,
- WGPUTextureFormat format) {
- return gpu_create_texture_view_2d(texture, format);
-}
+// Helpers are now in gpu.h (gpu_create_post_process_texture, gpu_create_texture_view_2d)
// Minimal valid post-process shader for testing
static const char* test_shader = R"(
@@ -87,30 +66,21 @@ static void test_bind_group_creation(WebGPUTestFixture& fixture) {
assert(pipeline != nullptr && "Pipeline required for bind group test");
// Create input texture with TEXTURE_BINDING usage
- WGPUTexture input_texture =
- create_post_process_texture(fixture.device(), 256, 256, fixture.format());
- WGPUTextureView input_view =
- create_texture_view(input_texture, fixture.format());
-
- // Create uniform buffer
- const WGPUBufferDescriptor uniform_desc = {
- .usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst,
- .size = 16, // vec4<f32>
- };
- WGPUBuffer uniform_buffer =
- wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc);
- assert(uniform_buffer != nullptr && "Uniform buffer should be created");
+ TextureWithView input =
+ gpu_create_post_process_texture(fixture.device(), 256, 256, fixture.format());
- GpuBuffer uniforms = {uniform_buffer, 16};
+ // Create uniform buffers using gpu_create_buffer
+ GpuBuffer uniforms = gpu_create_buffer(
+ fixture.device(), 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
+ assert(uniforms.buffer != nullptr && "Uniform buffer should be created");
// Dummy effect params buffer for testing (matches vec4<f32>)
- WGPUBuffer dummy_params_buffer_handle =
- wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc);
- GpuBuffer dummy_effect_params_buffer = {dummy_params_buffer_handle, 16};
+ GpuBuffer dummy_effect_params_buffer = gpu_create_buffer(
+ fixture.device(), 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
// Test bind group creation
WGPUBindGroup bind_group = nullptr;
- pp_update_bind_group(fixture.device(), pipeline, &bind_group, input_view,
+ pp_update_bind_group(fixture.device(), pipeline, &bind_group, input.view,
uniforms, dummy_effect_params_buffer);
assert(bind_group != nullptr && "Bind group should be created successfully");
@@ -118,10 +88,10 @@ static void test_bind_group_creation(WebGPUTestFixture& fixture) {
// Cleanup
wgpuBindGroupRelease(bind_group);
- wgpuTextureViewRelease(input_view);
- wgpuTextureRelease(input_texture);
- wgpuBufferRelease(uniform_buffer);
- wgpuBufferRelease(dummy_params_buffer_handle);
+ wgpuTextureViewRelease(input.view);
+ wgpuTextureRelease(input.texture);
+ wgpuBufferRelease(uniforms.buffer);
+ wgpuBufferRelease(dummy_effect_params_buffer.buffer);
wgpuRenderPipelineRelease(pipeline);
fprintf(stdout, " ✓ Resources released\n");
}
@@ -133,48 +103,39 @@ static void test_bind_group_update(WebGPUTestFixture& fixture) {
WGPURenderPipeline pipeline = create_post_process_pipeline(
fixture.device(), fixture.format(), test_shader);
- WGPUTexture texture1 =
- create_post_process_texture(fixture.device(), 256, 256, fixture.format());
- WGPUTextureView view1 = create_texture_view(texture1, fixture.format());
+ TextureWithView texture1 =
+ gpu_create_post_process_texture(fixture.device(), 256, 256, fixture.format());
+ TextureWithView texture2 =
+ gpu_create_post_process_texture(fixture.device(), 512, 512, fixture.format());
- WGPUTexture texture2 =
- create_post_process_texture(fixture.device(), 512, 512, fixture.format());
- WGPUTextureView view2 = create_texture_view(texture2, fixture.format());
-
- const WGPUBufferDescriptor uniform_desc = {
- .usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst,
- .size = 16,
- };
- WGPUBuffer uniform_buffer =
- wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc);
- GpuBuffer uniforms = {uniform_buffer, 16};
+ GpuBuffer uniforms = gpu_create_buffer(
+ fixture.device(), 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
// Dummy effect params buffer for testing (matches vec4<f32>)
- WGPUBuffer dummy_params_buffer_handle =
- wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc);
- GpuBuffer dummy_effect_params_buffer = {dummy_params_buffer_handle, 16};
+ GpuBuffer dummy_effect_params_buffer = gpu_create_buffer(
+ fixture.device(), 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
// Create initial bind group
WGPUBindGroup bind_group = nullptr;
- pp_update_bind_group(fixture.device(), pipeline, &bind_group, view1, uniforms,
- dummy_effect_params_buffer);
+ pp_update_bind_group(fixture.device(), pipeline, &bind_group, texture1.view,
+ uniforms, dummy_effect_params_buffer);
assert(bind_group != nullptr && "Initial bind group should be created");
fprintf(stdout, " ✓ Initial bind group created\n");
// Update bind group (should release old and create new)
- pp_update_bind_group(fixture.device(), pipeline, &bind_group, view2, uniforms,
- dummy_effect_params_buffer);
+ pp_update_bind_group(fixture.device(), pipeline, &bind_group, texture2.view,
+ uniforms, dummy_effect_params_buffer);
assert(bind_group != nullptr && "Updated bind group should be created");
fprintf(stdout, " ✓ Bind group updated successfully\n");
// Cleanup
wgpuBindGroupRelease(bind_group);
- wgpuTextureViewRelease(view1);
- wgpuTextureRelease(texture1);
- wgpuTextureViewRelease(view2);
- wgpuTextureRelease(texture2);
- wgpuBufferRelease(uniform_buffer);
- wgpuBufferRelease(dummy_params_buffer_handle);
+ wgpuTextureViewRelease(texture1.view);
+ wgpuTextureRelease(texture1.texture);
+ wgpuTextureViewRelease(texture2.view);
+ wgpuTextureRelease(texture2.texture);
+ wgpuBufferRelease(uniforms.buffer);
+ wgpuBufferRelease(dummy_effect_params_buffer.buffer);
wgpuRenderPipelineRelease(pipeline);
fprintf(stdout, " ✓ Resources released\n");
}
@@ -189,31 +150,23 @@ static void test_full_setup(WebGPUTestFixture& fixture) {
assert(pipeline != nullptr && "Pipeline creation failed");
// Create input texture (with TEXTURE_BINDING usage)
- WGPUTexture input_texture =
- create_post_process_texture(fixture.device(), 256, 256, fixture.format());
- WGPUTextureView input_view =
- create_texture_view(input_texture, fixture.format());
+ TextureWithView input =
+ gpu_create_post_process_texture(fixture.device(), 256, 256, fixture.format());
// Create output texture (can use OffscreenRenderTarget for this)
OffscreenRenderTarget output_target(fixture.instance(), fixture.device(), 256,
256);
- const WGPUBufferDescriptor uniform_desc = {
- .usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst,
- .size = 16,
- };
- WGPUBuffer uniform_buffer =
- wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc);
- GpuBuffer uniforms = {uniform_buffer, 16};
+ GpuBuffer uniforms = gpu_create_buffer(
+ fixture.device(), 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
// Dummy effect params buffer for testing (matches vec4<f32>)
- WGPUBuffer dummy_params_buffer_handle =
- wgpuDeviceCreateBuffer(fixture.device(), &uniform_desc);
- GpuBuffer dummy_effect_params_buffer = {dummy_params_buffer_handle, 16};
+ GpuBuffer dummy_effect_params_buffer = gpu_create_buffer(
+ fixture.device(), 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
// Create bind group
WGPUBindGroup bind_group = nullptr;
- pp_update_bind_group(fixture.device(), pipeline, &bind_group, input_view,
+ pp_update_bind_group(fixture.device(), pipeline, &bind_group, input.view,
uniforms, dummy_effect_params_buffer);
assert(bind_group != nullptr && "Bind group creation failed");
@@ -252,10 +205,10 @@ static void test_full_setup(WebGPUTestFixture& fixture) {
wgpuRenderPassEncoderRelease(pass);
wgpuCommandEncoderRelease(encoder);
wgpuBindGroupRelease(bind_group);
- wgpuTextureViewRelease(input_view);
- wgpuTextureRelease(input_texture);
- wgpuBufferRelease(uniform_buffer);
- wgpuBufferRelease(dummy_params_buffer_handle);
+ wgpuTextureViewRelease(input.view);
+ wgpuTextureRelease(input.texture);
+ wgpuBufferRelease(uniforms.buffer);
+ wgpuBufferRelease(dummy_effect_params_buffer.buffer);
wgpuRenderPipelineRelease(pipeline);
fprintf(stdout, " ✓ Full setup test completed\n");