mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-17 10:59:17 +00:00
ifcviewer: move render() body into ViewportCore (#84-x)
The frame loop — surface acquisition, parallel cull dispatch, streaming drive, two-pass main render, HiZ resolve, edge pass, screenshot capture, FrameStats emission, interactive / bench heartbeat, bench summary + auto-quit — all live in ViewportCore now. ViewportWindow::render() shrinks to the Qt-only prelude: isExposed() guard, fpsIntegrate() (fly-mode WASD step), then core_.render(). The overlay renderer stays Qt-bound (OverlayRenderer.h carries QString labels). Core reaches it via two new ViewportHost virtuals: encodeOverlaysInMainPass (section gizmos, highlights, pivot, lines, points — in-MSAA-pass) and encodeOverlaysPostMain (corner axis, marquee, labels — on the resolved surface). The QtViewportHost implementation in ViewportWindow forwards each to overlays_.X(). FrameStats moves to its own Qt-free header (FrameStats.h) with ViewportWindow::FrameStats re-exported as a using-alias so the bonsai-side signal binding keeps working. ViewportHost::onFrameStats replaces the placeholder 4-double signature with the typed POD. OverlayFrame moves alongside (OverlayFrame.h) so the host overlay callbacks can carry it without dragging Qt into core. Bench + frame-stats + cull-tuning state (min_pixel_radius_, motion_min_pixel_radius_, lod1_pixel_threshold_, cull_threads_enabled_, prev_camera_*, has_prev_camera_, last_cull_was_motion_, last_visible_*, last_cull_*ms_, last_stream_ms_, bench_*, interactive_frame_count_, frame_time_ms_window_/_sum_/_count_/_head_) move to ViewportCore; VW keeps reference aliases so the env-var prelude, setBenchmarkFrames, and the various tool keybind setters keep compiling unchanged. Smoke checks: --screenshot path renders + saves a clean PNG; --benchmark 10 runs the warm gate, prints the per-frame log + summary, and exits cleanly via host_->quit().
This commit is contained in:
@@ -355,6 +355,19 @@ public:
|
||||
void finalizeScreenshotCapture(WGPUBuffer capture_buffer,
|
||||
std::uint32_t padded_bpr);
|
||||
|
||||
// ---- Render loop (#84-x) ----------------------------------------------
|
||||
//
|
||||
// Encode one frame: acquire the swapchain texture, run cull (parallel
|
||||
// when WGPU_CULL_THREADS!=0), drive streaming residency, encode the
|
||||
// two-pass main draw, edge pass, HiZ resolve, and (optionally) the
|
||||
// screenshot capture. Calls host_->encodeOverlaysInMainPass and
|
||||
// host_->encodeOverlaysPostMain for the overlay layers (still
|
||||
// Qt-bound), and host_->onFrameStats for the bench / status bar
|
||||
// listeners. Idempotent re: framebuffer size — reconfigures the
|
||||
// surface on Outdated/Lost. Returns early when the surface query
|
||||
// fails so the next frame retries cleanly.
|
||||
void render();
|
||||
|
||||
// ---- Surface configuration (#84-u) ------------------------------------
|
||||
//
|
||||
// Configure the swapchain at the given physical size. Picks a present
|
||||
@@ -790,6 +803,78 @@ private:
|
||||
std::unordered_map<std::uint32_t, std::unique_ptr<SidecarData>>
|
||||
pending_direct_loads_;
|
||||
|
||||
// ---- Render-loop state (#84-x) ---------------------------------------
|
||||
|
||||
// Contribution-cull thresholds. min_pixel_radius_ is the still-frame
|
||||
// floor; motion_min_pixel_radius_ kicks in during orbit/pan/zoom to
|
||||
// drop more sub-pixel work. lod1_pixel_threshold_ chooses LOD1 over
|
||||
// LOD0 when an instance projects below that radius.
|
||||
float min_pixel_radius_ = 3.0f;
|
||||
float motion_min_pixel_radius_ = 15.0f;
|
||||
float lod1_pixel_threshold_ = 30.0f;
|
||||
// WGPU_CULL_THREADS=0 forces sequential cull (one model after another)
|
||||
// for parallel-vs-serial benchmarking. Default ON.
|
||||
bool cull_threads_enabled_ = true;
|
||||
|
||||
// Per-frame stats latched by render() for FrameStats emission +
|
||||
// the interactive heartbeat / bench per-frame line.
|
||||
std::uint32_t last_visible_objects_ = 0;
|
||||
std::uint32_t last_visible_triangles_ = 0;
|
||||
std::uint32_t last_sub_draws_ = 0;
|
||||
double last_cull_ms_ = 0.0;
|
||||
double last_cull_compute_ms_ = 0.0;
|
||||
double last_cull_upload_ms_ = 0.0;
|
||||
double last_stream_ms_ = 0.0;
|
||||
// True when the cull just used motion_min_pixel_radius_ — render()
|
||||
// schedules one more frame so the camera-now-stopped state recomputes
|
||||
// the cull at the still threshold and previously dropped sub-pixel
|
||||
// instances pop back in.
|
||||
bool last_cull_was_motion_ = false;
|
||||
|
||||
// Previous frame's camera state for the motion-vs-still decision.
|
||||
float prev_camera_target_[3] = { 0, 0, 0 };
|
||||
float prev_camera_distance_ = 0.0f;
|
||||
float prev_camera_yaw_deg_ = 0.0f;
|
||||
float prev_camera_pitch_deg_ = 0.0f;
|
||||
bool has_prev_camera_ = false;
|
||||
|
||||
// Rolling-average FPS readout (60-frame window). frame_time_ms_sum_
|
||||
// tracks the running sum so FrameStats can divide-by-count without
|
||||
// re-summing.
|
||||
static constexpr int FRAME_TIME_WINDOW = 60;
|
||||
double frame_time_ms_window_[FRAME_TIME_WINDOW] = {};
|
||||
int frame_time_ms_count_ = 0;
|
||||
int frame_time_ms_head_ = 0;
|
||||
double frame_time_ms_sum_ = 0.0;
|
||||
|
||||
// Benchmark-mode state. Activated by setBenchmarkFrames(n); render()
|
||||
// orbits the camera at bench_yaw_speed_ deg/frame for bench_total_
|
||||
// frames after a bench_warmup_ settle period, collects per-frame ms,
|
||||
// emits a percentile summary, and calls host_->quit().
|
||||
int bench_total_ = 0;
|
||||
int bench_count_ = 0;
|
||||
int bench_warmup_ = 5;
|
||||
float bench_yaw_start_ = 0.0f;
|
||||
float bench_yaw_speed_ = 0.5f; // degrees per frame
|
||||
std::vector<float> bench_frame_ms_;
|
||||
|
||||
// Cold-load warmup gate counters. The orbit sweep waits until
|
||||
// streaming has converged for CONVERGE_FRAMES_REQUIRED consecutive
|
||||
// frames before starting the sample collection.
|
||||
int bench_warm_streak_ = 0;
|
||||
int bench_warm_frames_total_ = 0;
|
||||
bool bench_warm_done_ = false;
|
||||
|
||||
// Per-frame timing accumulators for the bench summary. Each
|
||||
// accumulator is divided by bench_total_ when the run finishes.
|
||||
double bench_cull_ms_total_ = 0.0;
|
||||
double bench_stream_ms_total_ = 0.0;
|
||||
double bench_hiz_readback_ms_total_ = 0.0;
|
||||
|
||||
// Interactive [frame] heartbeat counter. Used to rate-limit the
|
||||
// stream-health summary + WGPU_STREAM_DEEP_DEBUG dump.
|
||||
int interactive_frame_count_ = 0;
|
||||
|
||||
// Auto-viewAll suppression. Flipped true by the first applyCachedModel
|
||||
// (so a fresh scene frames itself) or by any explicit setCamera (so a
|
||||
// user/bonsai-side camera write isn't overridden by the next model
|
||||
|
||||
Reference in New Issue
Block a user