ifcviewer (GL minimal): --screenshot for parity diff with wgpu

Closes the other half of task #10. The wgpu minimal already wrote PNGs
via wgpuCommandEncoderCopyTextureToBuffer + mapAsync; the GL backend
now has the equivalent via glReadPixels on the back buffer just before
swapBuffers.

  - ViewportWindow::captureNextFrameToPng(path, quit_after=true) queues
    a one-shot capture. render() reads the default framebuffer at full
    pixel size (width * devicePixelRatio), flips bottom-up → top-down
    into a QImage::Format_RGBA8888, saves PNG, and optionally
    QCoreApplication::quit. Synchronous glReadPixels is fine here —
    pick is interactive and rare; not used per-frame.

  - ifcviewer-minimal --screenshot PATH wires through MinimalWindow
    just like --camera / --benchmark. Honoured after all loads complete
    (applyPendingBenchmark also drains pending_screenshot_).

Lets a parity script do:
    IfcViewerMinimal      foo.ifc      --camera A,B,C,D,E,F --screenshot gl.png
    IfcViewerWgpuMinimal  foo.ifcview  --camera A,B,C,D,E,F --screenshot wgpu.png
    # then pixel-diff with whatever (ImageMagick, PIL, etc.)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-05-27 20:33:20 +10:00
parent 4dfe27e251
commit 5810894eb8
5 changed files with 75 additions and 1 deletions
+12
View File
@@ -399,6 +399,14 @@ public:
void setCamera(float tx, float ty, float tz, float dist, float yaw, float pitch);
void setBenchmarkFrames(int n);
// Queue a one-shot framebuffer capture: at the end of the next render()
// (just before swapBuffers), the default framebuffer is read back with
// glReadPixels, saved as PNG to `path`, and — if `quit_after` — the
// QCoreApplication is asked to quit. Used by parity-diff harnesses to
// produce a GL output PNG that's directly comparable to the wgpu
// backend's --screenshot.
void captureNextFrameToPng(const QString& path, bool quit_after = true);
QString cameraString() const;
// Move camera_target_ to the selected set's world-AABB centroid and
@@ -716,6 +724,10 @@ private:
float benchmark_yaw_speed_ = 0.5f; // degrees per frame
std::vector<float> benchmark_frame_times_;
// Queued one-shot framebuffer capture (see captureNextFrameToPng).
QString pending_screenshot_path_;
bool pending_screenshot_quit_ = false;
// Per-frame stats
uint32_t visible_triangles_ = 0;
uint32_t visible_objects_ = 0;