mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 12:18:02 +00:00
wgpu: streaming + HiZ correctness fixes
Three correctness bugs found and fixed, plus an unrelated fly-mode deadlock surfaced along the way. HiZ false-rejection at the bottom of the screen ------------------------------------------------ The mip-pyramid sizing floored when halving — for a 256×70 mip 0 the level-3 mip is 32×8, but mip-0 row 69 maps to ly = 69>>3 = 8, which is out of bounds for an 8-row mip. ly1 then clamps down to 7 while ly0 stays at 8, the sampling loop runs zero times, max_d retains its initial 0.0, and `min_z > 0` rejects every AABB whose projected y range touches the bottom row. Same class for the right edge on very wide viewports. Fix: ceil rather than floor when halving mip dimensions so every parent row has a covering child texel, plus std::clamp on both lookup endpoints as belt-and-suspenders for any future mip-sizing change. Surfaced after the user added more sidecars and saw "anything near the bottom of the screen, no matter close or far" disappear ~0.5 s after camera stops — that delay was the strict-VP gate + readback latency opening the HiZ window. Found via WGPU_HIZ_TRACE rejection logs that showed every rejection had `max_d=0` and `ly0 > ly1`. Streaming priority lets the ocean starve out the bracing --------------------------------------------------------- Per-instance projected screen footprint was estimated as bounding- sphere radius squared. BIM geometry is overwhelmingly thin-in-one-axis (slabs, pipes, columns, windows) and a flat ocean plane viewed nearly edge-on gets a sphere projection ~250× larger than its actual screen rect. Its chunk dominated the priority ranking and evicted the brace chunks despite the braces being one of the closest visible things. Fix: per-instance priority is now the screen-space AABB rectangle area (world AABB extents projected onto the camera right/up basis vectors, divided by view-z). Sphere radius is retained for the contribution cull and LOD pick because conservative-over is the right failure mode there. Stale-VP HiZ gate ----------------- HiZ resolves into an async ping-pong of staging buffers, so the pyramid resident at cull time was typically captured one or two frames ago. During camera motion the captured VP differs from vp_this_frame and AABBs end up sampling depth taken for what was at slightly-different screen positions in the old view. Strict by default now: HiZ engages only when hiz_vp_ == vp_this_frame. WGPU_HIZ_MOTION=1 trusts the stale pyramid (matches GL's default). Fly mode Shift+Q deadlock -------------------------- keyPressEvent requested a redraw only on the first key of a new held set (was_empty). Pressing Shift first then Q never satisfied that condition because Shift had already populated the set, so the render loop never ticked. Now every relevant keypress calls requestUpdate unconditionally. HiZ stays opt-in behind WGPU_HIZ=1 for one release while the fix bakes; WGPU_HIZ_TRACE=1 keeps the per-rejection diagnostic available for future bugs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <webgpu/webgpu.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
@@ -294,9 +295,19 @@ private:
|
||||
// vertices. Touches no wgpu state, so this can run on a worker thread
|
||||
// (multiple models culled in parallel). Returns the number of HiZ
|
||||
// rejections accumulated (caller adds to the per-frame stat).
|
||||
// right/up are world-space camera basis vectors (orthonormal with
|
||||
// forward). Used by the streaming priority accumulator to project
|
||||
// each instance's world AABB to a screen-space rectangle — far
|
||||
// tighter than a bounding-sphere projection for BIM geometry, which
|
||||
// is overwhelmingly thin-in-one-axis (pipes, columns, slabs,
|
||||
// windows). Sphere projection is kept for contribution / LOD picks
|
||||
// because conservative-over is the right failure mode there.
|
||||
uint32_t cullModelCpuCompute(WgpuModelGpuData& m,
|
||||
const float planes[6][4],
|
||||
const float eye[3], const float forward[3],
|
||||
const float eye[3],
|
||||
const float forward[3],
|
||||
const float right[3],
|
||||
const float up[3],
|
||||
float focal_px,
|
||||
float min_radius_px,
|
||||
float lod1_threshold_px,
|
||||
@@ -432,6 +443,13 @@ private:
|
||||
bool hiz_valid_ = false;
|
||||
uint32_t hiz_reject_count_ = 0; // per-frame stat
|
||||
|
||||
// WGPU_HIZ_TRACE=1 — diagnostic logging budget shared across the
|
||||
// parallel cull threads. Set to a non-zero count at start of cull
|
||||
// when tracing is on; each rejection in aabbOccludedByHiz atomically
|
||||
// decrements and logs while >0. Atomic because cull dispatches one
|
||||
// thread per model.
|
||||
mutable std::atomic<int> hiz_trace_budget_{0};
|
||||
|
||||
QColor background_color_ = QColor("#202329");
|
||||
|
||||
// Camera (orbit, right-handed Y-up world → wait, BIM is +Z up).
|
||||
@@ -533,9 +551,17 @@ private:
|
||||
uint32_t spatial_max_instances_ = 5000;
|
||||
|
||||
public:
|
||||
// Master switch for HiZ occlusion. Set false to skip the depth resolve
|
||||
// + readback + cull test entirely (matches IFC_NO_HIZ in the GL backend).
|
||||
bool hiz_enabled_ = true;
|
||||
// Master switch for HiZ occlusion. OFF by default — has two issues vs
|
||||
// the GL backend on this codepath (see task #58):
|
||||
// (1) Correctness: bottom-edge AABBs get falsely rejected as the
|
||||
// camera rotates. Math review didn't pin it down; root cause
|
||||
// likely needs RenderDoc capture of the pyramid.
|
||||
// (2) Perf: HiZ ON costs ~2.5 ms more cull time than HiZ OFF on
|
||||
// the federation bench but only saves ~1 ms of raster work
|
||||
// because our indirect-draw iterates the visible_draws buffer
|
||||
// regardless. Net 9% slower (49.7 vs 54.2 fps).
|
||||
// Opt-in via WGPU_HIZ=1.
|
||||
bool hiz_enabled_ = false;
|
||||
|
||||
// When true, initWgpu requests the WebGPU mandatory floor limits
|
||||
// (maxStorageBufferBindingSize=128MB, maxBufferSize=256MB) instead of
|
||||
|
||||
Reference in New Issue
Block a user