simvx.graphics.renderer.buffer_manager

BufferManager: owns the forward renderer’s SSBOs and descriptor sets.

Extracted from Renderer so transform/material/light/shadow/joint buffers and the Forward+ tile-culling placeholders live in one place. The descriptor set layout and cubemap placeholder are owned here too so the renderer can swap the IBL cubemap in via write_cubemap_descriptor.

Module Contents

Classes

BufferManager

Owns the renderer’s SSBOs and descriptor sets.

Data

API

simvx.graphics.renderer.buffer_manager.__all__

[‘BufferManager’, ‘SHADOW_DATA_SIZE’]

simvx.graphics.renderer.buffer_manager.log

‘getLogger(…)’

simvx.graphics.renderer.buffer_manager.SHADOW_DATA_SIZE

384

simvx.graphics.renderer.buffer_manager.MAX_PROBES

8

simvx.graphics.renderer.buffer_manager.PROBE_BUFFER_SIZE

None

simvx.graphics.renderer.buffer_manager.IRRADIANCE_VOLUME_HEADER_SIZE

64

simvx.graphics.renderer.buffer_manager.IRRADIANCE_VOLUME_MAX_PROBES

256

simvx.graphics.renderer.buffer_manager.IRRADIANCE_VOLUME_BUFFER_SIZE

None

class simvx.graphics.renderer.buffer_manager.BufferManager(engine: Any, max_objects: int, max_materials: int = 1024, max_lights: int = 256, max_joints: int = 256)[source]

Owns the renderer’s SSBOs and descriptor sets.

Main descriptor set (ssbo_set) exposes eighteen bindings: 0: transforms, 1: materials, 2: lights, 3: shadow, 4: IBL cubemap sampler, 5: tile light indices, 6: tile info, 7/8/9: IBL irradiance cube / prefilter cube / BRDF 2D LUT, 10/11: reflection-probe irradiance / prefilter cube arrays, 12: reflection-probe box SSBO, 13: FrameGlobals UBO, 14: scene colour copy, 15: scene depth copy (written by the renderer’s :class:SceneCopyTargets), 16/17: indirect specular / diffuse hook textures (1x1 black until an SSR / SSGI producer writes them).

Joint descriptor set (joint_set) is set 2 binding 0 for skinned meshes.

Initialization

property transform_buf: Any[source]
property transform_mem: Any[source]
property aabb_buf: Any[source]
property aabb_mem: Any[source]
property shadow_buf: Any[source]
property shadow_mem: Any[source]
property frame_globals_buf: Any[source]
property frame_globals_mem: Any[source]
property ssbo_set: Any[source]

The current frame’s main SSBO descriptor set (what every pass binds).

property joint_buf: Any[source]
property joint_mem: Any[source]
property joint_set: Any[source]

The current frame’s joint descriptor set (bound for skinned meshes).

setup() None[source]

Allocate all SSBOs and descriptor sets.

property transform_capacity: int[source]

Total transform-SSBO slots available this frame (== max_objects).

begin_frame_arena() None[source]

Reset the per-frame bump cursor. Call once at the start of every frame.

reserve_slots(count: int) int[source]

Reserve a contiguous range of count transform slots; return its base.

Bump-allocates from the shared SSBO arena. On overflow (the running cursor would pass capacity) the request is clamped to what fits, a WARNING is logged once, and a grow to next_pow2(needed) is scheduled for the next frame boundary. The high-water mark is updated either way so a proactive grow can fire before an actual overflow recurs.

Returns the base slot. The caller records draws with first_instance = base + local_index and writes its transforms into the SSBO at byte offset base * TRANSFORM_DTYPE.itemsize.

request_joint_capacity(joint_count: int) int[source]

Reserve room for joint_count bone matrices in the joint SSBO.

Returns the number that fit in the CURRENT buffer (so the caller clamps its upload and never writes past the allocation). When the request exceeds capacity a grow is scheduled for the next frame boundary (mirrors the transform arena), so the dropped skeletons appear one frame later instead of corrupting device memory. Symmetric with the web _ensureBoneBuf.

maybe_grow() bool[source]

Grow the transform/AABB and joint SSBOs if scheduled. Frame-boundary only.

Reallocates when a grow is pending (an overflow clamped this frame) OR the high-water mark has crossed _GROW_THRESHOLD of capacity (proactive). Must run OUTSIDE command recording (begin_frame or post-submit) so the reallocated buffer + descriptor rewrite never race the GPU. Returns True when a grow happened.

write_probe_descriptors(irradiance_array_view: Any, prefilter_array_view: Any, sampler: Any) None[source]

Bind the ReflectionProbePass’s cubemap arrays to the forward set (bindings 10/11).

write_probe_buffer(data: numpy.ndarray) None[source]

Upload the probe box SSBO bytes (count header + Probe array, binding 12).

write_decals(data: numpy.ndarray) None[source]

Upload the decal SSBO bytes (count header + Decal array + tile masks, b19).

data is the block from decal_pack.build_decal_buffer. The base (header + record) region is a fixed :data:DECAL_BUFFER_SIZE; when the screen-tile cull is active the per-tile bitmask array is appended, so the block can exceed the initial allocation. It is grown (and its b19 descriptor repointed) on demand at the frame boundary; the growth only ever adds tile-mask capacity, so it never perturbs the record region. An all-zero block (no decals) leaves decal_count at 0, a byte-identical no-op.

write_irradiance_volume_header(header: numpy.ndarray) None[source]

Upload ONLY the volume SSBO header (64 B: grid + bounds + params, binding 18).

The per-probe SH region that follows is written by the IrradianceVolumePass SH-reduce compute (GPU), so the header upload must never touch it.

write_ibl_descriptors(irradiance_view: Any, prefilter_view: Any, brdf_view: Any, sampler: Any) None[source]

Bind an IBLPass’s precomputed maps to the forward set (bindings 7/8/9).

upload_transforms(instances: list, *, upload_aabbs: bool = False, base: int = 0) numpy.ndarray | None[source]

Upload instance transforms + normal matrices + material ids into the SSBO slice.

Writes into the shared transform SSBO starting at slot base (the slice reserved for this scene-render unit; base == 0 for the main scene). Returns the (N, 4, 4) column-major (GLSL-ready) model matrices so the caller can feed the exact same data to the TAA velocity pass (prev-frame transform plumbing). Returns None when there are no instances.

When upload_aabbs is True (GPU occlusion culling enabled) the per-slot LOCAL AABB SSBO is populated alongside. Off by default so the occlusion-off path performs no extra host upload (byte-identical default behaviour).

upload_transform_block(transforms: numpy.ndarray, base: int, *, material_index: int = 0, material_ids: numpy.ndarray | None = None) numpy.ndarray | None[source]

Vectorized upload of a contiguous instance block (e.g. a MultiMesh).

Unlike :meth:upload_transforms, which iterates a Python list of per- instance tuples, this packs the whole (N, 4, 4) block with no Python loop and writes it at slots [base, base+N). Returns the world-space instance centres (N, 3) (translation columns) so the caller can frustum-cull the block without re-reading the SSBO. Returns None when the block does not fit.

set_materials(materials: numpy.ndarray) numpy.ndarray[source]

Upload material array. Returns the (possibly clamped) array stored.

set_lights(lights: numpy.ndarray) None[source]

Upload light array prefixed with the uint32 count (GLSL LightBuffer layout).

write_shadow_data(shadow_data: numpy.ndarray) None[source]

Upload raw shadow SSBO bytes (used by shadow passes + IBL-only fallback).

write_cubemap_descriptor(view: Any, sampler: Any) None[source]

Bind a cubemap view+sampler to the IBL slot (binding 4).

update_frame_globals(now: float, env: simvx.graphics.frame_globals.FrameGlobalsEnv, internal_extent: tuple[int, int], output_extent: tuple[int, int], render_scale: float = 1.0) None[source]

Repack + upload the per-frame FrameGlobals UBO (binding 13).

delta is derived from the scene clock (now minus the previous call’s now) and frame_index from an internal counter, so the block needs no renderer-wide frame clock. internal_extent is the HDR-chain render extent, output_extent the swapchain extent; they are equal (and render_scale 1.0) on the unscaled path, packing the exact pre-scale block.

cleanup() None[source]

Destroy all buffers, descriptor pools/layouts, and placeholder cubemap.