pub struct MeshSource {Show 43 fields
pub(crate) context: RenderContext,
metadata_array: Array,
metadata_buf: ResHandle<ArrayHandle>,
joints_array: Array,
joints_buf: ResHandle<ArrayHandle>,
morph_weights_array: Array,
morph_weights_buf: ResHandle<ArrayHandle>,
morph_deltas_pool: ArrayPool,
morph_deltas_buf: ResHandle<ArrayHandle>,
lights_array: Array,
lights_buf: ResHandle<ArrayHandle>,
light_cells_array: Array,
light_cells_buf: ResHandle<ArrayHandle>,
light_vertices_array: Array,
light_vertices_buf: ResHandle<ArrayHandle>,
cluster_buf: ResHandle<Buffer>,
lighting_buf: ResHandle<Buffer>,
pub clustering: ClusterConfig,
packed_lights: Vec<PackedLight>,
light_clusters: LightClusters,
light_vertices: Vec<Vec4>,
light_records: Vec<LightGpu>,
lighting: LightingUniform,
cluster_staging: StagingBuffer,
lighting_staging: StagingBuffer,
morph_deltas_dirty: bool,
metadata: Vec<MeshMetadata>,
free_metadata: Vec<u32>,
metadata_dirty: bool,
packed_joints: Vec<JointMatrix>,
packed_morph_weights: Vec<f32>,
pub(crate) index_pool: BufferPool,
pub(crate) index_pool_id: ResHandle<Buffer>,
pub(crate) vertex_pool: VertexStreamPool,
vertex_pool_ids: HashMap<VertexBufferLayoutDesc, ResHandle<Buffer>>,
pipelines: Vec<RegisteredPipeline>,
families: Vec<Box<dyn AnyFamily>>,
family_ids: TypeIdHashMap<FamilyId>,
visible_meshes_cache: Vec<VisibleMesh>,
visible_cache: Vec<VisibleEntry>,
family_instance_cache: Vec<Option<(u32, Buffer)>>,
pipeline_handle_cache: Vec<RenderPipelineHandles>,
entry_handle_cache: HashMap<DrawHandlesKey, EntryHandles>,
}Expand description
It owns the mesh pools, the pipeline families, the per-frame caches and the
Scene the frame’s draws are assembled into, and it fetches the device,
the queue and the resource graph from the world through the
RenderContext it was created with. Register the families it draws with
— MeshSource::register_lit_family for the built-in lit shader — and
spawn it with Source::new.
Fields§
§context: RenderContextThe world addresses of the frame’s GPU state, kept so every entry point fetches the device, the queue and the graph for itself instead of holding a borrow of them between calls.
metadata_array: ArrayThe mesh-metadata array, held in whichever resource the device reads.
metadata_buf: ResHandle<ArrayHandle>Resource id of the mesh-metadata array.
joints_array: ArrayThe frame’s joint-matrix array, held in whichever resource the device reads.
joints_buf: ResHandle<ArrayHandle>Resource id of the frame’s joint-matrix array.
morph_weights_array: ArrayThe frame’s morph-weight array, held in whichever resource the device reads.
morph_weights_buf: ResHandle<ArrayHandle>Resource id of the frame’s morph-weight array.
morph_deltas_pool: ArrayPoolThe frame’s morph-displacement array, pooling every morphed mesh’s deltas into one resource.
A mesh’s displacements are its own geometry, but one array holds them
for the frame and the mesh names its slice through its metadata entry’s
morph_deltas_offset. That is what leaves the mesh group nothing to
bind.
morph_deltas_buf: ResHandle<ArrayHandle>Resource id of the frame’s morph-displacement array.
lights_array: ArrayThe frame’s lights, held in whichever resource the device reads.
lights_buf: ResHandle<ArrayHandle>Resource id of the frame’s light array.
light_cells_array: ArrayThe frame’s cluster cells, held in whichever resource the device reads.
light_cells_buf: ResHandle<ArrayHandle>Resource id of the frame’s cluster-cell array.
light_vertices_array: ArrayThe frame’s light vertices: the corner pool every quadrilateral light appends to.
light_vertices_buf: ResHandle<ArrayHandle>Resource id of the frame’s light-vertex array.
cluster_buf: ResHandle<Buffer>Resource id of the cluster uniform buffer.
lighting_buf: ResHandle<Buffer>Resource id of the frame-wide lighting uniform buffer.
clustering: ClusterConfigThe cluster grid this frame’s lights are assigned to.
The source clusters every frame a lit pipeline is registered for, since a frame’s camera moves and its lights move with it. Its near and far planes are the clustering’s own: a Camera carries a projection, not the extents that projection was built from.
packed_lights: Vec<PackedLight>Reused per-frame light records, ranked by importance by the clusterer.
light_clusters: LightClustersReused per-frame cluster assignment.
light_vertices: Vec<Vec4>Reused per-frame polygon-vertex pool, which a quadrilateral light appends its corners to.
light_records: Vec<LightGpu>Reused per-frame light records, in the order the clusterer ranked them.
lighting: LightingUniformThe frame-wide lighting uniform, rebuilt and uploaded every lit frame.
cluster_staging: StagingBufferStaging buffer for the cluster uniform, reused across frames.
lighting_staging: StagingBufferStaging buffer for the lighting uniform, reused across frames.
morph_deltas_dirty: boolWhether a mesh’s displacements were written into the pool since the array was last uploaded.
Allocating or removing a mesh marks it; the next build uploads the array then, so the upload always lands in the same encoder as the draws that read it.
metadata: Vec<MeshMetadata>Metadata entries, one per live uploaded mesh.
free_metadata: Vec<u32>Metadata slots whose mesh was removed and whose index is free to hand out again.
metadata_dirty: boolWhether the metadata array changed since it was last uploaded.
Allocating or removing a mesh marks it; the next build uploads the array then, so an upload always lands in the same encoder as the draws that read it.
packed_joints: Vec<JointMatrix>The frame’s joint matrices, packed in visible-instance order.
Reused across frames rather than reallocated: the packed data is exactly what is uploaded, so the array and the buffer stay one allocation each.
packed_morph_weights: Vec<f32>The frame’s morph weights, packed in visible-instance order.
index_pool: BufferPoolReused staging buffers, one per buffer uploaded to every frame, so a steady frame reaches the GPU without a per-frame allocation or submission.
The camera, globals and view uniforms are not among them: the frame’s
GlobalUniforms stages those.
The pool every mesh uploaded through
MeshSource::allocate_lit_mesh keeps its indices in, as one large
buffer shared by every indexed mesh.
A mesh names it through MeshParts::index_buffer, which is why the
buffer is a node in the resource graph and has to be replaced there
when the pool grows; see MeshSource::sync_pool_node.
index_pool_id: ResHandle<Buffer>The graph node of MeshSource::index_pool’s buffer.
vertex_pool: VertexStreamPoolThe pool every mesh uploaded through
MeshSource::allocate_lit_mesh keeps its vertices in: one large
buffer per vertex layout, so meshes that share a layout share a buffer,
and one element allocation covers every stream of a mesh at the same
element index.
vertex_pool_ids: HashMap<VertexBufferLayoutDesc, ResHandle<Buffer>>The graph node of each of MeshSource::vertex_pool’s buffers, by the
layout the buffer is shaped for.
pipelines: Vec<RegisteredPipeline>Every concrete pipeline registered with this source, in registration order.
A pipeline is appended the first time a family resolves a key that needs it, so an entity’s concrete pipeline exists once its family has resolved the draw’s surface and mesh layout.
families: Vec<Box<dyn AnyFamily>>Every pipeline family registered with this source, in registration order. A family’s index in this list is the FamilyId its visible entries carry.
Registration compiles nothing: a family appends to
MeshSource::pipelines lazily, the first time one of its variant
keys is resolved.
family_ids: TypeIdHashMap<FamilyId>§visible_meshes_cache: Vec<VisibleMesh>Reused Vec of the meshes that passed this frame’s frustum culling.
visible_cache: Vec<VisibleEntry>Reused Vec for visible-entity collection and per-frame sorting.
family_instance_cache: Vec<Option<(u32, Buffer)>>Reused Vec of the instance-stream binding of each registered family, indexed by FamilyId.
pipeline_handle_cache: Vec<RenderPipelineHandles>Reused Vec for cloned pipeline handles while the scene is built.
entry_handle_cache: HashMap<DrawHandlesKey, EntryHandles>The frame’s interned draw handles, one per distinct
DrawHandlesKey the visible set named. Reused between frames, so a
steady scene allocates nothing.
Implementations§
Source§impl MeshSource
Mesh allocation and family registration for the built-in lit pipeline.
impl MeshSource
Mesh allocation and family registration for the built-in lit pipeline.
These are ordinary inherent methods on MeshSource: a caller’s own family
uses MeshSource::register_family and MeshSource::allocate_mesh the
same way these use them, and the module gathers them next to the shader
they serve.
Sourcepub fn register_lit_family(&mut self, world: &Scope<'_>)
pub fn register_lit_family(&mut self, world: &Scope<'_>)
Register the built-in lit shader as a family.
The family specializes each entity’s options on the frame’s render
target and the mesh’s vertex layout: two draws that agree on both share
one compiled pipeline, and a draw whose mesh layout implies different
channels compiles its own. The options are the entity’s: a mesh or
material is built against the LitOptions it will be drawn with,
through MeshSource::allocate_lit_mesh and
MeshSource::allocate_lit_material. Those take the options
rather than the key, so any pipeline whose variant reads the same
channels can draw the mesh.
This compiles nothing; like any family, its first concrete pipeline is built when an entity that uses it is first drawn.
The source clusters and uploads every frame’s LightSources whether or not this family is registered: registration says which family a draw resolves with, not which frames draw, so the lights have to be there before the first lit draw. A source that never draws a lit variant pays that upload for nothing.
§Panics
If the lit family is already registered.
Sourcepub fn allocate_lit_mesh(
&mut self,
world: &Scope<'_>,
options: &Hashed<LitOptions>,
desc: LitMeshDesc<'_>,
) -> GpuMesh
pub fn allocate_lit_mesh( &mut self, world: &Scope<'_>, options: &Hashed<LitOptions>, desc: LitMeshDesc<'_>, ) -> GpuMesh
Upload raw mesh channels in the layout the built-in lit shader expects, and return a GpuMesh handle.
Positions and UVs are compressed to the compact vertex formats the shader decodes, packed into a position buffer and an interleaved UV-and-colour buffer, and bound with the mesh-metadata bind group the shader reads its decode parameters from. Colours are already stored in the width they are uploaded at, so they are copied through unchanged.
A skinned mesh’s joint indices and weights are packed into the same stream as its positions, right after them. A morphed mesh’s per-vertex displacements go into a buffer of its own.
Neither mesh carries a pose: the joint matrices and morph weights a
frame deforms by are per-instance state the CPU writes, so they live in
the SkinPose and
MorphWeights components the mesh’s
entity names through a SkinBinding
and a MorphBinding. The frame packs
them once per frame, so animating a mesh costs a component write and no
re-upload.
This is a convenience over MeshSource::allocate_mesh: it builds the
same MeshDesc a caller could build by hand, and shares the
compression in unlit_wgpu::mesh with anyone else who wants it.
Which channels are packed follows the slices the caller passes: a channel with no slice is left out, and the mesh’s vertex layout records exactly the channels that were packed, so the pipeline it is later drawn with reads back the same shape.
§Panics
If the input slices are empty or of mismatched length (see the
compressors in unlit_wgpu::mesh); if only one of
LitMeshDesc::joints and LitMeshDesc::weights is Some; or
if LitMeshDesc::morph_deltas is present but does not hold three
components per vertex and target.
Sourcepub fn allocate_lit_material(
&mut self,
world: &Scope<'_>,
options: &Hashed<LitOptions>,
view_id: ResHandle<TextureView>,
sampler_id: ResHandle<Sampler>,
) -> GpuMaterial
pub fn allocate_lit_material( &mut self, world: &Scope<'_>, options: &Hashed<LitOptions>, view_id: ResHandle<TextureView>, sampler_id: ResHandle<Sampler>, ) -> GpuMaterial
Allocate the lit material bind group from an existing base-colour texture view and sampler, and return its GpuMaterial handle.
Only the bind group is built. view_id and sampler_id name resources
the caller has already put in the graph, and they become the group
dependencies, so replacing either marks it dirty. Whether a draw
samples the texture is the draw own answer — it is what decides the
variant — so a caller that wants a material calls this, and one that
does not leaves it out.
§Panics
If view_id or sampler_id is not a texture view or sampler in the
graph.
Source§impl MeshSource
impl MeshSource
Sourcepub(super) fn upload_joints(
&mut self,
world: &Scope<'_>,
encoder: &mut CommandEncoder,
)
pub(super) fn upload_joints( &mut self, world: &Scope<'_>, encoder: &mut CommandEncoder, )
Grow the frame’s joint-matrix array if the packed data outgrew it, and upload it through the frame’s encoder.
Like the metadata array the resource is replaced only when it is too small, so a steady frame rewrites in place and rebuilds no bind group.
Sourcepub(super) fn upload_morph_deltas(
&mut self,
world: &Scope<'_>,
encoder: &mut CommandEncoder,
)
pub(super) fn upload_morph_deltas( &mut self, world: &Scope<'_>, encoder: &mut CommandEncoder, )
Grow the frame’s morph-displacement array if a mesh outgrew it, and upload the pooled slices through the frame’s encoder.
Allocating or removing a mesh marks the array dirty, so the upload lands in the next frame together with the draws that read it. The resource is replaced only when it is too small, so a steady scene rewrites in place and rebuilds no bind group.
Sourcepub(super) fn upload_morph_weights(
&mut self,
world: &Scope<'_>,
encoder: &mut CommandEncoder,
)
pub(super) fn upload_morph_weights( &mut self, world: &Scope<'_>, encoder: &mut CommandEncoder, )
Grow the frame’s morph-weight array if the packed data outgrew it, and upload it through the frame’s encoder.
Sourcepub(super) fn global_resources(&self) -> GlobalResources
pub(super) fn global_resources(&self) -> GlobalResources
The ids of the source’s global arrays, as a factory and a rebuild recipe see them. The camera, the globals and the view are not among them: the frame holds those.
Sourcepub(super) fn grow_array_to_fit(
world: &Scope<'_>,
ctx: RenderContext,
label: &str,
array: &mut Array,
node: &ResHandle<ArrayHandle>,
device: &Device,
needed: u64,
)
pub(super) fn grow_array_to_fit( world: &Scope<'_>, ctx: RenderContext, label: &str, array: &mut Array, node: &ResHandle<ArrayHandle>, device: &Device, needed: u64, )
Grow array to hold at least capacity elements, publishing the new
resource into the graph when it had to be replaced.
A replaced array leaves every bind group built from the old one stale;
the graph marks their nodes dirty here, and the next
Self::maintain rebuilds them. A no-op when the array already has the
room, so a steady frame replaces nothing and marks nothing.
Sourcepub(super) fn upload_metadata(
&mut self,
world: &Scope<'_>,
encoder: &mut CommandEncoder,
)
pub(super) fn upload_metadata( &mut self, world: &Scope<'_>, encoder: &mut CommandEncoder, )
Grow the metadata buffer if the array outgrew it, and upload the array through the frame’s encoder if it changed.
Allocating or removing a mesh marks the array dirty, so the upload lands in the next frame together with the draws that read it. The storage buffer is recreated only when the array outgrows it, so a steady scene rewrites in place and rebuilds no bind group.
Source§impl MeshSource
impl MeshSource
Sourcepub fn register_family<K, F, I>(
&mut self,
world: &Scope<'_>,
factory: F,
instances: I,
)where
K: RenderPipelineKey + 'static,
F: RenderPipelineFactory<<K::Variant as PipelineVariant<RenderPipeline>>::Descriptor> + 'static,
I: InstanceData,
pub fn register_family<K, F, I>(
&mut self,
world: &Scope<'_>,
factory: F,
instances: I,
)where
K: RenderPipelineKey + 'static,
F: RenderPipelineFactory<<K::Variant as PipelineVariant<RenderPipeline>>::Descriptor> + 'static,
I: InstanceData,
Register a pipeline family for the key type K.
This is the only way a pipeline enters the source, for the built-in unlit shader and a caller own alike. The key type is the family identity: entities draw with it when they carry a GpuRenderPipeline of that type, and registering a second family for the same key type is a programming error.
A family compiles nothing on registration: its concrete pipelines are built lazily, the first time a draw resolves a variant, and are appended to the source pipeline list in resolution order.
MeshSource::register_lit_family is the built-in lit family; a
caller registers their own by supplying the key whose
RenderPipelineKey::variant resolves a draw into a variant, the
RenderPipelineFactory that describes the compiled result, and the
InstanceData that writes its per-instance records. A family with no
per-instance state passes ().
§Panics
If a family is already registered for K.
Sourcepub(super) fn pack_family_instances(
&mut self,
world: &Scope<'_>,
encoder: &mut CommandEncoder,
)
pub(super) fn pack_family_instances( &mut self, world: &Scope<'_>, encoder: &mut CommandEncoder, )
Pack and upload every family’s per-instance data for this frame.
Each family owns one instance stream. The records are written in visible order, so the entry an instance index names is the entry whose draw range covers that index.
Sourcepub(super) fn collect_and_sort_visible(
&mut self,
world: &Scope<'_>,
camera: &Camera,
surface: SurfaceKey,
)
pub(super) fn collect_and_sort_visible( &mut self, world: &Scope<'_>, camera: &Camera, surface: SurfaceKey, )
Collect entities that pass frustum culling, then sort them for drawing.
The pass itself lives in crate::scene; this only unpacks the source’s caches and the closure that registers a newly resolved pipeline, so a family never borrows the whole source.
surface is the render target this frame draws into; it is threaded
into every entity’s pipeline resolution, so each entry’s pipeline_id
is a concrete pipeline valid for that target.
Sourcepub(super) fn assemble_frame(
&mut self,
world: &Scope<'_>,
scene: &mut Scene,
uniforms: &FrameUniforms,
)
pub(super) fn assemble_frame( &mut self, world: &Scope<'_>, scene: &mut Scene, uniforms: &FrameUniforms, )
Assemble the draws of the frame’s visible set into self.scene.
The handles every draw names — the bind groups, the vertex and index buffers, the pipeline — are cloned out of the resource graph into reused scratch tables first, so assembling touches the graph once per distinct draw state and the assembled scene owns everything it names.
A scene usually draws many entities per mesh, and every one of them
names the same handles. The visible set therefore carries a
DrawHandlesKey by value rather than the handles themselves, and the
expensive part — reading the mesh component and cloning its buffers out
of the graph — happens once per distinct key instead of once per entity.
Source§impl MeshSource
impl MeshSource
Sourcepub fn allocate_mesh(&mut self, world: &Scope<'_>, desc: MeshDesc) -> GpuMesh
pub fn allocate_mesh(&mut self, world: &Scope<'_>, desc: MeshDesc) -> GpuMesh
Upload vertex and index data and return a GpuMesh handle.
The source assumes no vertex layout: vertex_buffers lists exactly the
buffers a draw binds, each tagged with the slot the pipeline’s vertex
state declares, so a mesh may carry any combination of attributes in
any format. The pipeline specializes on the layout.
The mesh’s Aabb is recorded in the source’s
mesh-metadata array, which the next built scene uploads.
MeshSource::allocate_lit_mesh is the helper that builds the
compressed layout the built-in lit shader expects.
§Panics
If count is zero for a non-empty draw, or if the index format does
not match the packed data.
Sourcepub(crate) fn allocate_mesh_with_metadata(
&mut self,
world: &Scope<'_>,
desc: MeshDesc,
metadata: MeshMetadata,
skinned: bool,
vertex_offset: u32,
) -> GpuMesh
pub(crate) fn allocate_mesh_with_metadata( &mut self, world: &Scope<'_>, desc: MeshDesc, metadata: MeshMetadata, skinned: bool, vertex_offset: u32, ) -> GpuMesh
Upload a mesh together with the full metadata entry it owns.
The entry is appended to the CPU-side array and reaches the GPU on the
next built scene; the returned handle names its index. vertex_offset
is the draw addressing the entry carries; the morph count is the one the
mesh’s own displacements declare.
skinned records whether the mesh’s position stream carries joints, so
a skinned draw can be required to name the pose entity it deforms by.
Sourcepub fn register_texture_and_default_view(
&mut self,
world: &Scope<'_>,
texture: Texture,
) -> (ResHandle<Texture>, ResHandle<TextureView>)
pub fn register_texture_and_default_view( &mut self, world: &Scope<'_>, texture: Texture, ) -> (ResHandle<Texture>, ResHandle<TextureView>)
Insert texture into the resource graph and return a pair of ids: the
texture itself and a default view of it.
The view is recorded as depending on the texture, so replacing the texture marks every material built from the view dirty. The caller keeps ownership of the texture only until this call; afterwards the graph holds it.
Sourcepub fn register_sampler(
&mut self,
world: &Scope<'_>,
descriptor: Option<SamplerDescriptor<'_>>,
) -> ResHandle<Sampler>
pub fn register_sampler( &mut self, world: &Scope<'_>, descriptor: Option<SamplerDescriptor<'_>>, ) -> ResHandle<Sampler>
Create a sampler with descriptor — or the default one when None —
insert it into the resource graph and return its id.
Sourcepub fn allocate_material(
&mut self,
world: &Scope<'_>,
build: impl Fn(&ResourceGraph) -> BindGroup + 'static,
dependencies: impl IntoIterator<Item = ResHandle>,
) -> GpuMaterial
pub fn allocate_material( &mut self, world: &Scope<'_>, build: impl Fn(&ResourceGraph) -> BindGroup + 'static, dependencies: impl IntoIterator<Item = ResHandle>, ) -> GpuMaterial
Build a material bind group with build and return its GpuMaterial
handle.
Only the bind group is created here: the resources it reads are the
caller’s, already in the resource graph and named in dependencies so
replacing one marks the group dirty. build owns the layout the group is
built against and is called again by Self::maintain whenever a
dependency is replaced, so it has to read whatever it binds back out of
the graph rather than capture a handle. The layout is the material layout
of the pipeline the material is for —
LitVariant::bind_group_layouts
for the built-in shader, or the one a custom pipeline registered.
§Panics
If a resource build reads is not in the graph.
Sourcepub fn remove_mesh(&mut self, mesh: GpuMesh)
pub fn remove_mesh(&mut self, mesh: GpuMesh)
Free mesh and every resource it owns, and drop its mesh-metadata
entry.
The whole mesh hangs off its virtual root: the parts are held by the
root and by nothing else, so dropping mesh — the last holder of the
root — makes them collectable, and the next
Self::maintain frees the root, its bind group
and the per-mesh uniform that only fed that bind group. A mesh uploaded
through allocate_lit_mesh keeps
its vertices and indices in pools the source shares between meshes;
those allocations are handed back here, and the pool buffers outlive the
mesh. A mesh uploaded with allocate_mesh
owns its buffers, and they die with it.
Its metadata slot is freed and reused by a mesh allocated later, so removing meshes does not grow the array a long-lived source uploads. The next built scene uploads the array the shader reads. Removing a mesh does not shrink the metadata buffer: it grows to the largest array it has ever held and stays there.
Any other GpuMesh value sharing this mesh’s parts keeps it alive:
the parts are reference-counted, so a caller that cloned the handle
before calling this still reads a live mesh.
Sourcepub(crate) fn vertex_node(
&mut self,
world: &Scope<'_>,
layout: &VertexBufferLayoutDesc,
) -> ResHandle<Buffer>
pub(crate) fn vertex_node( &mut self, world: &Scope<'_>, layout: &VertexBufferLayoutDesc, ) -> ResHandle<Buffer>
The graph node of the vertex pool’s buffer for layout, creating it if
the pool has never been asked for the layout before.
The node is strong: the source owns the pool, no mesh does. See
MeshSource::sync_pool_node for why nothing may depend on it.
Sourcepub(crate) fn sync_vertex_node(
&mut self,
world: &Scope<'_>,
id: &ResHandle<Buffer>,
layout: &VertexBufferLayoutDesc,
)
pub(crate) fn sync_vertex_node( &mut self, world: &Scope<'_>, id: &ResHandle<Buffer>, layout: &VertexBufferLayoutDesc, )
Point the stream node id at the vertex pool’s buffer for layout.
The pool hands out a new buffer when it grows, so the node has to follow it.
Sourcepub(crate) fn sync_pool_node(
pool: &BufferPool,
id: &ResHandle<Buffer>,
graph: &mut ResourceGraph,
)
pub(crate) fn sync_pool_node( pool: &BufferPool, id: &ResHandle<Buffer>, graph: &mut ResourceGraph, )
Point the graph node id at the buffer pool currently hands out.
A pool grows by creating a new buffer, and a mesh keeps the pool’s node id rather than its buffer, so the node has to follow the buffer. The check is the pool’s own handle compared against what the node holds: no counter to keep in step, and repeating the call is free.
Nothing depends on a pool node — the built-in variants bind no per-mesh resource at all — so replacing one marks nothing else dirty. A dependency added onto a pool buffer makes every grow rebuild it, which is why there must not be one.
Source§impl MeshSource
impl MeshSource
Sourcepub(super) fn upload_lights(
&mut self,
world: &Scope<'_>,
encoder: &mut CommandEncoder,
camera: &Camera,
size: (u32, u32),
)
pub(super) fn upload_lights( &mut self, world: &Scope<'_>, encoder: &mut CommandEncoder, camera: &Camera, size: (u32, u32), )
Cluster the frame’s lights, then grow and upload the three arrays and the uniform a lit draw reads them through.
Clustering runs on the CPU, so the cells and the records reach the GPU the same way on every backend: the arrays are the ones the metadata already travels in, a storage buffer on WebGPU and a texture on WebGL2. The assignment is rewritten every frame, because the camera and the lights can both move.
A quad light’s corners are appended to one frame-wide vertex pool as the lights are packed, and the record names the slice each light took.
Source§impl MeshSource
impl MeshSource
Sourcepub fn new(world: &Scope<'_>, ctx: RenderContext) -> Self
pub fn new(world: &Scope<'_>, ctx: RenderContext) -> Self
Create the source and the GPU resources the mesh path shares.
The camera and globals uniforms, the mesh-metadata storage buffer and
the index and vertex pools every uploaded mesh draws out of are inserted
into the context’s resource graph. The source starts with no families:
register the ones you draw with through
MeshSource::register_family — for the built-in lit shader,
MeshSource::register_lit_family does it for you. Registration
compiles nothing; a family’s first concrete pipeline is built the first
time an entity that uses it is drawn.
§Panics
If ctx does not name the world’s device and resource graph.
Sourcepub fn context(&self) -> RenderContext
pub fn context(&self) -> RenderContext
The world addresses this source draws through.
Setup-time code that needs the resource graph reaches it with
source.context().graph(&view), which is an ordinary ECS access: the
graph and the source live in different cells.
Sourcepub fn device(&self, world: &Scope<'_>) -> Device
pub fn device(&self, world: &Scope<'_>) -> Device
The device the frame is drawn with, cloned out of world.
§Panics
If the context’s device resource is gone.
Sourcepub fn queue(&self, world: &Scope<'_>) -> Queue
pub fn queue(&self, world: &Scope<'_>) -> Queue
The queue the frame is submitted to, cloned out of world.
§Panics
If the context’s queue resource is gone.
Sourcepub fn capabilities(&self, world: &Scope<'_>) -> DeviceCapabilities
pub fn capabilities(&self, world: &Scope<'_>) -> DeviceCapabilities
What the device can do beyond the WebGPU baseline.
Captured from the adapter when the context was spawned, because the
device cannot report it; see
DeviceCapabilities.
§Panics
If the context’s capabilities resource is gone.
Sourcepub fn maintain(&mut self, world: &Scope<'_>)
pub fn maintain(&mut self, world: &Scope<'_>)
Bring the resource graph up to date for this frame.
Collects the resources nothing holds any more, then rebuilds every
dirty node whose recipe the graph holds — the global bind groups among
them. A built scene runs it once, at the point before the frame reads
any of those groups; RenderContext::maintain_scope is how a build
states that point without a call at each of its returns.
Trait Implementations§
Source§impl FrameSource for MeshSource
impl FrameSource for MeshSource
Source§fn build_scene(
&mut self,
world: &Scope<'_>,
ctx: RenderContext,
info: PassInfo,
scene: &mut Scene,
encoder: &mut CommandEncoder,
)
fn build_scene( &mut self, world: &Scope<'_>, ctx: RenderContext, info: PassInfo, scene: &mut Scene, encoder: &mut CommandEncoder, )
Source§fn order(&self) -> FrameSourceOrder
fn order(&self) -> FrameSourceOrder
Auto Trait Implementations§
impl !RefUnwindSafe for MeshSource
impl !Send for MeshSource
impl !Sync for MeshSource
impl !UnwindSafe for MeshSource
impl Forget for MeshSource
impl Freeze for MeshSource
impl Unpin for MeshSource
impl UnsafeUnpin for MeshSource
Blanket Implementations§
impl<T> AnySource for Twhere
T: FrameSource,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> Component for Twhere
T: 'static,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more