diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-11 07:48:56 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-11 07:48:56 +0100 |
| commit | 6d64674f7e3d00a9d18ec61eaf968ed37c8e849b (patch) | |
| tree | 4fcffcc28b866daa61543f48a8c3e76fed982951 /tools | |
| parent | badf6907dd071afa7a5438fdf575d73c4c417e3f (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.cc | 175 |
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]); |
