mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
ifcviewer: GPU cull drives rendering under IFC_GPU_CULL=1
Promote the compute cull from a validation shader to the actual draw driver. With the gate on, the CPU cull fan-out is skipped and MDI consumes gpu_indirect_buffer / gpu_visible_ssbo directly. - uploadGpuCullStaticBuffers() pre-fills per-mesh DrawElementsIndirect commands and a mesh_base prefix sum so the compact shader can scatter survivors into a fixed per-mesh range. Instance count for each command is zeroed by a tiny reset dispatch, then the compact shader atomically writes survivors and increments instanceCount. - Draw loop branches on the gate: single CCW MDI with all mesh commands. Fwd/rev winding split, LOD selection, and HiZ are still CPU-path-only; reflected instances render with wrong winding under this gate (step 3b). - Once-per-second readback of each model's indirect buffer populates the survivor / visible-object / visible-triangle stats so the [frame] line reflects what the GPU actually drew. Known regression: sub_draws is the full mesh count per model (~172k on the test dataset) vs the handful of non-empty commands the CPU path produces. Command-processor overhead from zero-instance sub-draws is what drives the FPS drop, not the cull itself (0.05 ms). Compacting non-empty commands requires glMultiDrawElementsIndirectCount, a GL 4.6 entrypoint not exposed by Qt's QOpenGLFunctions_4_5_Core; deferring to 3a-followup so we don't bolt a getProcAddress loader into the renderer mid-restructure. IFC_GPU_CULL is off by default, so this does not affect normal runs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -102,6 +102,20 @@ struct ModelGpuData {
|
||||
GLuint aabb_ssbo = 0;
|
||||
size_t aabb_ssbo_capacity = 0; // bytes
|
||||
|
||||
// Phase 3E GPU-cull draw buffers. Separate from the CPU path's
|
||||
// visible_ssbo / indirect_buffer so the env-var gate can swap between
|
||||
// them without reallocating. Built once at finalize; each frame only
|
||||
// the instanceCount field of gpu_indirect_buffer is rewritten by the
|
||||
// cull shader (zeroed by the reset shader, atomically incremented as
|
||||
// survivors are appended into gpu_visible_ssbo at mesh_base[i] + local).
|
||||
GLuint gpu_indirect_buffer = 0;
|
||||
size_t gpu_indirect_capacity = 0;
|
||||
GLuint gpu_visible_ssbo = 0;
|
||||
size_t gpu_visible_capacity = 0;
|
||||
GLuint gpu_mesh_base_ssbo = 0;
|
||||
size_t gpu_mesh_base_capacity = 0;
|
||||
uint32_t gpu_mesh_command_count = 0;
|
||||
|
||||
// Dynamic visible-instance index buffer (std430, binding = 1).
|
||||
// Re-uploaded each frame from visible_flat_.
|
||||
GLuint visible_ssbo = 0;
|
||||
@@ -229,6 +243,12 @@ private:
|
||||
// compute cull (Phase 3E, in progress).
|
||||
void uploadInstanceAabbs(ModelGpuData& m);
|
||||
|
||||
// Build the static GPU-cull draw buffers (gpu_indirect_buffer,
|
||||
// gpu_visible_ssbo, gpu_mesh_base_ssbo) from m.meshes + m.instances.
|
||||
// Called after uploadInstanceAabbs at finalize / applyCachedModel once
|
||||
// m.meshes[].instance_count has been populated.
|
||||
void uploadGpuCullStaticBuffers(ModelGpuData& m);
|
||||
|
||||
// Frustum-cull m's instances (BVH if available, else linear scan),
|
||||
// build the per-mesh DrawElementsIndirectCommand array + flat visible
|
||||
// list, and upload both to m.indirect_buffer / m.visible_ssbo.
|
||||
@@ -267,11 +287,16 @@ private:
|
||||
GLuint pick_program_ = 0;
|
||||
GLuint axis_program_ = 0;
|
||||
|
||||
// Phase 3E compute cull (frustum-only, validation). Runs alongside the
|
||||
// CPU cull when IFC_GPU_CULL=1; result is cross-checked against CPU's
|
||||
// visible_objects count. No draw-path side effects yet.
|
||||
GLuint cull_program_ = 0;
|
||||
GLuint gpu_cull_counter_ssbo_ = 0;
|
||||
// Phase 3E compute cull. When IFC_GPU_CULL=1, render() uses the GPU
|
||||
// path exclusively: cull_reset_program_ zeros each mesh's instanceCount
|
||||
// in gpu_indirect_buffer, then cull_compact_program_ runs frustum +
|
||||
// contribution cull per instance and atomically appends survivors into
|
||||
// gpu_visible_ssbo at mesh_base[mesh_id] + local_slot. No LOD / HiZ /
|
||||
// reflection bucketing yet — reflected instances render with wrong
|
||||
// winding under the gate, which is why this stays gated until the
|
||||
// fwd/rev split lands (step 3b).
|
||||
GLuint cull_reset_program_ = 0;
|
||||
GLuint cull_compact_program_ = 0;
|
||||
uint32_t gpu_cull_last_survivors_ = 0;
|
||||
uint32_t gpu_cull_last_input_ = 0;
|
||||
uint64_t gpu_cull_ns_ = 0; // per-window accumulator
|
||||
|
||||
Reference in New Issue
Block a user