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: BufferPer-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: BufferHolds up to instance_capacity instances; the visible subset
is packed into [0, count) each frame by Self::cull_bin_upload.
instance_capacity: u32§colmul: BufferPer-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: BufferGPU.10.3 — per-tile (offset, count) into tile_instances,
flat 2 * tiles_x * tiles_y u32s. Grown to fit the screen.
tile_instances: BufferGPU.10.3 — flat list of visible-instance indices grouped by tile. Grown to fit the per-frame total.
Implementations§
Source§impl SpriteRegistryResident
impl SpriteRegistryResident
Sourcepub fn upload(
device: &Device,
registry: &SpriteModelRegistry,
instances: &[SpriteInstance],
) -> Self
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.
Sourcepub fn instance_count(&self) -> usize
pub fn instance_count(&self) -> usize
Number of resident instances (the cull set length).
Sourcepub fn append_instances(
&mut self,
device: &Device,
registry: &SpriteModelRegistry,
instances: &[SpriteInstance],
) -> u32
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.
Sourcepub fn remove_instance(&mut self, index: usize) -> Option<usize>
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.
Sourcepub fn set_instance_colmul(&mut self, tables: &[[u64; 256]])
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.
Sourcepub fn update_transforms(&mut self, instances: &[SpriteInstance])
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.
Sourcepub fn update_model(
&mut self,
device: &Device,
queue: &Queue,
registry: &SpriteModelRegistry,
chain_id: u32,
)
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.
Sourcepub fn add_model(
&mut self,
device: &Device,
queue: &Queue,
registry: &SpriteModelRegistry,
chain_id: u32,
)
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.
Sourcepub fn dead_model_count(&self) -> usize
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.
Sourcepub fn live_model_count(&self) -> usize
pub fn live_model_count(&self) -> usize
Number of live (non-removed) models.
Sourcepub fn remove_model(&mut self, chain_id: u32)
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.
Sourcepub fn compact(
&mut self,
device: &Device,
queue: &Queue,
registry: &SpriteModelRegistry,
)
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.
Sourcepub 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)
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).