summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-11 07:48:56 +0100
committerskal <pascal.massimino@gmail.com>2026-02-11 07:48:56 +0100
commit6d64674f7e3d00a9d18ec61eaf968ed37c8e849b (patch)
tree4fcffcc28b866daa61543f48a8c3e76fed982951 /tools
parentbadf6907dd071afa7a5438fdf575d73c4c417e3f (diff)
fix: CNN test tool GPU readback with wgpuDevicePoll
Fixed buffer mapping callback mode mismatch causing Unknown status. Changed from WaitAnyOnly+ProcessEvents to AllowProcessEvents+DevicePoll. Readback now functional but CNN output incorrect (all white). Issue isolated to tool-specific binding/uniform setup - CNNEffect in demo works correctly. Technical details: - WGPUCallbackMode_WaitAnyOnly requires wgpuInstanceWaitAny - Using wgpuInstanceProcessEvents with WaitAnyOnly never fires callback - Fixed by using AllowProcessEvents mode + wgpuDevicePoll - Removed debug output and platform warnings Status: 36/36 tests pass, readback works, CNN shader issue remains. handoff(Claude): CNN test tool readback fixed, output debugging needed
Diffstat (limited to 'tools')
-rw-r--r--tools/cnn_test.cc175
1 files changed, 83 insertions, 92 deletions
diff --git a/tools/cnn_test.cc b/tools/cnn_test.cc
index c44606c..62a60f4 100644
--- a/tools/cnn_test.cc
+++ b/tools/cnn_test.cc
@@ -352,26 +352,6 @@ int main(int argc, char** argv) {
wgpuTextureCreateView(intermediate_textures[1], &intermediate_view_desc),
};
- // Create final output texture (BGRA8Unorm for readback)
- const WGPUTextureDescriptor final_desc = {
- .usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_CopySrc,
- .dimension = WGPUTextureDimension_2D,
- .size = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1},
- .format = WGPUTextureFormat_BGRA8Unorm,
- .mipLevelCount = 1,
- .sampleCount = 1,
- };
- WGPUTexture final_output_texture = wgpuDeviceCreateTexture(device, &final_desc);
- const WGPUTextureViewDescriptor final_view_desc = {
- .format = WGPUTextureFormat_BGRA8Unorm,
- .dimension = WGPUTextureViewDimension_2D,
- .baseMipLevel = 0,
- .mipLevelCount = 1,
- .baseArrayLayer = 0,
- .arrayLayerCount = 1,
- };
- WGPUTextureView final_output_view = wgpuTextureCreateView(final_output_texture, &final_view_desc);
-
// Get sampler
WGPUSampler sampler =
SamplerCache::Get().get_or_create(device, SamplerCache::clamp());
@@ -420,25 +400,92 @@ int main(int argc, char** argv) {
// Render to appropriate output texture with correct pipeline
bool is_final = (layer == NUM_LAYERS - 1);
- WGPUTextureView output_view = is_final ? final_output_view : intermediate_views[dst_idx];
- WGPURenderPipeline current_pipeline = is_final ? pipeline_final : pipeline_intermediate;
- WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
- WGPURenderPassEncoder pass = begin_render_pass(encoder, output_view);
- wgpuRenderPassEncoderSetPipeline(pass, current_pipeline);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); // Fullscreen triangle
- wgpuRenderPassEncoderEnd(pass);
- WGPUCommandBuffer commands = wgpuCommandEncoderFinish(encoder, nullptr);
- wgpuQueueSubmit(queue, 1, &commands);
+ if (is_final) {
+ // Final layer: use OffscreenRenderTarget (known working readback)
+ OffscreenRenderTarget rt(instance, device, width, height);
+ WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
+ WGPURenderPassEncoder pass = begin_render_pass(encoder, rt.view());
+ wgpuRenderPassEncoderSetPipeline(pass, pipeline_final);
+ wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr);
+ wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
+ wgpuRenderPassEncoderEnd(pass);
+ WGPUCommandBuffer commands = wgpuCommandEncoderFinish(encoder, nullptr);
+ wgpuQueueSubmit(queue, 1, &commands);
+ wgpuDevicePoll(device, true, nullptr);
+
+ wgpuCommandBufferRelease(commands);
+ wgpuRenderPassEncoderRelease(pass);
+ wgpuCommandEncoderRelease(encoder);
+ wgpuBindGroupRelease(bind_group);
+
+ // Read pixels immediately
+ printf("Reading pixels from GPU...\n");
+ std::vector<uint8_t> pixels = rt.read_pixels();
+
+ if (pixels.empty()) {
+ fprintf(stderr, "Error: GPU readback failed\n");
+ wgpuTextureViewRelease(intermediate_views[0]);
+ wgpuTextureViewRelease(intermediate_views[1]);
+ wgpuTextureRelease(intermediate_textures[0]);
+ wgpuTextureRelease(intermediate_textures[1]);
+ wgpuTextureViewRelease(input_view);
+ wgpuTextureRelease(input_texture);
+ wgpuBufferRelease(layer_params_buffer);
+ wgpuBufferRelease(common_uniform_buffer);
+ wgpuBindGroupLayoutRelease(bgl);
+ wgpuRenderPipelineRelease(pipeline_final);
+ wgpuRenderPipelineRelease(pipeline_intermediate);
+ fixture.shutdown();
+ return 1;
+ }
+
+ // Save output
+ bool success;
+ if (args.output_png) {
+ printf("Saving PNG to '%s'...\n", args.output_path);
+ success = save_png(args.output_path, pixels, width, height);
+ } else {
+ printf("Saving PPM to '%s'...\n", args.output_path);
+ success = save_ppm(args.output_path, pixels, width, height);
+ }
+
+ if (!success) {
+ wgpuTextureViewRelease(intermediate_views[0]);
+ wgpuTextureViewRelease(intermediate_views[1]);
+ wgpuTextureRelease(intermediate_textures[0]);
+ wgpuTextureRelease(intermediate_textures[1]);
+ wgpuTextureViewRelease(input_view);
+ wgpuTextureRelease(input_texture);
+ wgpuBufferRelease(layer_params_buffer);
+ wgpuBufferRelease(common_uniform_buffer);
+ wgpuBindGroupLayoutRelease(bgl);
+ wgpuRenderPipelineRelease(pipeline_final);
+ wgpuRenderPipelineRelease(pipeline_intermediate);
+ fixture.shutdown();
+ return 1;
+ }
- // Wait for GPU to complete this layer before proceeding
- wgpuDevicePoll(device, true, nullptr);
+ printf("Done! Output saved to '%s'\n", args.output_path);
+ 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);
+ WGPURenderPassEncoder pass = begin_render_pass(encoder, output_view);
+ wgpuRenderPassEncoderSetPipeline(pass, pipeline_intermediate);
+ wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group, 0, nullptr);
+ wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
+ wgpuRenderPassEncoderEnd(pass);
+ WGPUCommandBuffer commands = wgpuCommandEncoderFinish(encoder, nullptr);
+ wgpuQueueSubmit(queue, 1, &commands);
+ wgpuDevicePoll(device, true, nullptr);
- wgpuCommandBufferRelease(commands);
- wgpuRenderPassEncoderRelease(pass);
- wgpuCommandEncoderRelease(encoder);
- wgpuBindGroupRelease(bind_group);
+ wgpuCommandBufferRelease(commands);
+ wgpuRenderPassEncoderRelease(pass);
+ wgpuCommandEncoderRelease(encoder);
+ wgpuBindGroupRelease(bind_group);
+ }
// Update for next layer: output becomes input
if (layer < NUM_LAYERS - 1) {
@@ -448,62 +495,6 @@ int main(int argc, char** argv) {
}
}
- printf("Reading pixels from GPU...\n");
-
- // Read final output from GPU (always BGRA8Unorm)
- std::vector<uint8_t> pixels =
- read_texture_pixels(instance, device, final_output_texture, width, height);
-
- if (pixels.empty()) {
- fprintf(stderr, "Error: failed to read pixels from GPU\n");
- // Cleanup...
- wgpuTextureViewRelease(final_output_view);
- wgpuTextureRelease(final_output_texture);
- wgpuTextureViewRelease(intermediate_views[0]);
- wgpuTextureViewRelease(intermediate_views[1]);
- wgpuTextureRelease(intermediate_textures[0]);
- wgpuTextureRelease(intermediate_textures[1]);
- wgpuBufferRelease(layer_params_buffer);
- wgpuBufferRelease(common_uniform_buffer);
- wgpuBindGroupLayoutRelease(bgl);
- wgpuRenderPipelineRelease(pipeline_intermediate);
- wgpuRenderPipelineRelease(pipeline_final);
- wgpuTextureViewRelease(input_view);
- wgpuTextureRelease(input_texture);
- fixture.shutdown();
- return 1;
- }
-
- // Save output
- bool success = false;
- if (args.output_png) {
- printf("Saving PNG to '%s'...\n", args.output_path);
- success = save_png(args.output_path, pixels, width, height);
- } else {
- printf("Saving PPM to '%s'...\n", args.output_path);
- success = save_ppm(args.output_path, pixels, width, height);
- }
-
- if (!success) {
- wgpuTextureViewRelease(final_output_view);
- wgpuTextureRelease(final_output_texture);
- wgpuTextureViewRelease(intermediate_views[0]);
- wgpuTextureViewRelease(intermediate_views[1]);
- wgpuTextureRelease(intermediate_textures[0]);
- wgpuTextureRelease(intermediate_textures[1]);
- wgpuBufferRelease(layer_params_buffer);
- wgpuBufferRelease(common_uniform_buffer);
- wgpuBindGroupLayoutRelease(bgl);
- wgpuRenderPipelineRelease(pipeline_intermediate);
- wgpuRenderPipelineRelease(pipeline_final);
- wgpuTextureViewRelease(input_view);
- wgpuTextureRelease(input_texture);
- fixture.shutdown();
- return 1;
- }
-
- printf("Done! Output saved to '%s'\n", args.output_path);
-
// Cleanup
wgpuTextureViewRelease(intermediate_views[0]);
wgpuTextureViewRelease(intermediate_views[1]);