Skip to main content

SpriteRegistryResident

Struct SpriteRegistryResident 

Source
pub struct SpriteRegistryResident {
    pub occupancy: Buffer,
    pub colors: Buffer,
    pub dirs: Buffer,
    pub color_offsets: Buffer,
    pub model_meta: Buffer,
    pub instances: Buffer,
    pub instance_capacity: u32,
    pub colmul: Buffer,
    pub tile_ranges: Buffer,
    pub tile_instances: Buffer,
    /* private fields */
}
Expand description

GPU-resident registry + instances: every model’s occupancy / colours / offsets concatenated into shared storage buffers, a per-model metadata table, and a capacity-sized instance buffer rewritten each frame with the frustum-visible subset (GPU.10.2). One bind group serves all models (same approach as the multi-grid scene).

Fields§

§occupancy: Buffer§colors: Buffer§dirs: Buffer

Per-voxel surface-normal index, concatenated across models in the same layout as colors. The shader indexes the per-instance kv6colmul table by it.

§color_offsets: Buffer§model_meta: Buffer§instances: Buffer

Holds up to instance_capacity instances; the visible subset is packed into [0, count) each frame by Self::cull_bin_upload.

§instance_capacity: u32§colmul: Buffer

Per-visible-instance kv6colmul[256] tables, packed in the same order as the instances buffer each frame (two u32 per u64 entry: lanes 0|1 then 2|3). Sized instance_capacity * 256 * 2 u32; rewritten by Self::cull_bin_upload.

§tile_ranges: Buffer

GPU.10.3 — per-tile (offset, count) into tile_instances, flat 2 * tiles_x * tiles_y u32s. Grown to fit the screen.

§tile_instances: Buffer

GPU.10.3 — flat list of visible-instance indices grouped by tile. Grown to fit the per-frame total.

Implementations§

Source§

impl SpriteRegistryResident

Source

pub fn upload( device: &Device, registry: &SpriteModelRegistry, instances: &[SpriteInstance], ) -> Self

Concatenate registry’s models into shared buffers and prepare instances for per-frame culling. Model-relative indices stay as built; the shader adds each model’s base offset from the metadata table.

Source

pub fn instance_count(&self) -> usize

Number of resident instances (the cull set length).

Source

pub fn append_instances( &mut self, device: &Device, registry: &SpriteModelRegistry, instances: &[SpriteInstance], ) -> u32

Append new instances without re-uploading any model volume — the incremental counterpart to Self::upload, for streaming spawns (asteroids, projectiles, …). Returns the index of the first appended instance; the block occupies [base, base + N).

The model volumes are untouched, so every appended instance must reference a model_id (LOD chain) that was already present in the registry passed to Self::upload. Registering a new model still requires a full Self::upload (its voxels must be laid into the shared buffers). registry here is only read for the new instances’ bound-sphere radii and must be the resident one.

The instances GPU buffer is only grown here (power-of-two, amortised O(1)); its contents are not written. [Self:: cull_bin_upload] rewrites the whole visible range from cull every frame before the sprite pass reads it — exactly as for the static instances — so appending only needs to extend cull and ensure capacity. Writing the buffer here too caused a mid-frame write-while-in-flight hazard on some drivers (a stray full-screen flash on append). colmul likewise grows lazily in cull_bin_upload. After a removal the capacity is not shrunk.

Source

pub fn remove_instance(&mut self, index: usize) -> Option<usize>

Remove the instance at index by swap-remove — O(1), no GPU work (the next Self::cull_bin_upload repacks the visible set from the shrunk cull list). Capacity is retained for reuse.

Returns Some(old_last) when a different instance was moved into index to fill the hole (its index changed from old_last to index — callers holding instance handles must fix up that one), or None if index was the last element or out of range. Because this reorders, any Self::set_instance_colmul table set by position should be re-applied after a removal.

Source

pub fn set_instance_colmul(&mut self, tables: &[[u64; 256]])

Set the per-instance kv6colmul[256] lighting tables (voxlap’s update_reflects output), in the same order/length as the instances passed to Self::upload. The next Self::cull_bin_upload packs the visible subset to the GPU. Instances beyond tables.len() keep their previous tables.

Source

pub fn update_transforms(&mut self, instances: &[SpriteInstance])

Refresh instance poses in place from instances — for animated sprites (e.g. KFA limbs re-posed each frame) — without any model-volume re-upload. instances must match the set passed to Self::upload in length + order; each keeps its model_id (LOD chain) so only the transform + cull centre change. No GPU write happens here: the next Self::cull_bin_upload re-uploads the packed visible subset, as it already does every frame.

Source

pub fn update_model( &mut self, device: &Device, queue: &Queue, registry: &SpriteModelRegistry, chain_id: u32, )

GPU.12 incremental — re-upload only the entries of LOD chain chain_id after an in-place edit (carve / recolour) of its model, without rebuilding the whole registry. registry must be the same registry uploaded (same entry ids), with chain chain_id’s entries already edited (model_mut + rebuild_lod).

For each entry: occupancy + color_offsets are dims-fixed, so they are written in place; colors + dirs (variable, parallel) go through the suballocator — written in place when they fit the slack, relocated (with a model_meta rewrite) when they outgrow it, and only when the buffer tail overflows are colors/dirs grown + the whole registry repacked. Instances / cull / colmul are untouched (a carve never moves an instance or grows its bounds) — that is the win over Self::upload.

§Panics (debug)

If an entry’s dims changed (occupancy / color_offsets length), which the in-place path can’t absorb — growing dims needs a full re-upload via Self::upload.

Source

pub fn add_model( &mut self, device: &Device, queue: &Queue, registry: &SpriteModelRegistry, chain_id: u32, )

Append a new model (its full LOD chain) to the resident registry without re-uploading the existing models’ volumes — the incremental counterpart to a full Self::upload, for streaming in new geometry (unique asteroids, generated meshes).

Contract (mirrors Self::update_model): the caller owns the SpriteModelRegistry, has just appended this chain to it (e.g. via SpriteModelRegistry::add_lod), and passes the resulting chain_id. The chain’s entries must be the registry’s newest (ids >= the resident entry count) — entries are append-only.

The large colors/dirs/occupancy/color_offsets buffers carry slack and bump-append the new entries in place; a buffer that overflows is grown (with slack) and rebuilt once from the registry (amortised O(1) per add). The small model_meta table is rewritten each call. After this, Self::append_instances can reference the new chain_id.

Source

pub fn dead_model_count(&self) -> usize

Number of removed-but-not-yet-compacted models (tombstoned chains). A caller streams add_model / remove_model and calls Self::compact once this (relative to Self::live_model_count) crosses a threshold.

Source

pub fn live_model_count(&self) -> usize

Number of live (non-removed) models.

Source

pub fn remove_model(&mut self, chain_id: u32)

Remove a model (tombstone its LOD chain) — the counterpart to Self::add_model. O(chain length): marks the chain’s entries dead and frees their colors/dirs slots for reuse by a later add_model. The occupancy / color_offsets holes are not reclaimed until Self::compact; entry ids (and the caller’s other chain_ids) stay stable.

Instances of the removed chain are not dropped here — they linger in the cull set but draw as nothing (skipped in Self::cull_bin_upload); the caller removes them via Self::remove_instance when convenient. A no-op if chain_id is out of range or already removed.

Source

pub fn compact( &mut self, device: &Device, queue: &Queue, registry: &SpriteModelRegistry, )

Reclaim the holes left by Self::remove_model: rebuild the shared volume buffers from the live entries only, dropping every dead entry’s data. Entry ids and chain_ids are preserved (dead entries keep a zero-length meta tombstone), so the caller’s handles stay valid and no remap is needed.

registry must be the resident one (entry ids 1:1, as for Self::add_model / Self::update_model). O(live volume) — call it when Self::dead_model_count is high, not every frame.

Source

pub fn cull_bin_upload( &mut self, device: &Device, queue: &Queue, f: &ViewFrustum, screen_w: u32, screen_h: u32, tile_size: u32, lod_px: f32, ) -> (u32, u32, u32)

GPU.10.3 — frustum-cull, pack the visible subset into the instance buffer, then bin those instances into screen tiles: project each visible bounding sphere to a screen AABB and append its (visible) index to every overlapped tile. Uploads the instance buffer + tile_ranges (per-tile offset/count) + tile_instances (flat grouped indices), growing the tile buffers as needed. Returns (visible_count, tiles_x, tiles_y).

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,