simvx.graphics.renderer.view_occlusion¶
Per-view two-phase Hi-Z occlusion culling for offscreen views.
Extra views (SubViewport / RenderView) render as scene-render units
(SRUs) through :meth:SceneAdapter.render_to_target, outside the main pass’s
occlusion machinery. Setting use_occlusion=True on the node gives such a
view its own two-phase Hi-Z island: a scratch depth prepass + Hi-Z pyramid
sized to the VIEW’s target, its own cull compute pass, indirect batches, and
visibility ping-pong buffers, driven by the exact
Renderer._two_phase_occlusion sequence the main pass uses. During the
recording the renderer’s occlusion attributes are swapped to this bundle (the
same save / swap / restore isolation render_to_target applies to the
submission lists), so the main pass’s own occlusion state is untouched and the
default (flag-off) frame is byte-identical.
Scope (documented deviations, both engine decisions):
Desktop only. The web renderer’s Hi-Z cull is single-phase (tracked as “Web two-phase Hi-Z occlusion”) and has no per-view hook yet; the flag is a no-op on web.
Pipelined render mode defers per-view occlusion exactly like reflection-probe capture (
render_packet.py, “State intentionally NOT snapshotted”): the view renders un-culled and the owning manager logs a one-time warning. Immediate (synchronous) mode is the supported path.
Module Contents¶
Classes¶
One offscreen view’s private two-phase Hi-Z occlusion state. |
Functions¶
Return (creating on demand) the node’s occlusion bundle, or None. |
Data¶
API¶
- simvx.graphics.renderer.view_occlusion.log¶
‘getLogger(…)’
- simvx.graphics.renderer.view_occlusion.__all__¶
[‘ViewOcclusion’, ‘view_occlusion_for’]
- class simvx.graphics.renderer.view_occlusion.ViewOcclusion(engine: Any)¶
One offscreen view’s private two-phase Hi-Z occlusion state.
Owns the view-sized scratch :class:
~.depth_prepass.DepthPrepass+- Class:
~.hiz_pass.HiZPasspair (created eagerly, the sizes differ from the main pass’s) and harvests the size-agnostic pieces (cull compute pass, indirect batches, visibility ping-pong buffers) from the renderer’s own lazy_ensure_*helpers on the first recorded frame. Recreated whole when the view’s target size or the renderer’s instance capacity changes (both rare: resizes are debounced, capacity growth happens at a frame boundary after a device-idle reallocation).
Initialization
- record(cmd: Any, renderer: Any, width: int, height: int) None¶
Record this view’s two-phase occlusion cull into
cmd.Must run while the SRU’s state is bound (instances / viewport / slice base installed by
render_to_target) and OUTSIDE any render pass (compute is illegal inside one), i.e. between the SRU’s transform upload andtarget.begin_pass. Leaves the scene renderer’s per-frame occlusion plans pointing at THIS view’s culled batches so the SRU’srender_scene_contentconsumes them; :meth:finishmust be called after the SRU render to restore the main pass’s plan state.
- finish(renderer: Any) None¶
Restore the main pass’s plan state after the SRU render consumed ours.
- read_drawn(*, wait: bool = False) int¶
Sum
instance_countover this view’s culled indirect commands.Mirrors
SceneContentRenderer.read_occlusion_telemetryfor the view’s own batches. Passwait=True(test / end-of-run use) tovkDeviceWaitIdlefirst so the phase-2 dispatch has executed.
- destroy() None¶
Release all GPU resources (view reaped, resized, or app shutdown).
- simvx.graphics.renderer.view_occlusion.view_occlusion_for(store: dict[int, simvx.graphics.renderer.view_occlusion.ViewOcclusion], node: Any, engine: Any) simvx.graphics.renderer.view_occlusion.ViewOcclusion | None¶
Return (creating on demand) the node’s occlusion bundle, or None.
The one gate both offscreen-view managers use: with
use_occlusionFalse (the default) this is a singlegetattrplus, at most, the destruction of a bundle whose flag was just toggled off, so the common path stays zero-cost.storeis the manager’sid(node) -> bundledict; reaping on node exit stays the manager’s responsibility.