Skip to main content

RenderMeshInstanceCpu

Struct RenderMeshInstanceCpu 

Source
pub struct RenderMeshInstanceCpu {
    pub shared: RenderMeshInstanceSharedFlatBlob,
    pub transforms: MeshTransforms,
    pub render_layers: Option<RenderLayers>,
}
Expand description

CPU data that the render world keeps for each entity, when not using GPU mesh uniform building.

Fields§

§shared: RenderMeshInstanceSharedFlatBlob

Data shared between both the CPU mesh uniform building and the GPU mesh uniform building paths.

§transforms: MeshTransforms

The transform of the mesh.

This will be written into the MeshUniform at the appropriate time.

§render_layers: Option<RenderLayers>

The set of render layers that this mesh belongs to.

Methods from Deref<Target = RenderMeshInstanceSharedFlatBlob>§

Source

pub fn mesh_asset_id_flat(&self) -> MeshAssetIdFlat

Source

pub fn set_mesh_asset_id_flat(&self, value: MeshAssetIdFlat)

Source

pub fn material_bindings_index(&self) -> MaterialBindingId

Examples found in repository?
examples/shader_advanced/custom_render_phase.rs (line 452)
432    fn get_binned_batch_data(
433        (mesh_instances, _render_assets, mesh_allocator): &SystemParamItem<Self::Param>,
434        main_entity: MainEntity,
435    ) -> Option<Self::BufferData> {
436        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
437            error!(
438                "`get_binned_batch_data` should never be called in GPU mesh uniform building mode"
439            );
440            return None;
441        };
442        let mesh_instance = mesh_instances.get(&main_entity)?;
443        let first_vertex_index =
444            match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id()) {
445                Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
446                None => 0,
447            };
448
449        Some(MeshUniform::new(
450            &mesh_instance.transforms,
451            first_vertex_index,
452            mesh_instance.material_bindings_index().slot,
453            None,
454            None,
455            None,
456            None,
457        ))
458    }
Source

pub fn set_material_bindings_index(&self, value: MaterialBindingId)

Source

pub fn lightmap_slab_index_flat(&self) -> LightmapSlabIndexFlat

Source

pub fn set_lightmap_slab_index_flat(&self, value: LightmapSlabIndexFlat)

Source

pub fn tag(&self) -> u32

Source

pub fn set_tag(&self, value: u32)

Source

pub fn flags(&self) -> RenderMeshInstanceFlags

Source

pub fn set_flags(&self, value: RenderMeshInstanceFlags)

Source

pub fn mesh_asset_id(&self) -> AssetId<Mesh>

Examples found in repository?
examples/shader_advanced/custom_render_phase.rs (line 379)
363    fn get_batch_data(
364        (mesh_instances, _render_assets, mesh_allocator): &SystemParamItem<Self::Param>,
365        (_entity, main_entity): (Entity, MainEntity),
366    ) -> Option<(
367        Self::BufferData,
368        Option<(Self::BatchSetCompareData, Self::BatchCompareData)>,
369    )> {
370        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
371            error!(
372                "`get_batch_data` should never be called in GPU mesh uniform \
373                building mode"
374            );
375            return None;
376        };
377        let mesh_instance = mesh_instances.get(&main_entity)?;
378        let first_vertex_index =
379            match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id()) {
380                Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
381                None => 0,
382            };
383        let mesh_uniform = {
384            let mesh_transforms = &mesh_instance.transforms;
385            let (local_from_world_transpose_a, local_from_world_transpose_b) =
386                mesh_transforms.world_from_local.inverse_transpose_3x3();
387            MeshUniform {
388                world_from_local: mesh_transforms.world_from_local.to_transpose(),
389                previous_world_from_local: mesh_transforms.previous_world_from_local.to_transpose(),
390                lightmap_uv_rect: UVec2::ZERO,
391                local_from_world_transpose_a,
392                local_from_world_transpose_b,
393                flags: mesh_transforms.flags,
394                first_vertex_index,
395                current_skin_index: u32::MAX,
396                material_and_lightmap_bind_group_slot: 0,
397                tag: 0,
398                morph_descriptor_index: u32::MAX,
399            }
400        };
401        Some((mesh_uniform, None))
402    }
403}
404
405impl GetFullBatchData for StencilPipeline {
406    type BufferInputData = MeshInputUniform;
407
408    fn get_index_and_compare_data(
409        (mesh_instances, _, _): &SystemParamItem<Self::Param>,
410        main_entity: MainEntity,
411    ) -> Option<(
412        NonMaxU32,
413        Option<(Self::BatchSetCompareData, Self::BatchCompareData)>,
414    )> {
415        // This should only be called during GPU building.
416        let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
417            error!(
418                "`get_index_and_compare_data` should never be called in CPU mesh uniform building \
419                mode"
420            );
421            return None;
422        };
423        let mesh_instance = mesh_instances.get(&main_entity)?;
424        Some((
425            NonMaxU32::new(mesh_instance.gpu_specific.current_uniform_index())?,
426            mesh_instance
427                .should_batch()
428                .then_some((mesh_instance.mesh_asset_id(), ())),
429        ))
430    }
431
432    fn get_binned_batch_data(
433        (mesh_instances, _render_assets, mesh_allocator): &SystemParamItem<Self::Param>,
434        main_entity: MainEntity,
435    ) -> Option<Self::BufferData> {
436        let RenderMeshInstances::CpuBuilding(ref mesh_instances) = **mesh_instances else {
437            error!(
438                "`get_binned_batch_data` should never be called in GPU mesh uniform building mode"
439            );
440            return None;
441        };
442        let mesh_instance = mesh_instances.get(&main_entity)?;
443        let first_vertex_index =
444            match mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id()) {
445                Some(mesh_vertex_slice) => mesh_vertex_slice.range.start,
446                None => 0,
447            };
448
449        Some(MeshUniform::new(
450            &mesh_instance.transforms,
451            first_vertex_index,
452            mesh_instance.material_bindings_index().slot,
453            None,
454            None,
455            None,
456            None,
457        ))
458    }
459
460    fn write_batch_indirect_parameters_metadata(
461        indexed: bool,
462        base_output_index: u32,
463        batch_set_index: Option<NonMaxU32>,
464        indirect_parameters_buffers: &mut UntypedPhaseIndirectParametersBuffers,
465        indirect_parameters_offset: u32,
466    ) {
467        // Note that `IndirectParameters` covers both of these structures, even
468        // though they actually have distinct layouts. See the comment above that
469        // type for more information.
470        let indirect_parameters = IndirectParametersCpuMetadata {
471            base_output_index,
472            batch_set_index: match batch_set_index {
473                None => !0,
474                Some(batch_set_index) => u32::from(batch_set_index),
475            },
476        };
477
478        if indexed {
479            indirect_parameters_buffers
480                .indexed
481                .set(indirect_parameters_offset, indirect_parameters);
482        } else {
483            indirect_parameters_buffers
484                .non_indexed
485                .set(indirect_parameters_offset, indirect_parameters);
486        }
487    }
488
489    fn get_binned_index(
490        _param: &SystemParamItem<Self::Param>,
491        _query_item: MainEntity,
492    ) -> Option<NonMaxU32> {
493        None
494    }
495}
496
497// When defining a phase, we need to extract it from the main world and add it to a resource
498// that will be used by the render world. We need to give that resource all views that will use
499// that phase
500fn extract_camera_phases(
501    mut stencil_phases: ResMut<ViewSortedRenderPhases<Stencil3d>>,
502    cameras: Extract<Query<(Entity, &Camera), With<Camera3d>>>,
503    mut live_entities: Local<HashSet<RetainedViewEntity>>,
504) {
505    live_entities.clear();
506    for (main_entity, camera) in &cameras {
507        if !camera.is_active {
508            continue;
509        }
510        // This is the main camera, so we use the first subview index (0)
511        let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
512
513        stencil_phases.prepare_for_new_frame(retained_view_entity);
514        live_entities.insert(retained_view_entity);
515    }
516
517    // Clear out all dead views.
518    stencil_phases.retain(|camera_entity, _| live_entities.contains(camera_entity));
519}
520
521/// A resource that stores meshes that couldn't be specialized yet because their
522/// materials hadn't loaded.
523///
524/// See the documentation for [`PendingQueues`] for more information.
525#[derive(Default, Deref, DerefMut, Resource)]
526struct PendingCustomMeshQueues(pub PendingQueues);
527
528// This is a very important step when writing a custom phase.
529//
530// This system determines which meshes will be added to the phase.
531fn queue_custom_meshes(
532    custom_draw_functions: Res<DrawFunctions<Stencil3d>>,
533    mut pipelines: ResMut<SpecializedMeshPipelines<StencilPipeline>>,
534    pipeline_cache: Res<PipelineCache>,
535    custom_draw_pipeline: Res<StencilPipeline>,
536    render_meshes: Res<RenderAssets<RenderMesh>>,
537    render_mesh_instances: Res<RenderMeshInstances>,
538    maybe_batched_instance_buffers: Option<
539        Res<BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
540    >,
541    mut custom_render_phases: ResMut<ViewSortedRenderPhases<Stencil3d>>,
542    mut views: Query<(&ExtractedView, &RenderVisibleEntities)>,
543    view_key_cache: Res<ViewKeyCache>,
544    dirty_specializations: Res<DirtySpecializations>,
545    mut pending_custom_mesh_queues: ResMut<PendingCustomMeshQueues>,
546    has_marker: Query<(), With<DrawStencil>>,
547) {
548    for (view, visible_entities) in &mut views {
549        let Some(custom_phase) = custom_render_phases.get_mut(&view.retained_view_entity) else {
550            continue;
551        };
552        let draw_custom = custom_draw_functions.read().id::<DrawMesh3dStencil>();
553
554        let Some(&view_key) = view_key_cache.get(&view.retained_view_entity) else {
555            continue;
556        };
557
558        // Since our phase can work on any 3d mesh we can reuse the default mesh 3d filter
559        let Some(render_visible_mesh_entities) = visible_entities.get::<Mesh3d>() else {
560            continue;
561        };
562
563        let view_pending_custom_mesh_queues =
564            pending_custom_mesh_queues.prepare_for_new_frame(view.retained_view_entity);
565
566        // First, remove meshes that need to be respecialized, and those that were removed, from the bins.
567        for &main_entity in dirty_specializations
568            .iter_to_dequeue(view.retained_view_entity, render_visible_mesh_entities)
569        {
570            custom_phase.remove(Entity::PLACEHOLDER, main_entity);
571        }
572
573        for (render_entity, visible_entity) in dirty_specializations.iter_to_queue(
574            view.retained_view_entity,
575            render_visible_mesh_entities,
576            &view_pending_custom_mesh_queues.prev_frame,
577        ) {
578            // We only want meshes with the marker component to be queued to our phase.
579            if has_marker.get(*render_entity).is_err() {
580                continue;
581            }
582            let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*visible_entity)
583            else {
584                // We couldn't fetch the mesh, probably because it hasn't been
585                // loaded yet. Add the entity to the list of pending custom mesh
586                // queues and bail.
587                view_pending_custom_mesh_queues
588                    .current_frame
589                    .insert((*render_entity, *visible_entity));
590                continue;
591            };
592            let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id()) else {
593                continue;
594            };
595
596            // Specialize the key for the current mesh entity
597            // For this example we only specialize based on the mesh topology
598            // but you could have more complex keys and that's where you'd need to create those keys
599            let mut mesh_key = view_key;
600            mesh_key |= MeshPipelineKey::from_primitive_topology_and_strip_index(
601                mesh.primitive_topology(),
602                mesh.index_format(),
603            );
604
605            let pipeline_id = pipelines.specialize(
606                &pipeline_cache,
607                &custom_draw_pipeline,
608                mesh_key,
609                &mesh.layout,
610            );
611            let pipeline_id = match pipeline_id {
612                Ok(id) => id,
613                Err(err) => {
614                    error!("{}", err);
615                    continue;
616                }
617            };
618            // At this point we have all the data we need to create a phase item and add it to our
619            // phase
620            custom_phase.add_retained(Stencil3d {
621                sorting_info: TransparentSortingInfo3d::Sorted {
622                    mesh_center: pbr::get_mesh_instance_world_from_local(
623                        *visible_entity,
624                        mesh_instance.current_uniform_index,
625                        &render_mesh_instances,
626                        maybe_batched_instance_buffers.as_deref(),
627                    )
628                    .transform_point3(
629                        render_meshes
630                            .get(mesh_instance.mesh_asset_id())
631                            .unwrap()
632                            .aabb_center,
633                    ),
634                    depth_bias: 0.0,
635                },
636                distance: FloatOrd(0.0),
637                entity: (Entity::PLACEHOLDER, *visible_entity),
638                pipeline: pipeline_id,
639                draw_function: draw_custom,
640                // Sorted phase items aren't batched
641                batch_range: 0..1,
642                extra_index: PhaseItemExtraIndex::None,
643                indexed: mesh.indexed(),
644            });
645        }
646    }
647}
More examples
Hide additional examples
examples/shader_advanced/custom_shader_instancing.rs (line 169)
137fn queue_custom(
138    transparent_3d_draw_functions: Res<DrawFunctions<Transparent3d>>,
139    custom_pipeline: Res<CustomPipeline>,
140    mut pipelines: ResMut<SpecializedMeshPipelines<CustomPipeline>>,
141    pipeline_cache: Res<PipelineCache>,
142    meshes: Res<RenderAssets<RenderMesh>>,
143    render_mesh_instances: Res<RenderMeshInstances>,
144    maybe_batched_instance_buffers: Option<
145        Res<BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
146    >,
147    material_meshes: Query<(Entity, &MainEntity), With<InstanceMaterialData>>,
148    mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
149    views: Query<&ExtractedView>,
150    view_key_cache: Res<ViewKeyCache>,
151) {
152    let draw_custom = transparent_3d_draw_functions.read().id::<DrawCustom>();
153
154    for view in &views {
155        let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
156        else {
157            continue;
158        };
159
160        let Some(&view_key) = view_key_cache.get(&view.retained_view_entity) else {
161            continue;
162        };
163
164        for (entity, main_entity) in &material_meshes {
165            let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*main_entity)
166            else {
167                continue;
168            };
169            let Some(mesh) = meshes.get(mesh_instance.mesh_asset_id()) else {
170                continue;
171            };
172            let key = view_key
173                | MeshPipelineKey::from_primitive_topology_and_strip_index(
174                    mesh.primitive_topology(),
175                    mesh.index_format(),
176                );
177            let pipeline = pipelines
178                .specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout)
179                .unwrap();
180            transparent_phase.add_retained(Transparent3d {
181                sorting_info: TransparentSortingInfo3d::Sorted {
182                    mesh_center: pbr::get_mesh_instance_world_from_local(
183                        *main_entity,
184                        mesh_instance.current_uniform_index,
185                        &render_mesh_instances,
186                        maybe_batched_instance_buffers.as_deref(),
187                    )
188                    .transform_point3(
189                        meshes
190                            .get(mesh_instance.mesh_asset_id())
191                            .unwrap()
192                            .aabb_center,
193                    ),
194                    depth_bias: 0.0,
195                },
196                entity: (entity, *main_entity),
197                pipeline,
198                draw_function: draw_custom,
199                distance: 0.0,
200                batch_range: 0..1,
201                extra_index: PhaseItemExtraIndex::None,
202                indexed: true,
203            });
204        }
205    }
206}
207
208#[derive(Component)]
209struct InstanceBuffer {
210    buffer: Buffer,
211    length: usize,
212}
213
214fn prepare_instance_buffers(
215    mut commands: Commands,
216    query: Query<(Entity, &InstanceMaterialData)>,
217    render_device: Res<RenderDevice>,
218) {
219    for (entity, instance_data) in &query {
220        let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
221            label: Some("instance data buffer"),
222            contents: bytemuck::cast_slice(instance_data.as_slice()),
223            usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
224        });
225        commands.entity(entity).insert(InstanceBuffer {
226            buffer,
227            length: instance_data.len(),
228        });
229    }
230}
231
232#[derive(Resource)]
233struct CustomPipeline {
234    shader: Handle<Shader>,
235    mesh_pipeline: MeshPipeline,
236}
237
238fn init_custom_pipeline(
239    mut commands: Commands,
240    asset_server: Res<AssetServer>,
241    mesh_pipeline: Res<MeshPipeline>,
242) {
243    commands.insert_resource(CustomPipeline {
244        shader: asset_server.load(SHADER_ASSET_PATH),
245        mesh_pipeline: mesh_pipeline.clone(),
246    });
247}
248
249impl SpecializedMeshPipeline for CustomPipeline {
250    type Key = MeshPipelineKey;
251
252    fn specialize(
253        &self,
254        key: Self::Key,
255        layout: &MeshVertexBufferLayoutRef,
256    ) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
257        let mut descriptor = self.mesh_pipeline.specialize(key, layout)?;
258
259        descriptor.vertex.shader = self.shader.clone();
260        descriptor.vertex.buffers.push(VertexBufferLayout {
261            array_stride: size_of::<InstanceData>() as u64,
262            step_mode: VertexStepMode::Instance,
263            attributes: vec![
264                VertexAttribute {
265                    format: VertexFormat::Float32x4,
266                    offset: 0,
267                    shader_location: 3, // shader locations 0-2 are taken up by Position, Normal and UV attributes
268                },
269                VertexAttribute {
270                    format: VertexFormat::Float32x4,
271                    offset: VertexFormat::Float32x4.size(),
272                    shader_location: 4,
273                },
274            ],
275        });
276        descriptor.fragment.as_mut().unwrap().shader = self.shader.clone();
277        Ok(descriptor)
278    }
279}
280
281type DrawCustom = (
282    SetItemPipeline,
283    SetMeshViewBindGroup<0>,
284    SetMeshViewBindingArrayBindGroup<1>,
285    SetMeshBindGroup<2>,
286    DrawMeshInstanced,
287);
288
289struct DrawMeshInstanced;
290
291impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
292    type Param = (
293        SRes<RenderAssets<RenderMesh>>,
294        SRes<RenderMeshInstances>,
295        SRes<MeshAllocator>,
296    );
297    type ViewQuery = ();
298    type ItemQuery = Read<InstanceBuffer>;
299
300    #[inline]
301    fn render<'w>(
302        item: &P,
303        _view: (),
304        instance_buffer: Option<&'w InstanceBuffer>,
305        (meshes, render_mesh_instances, mesh_allocator): SystemParamItem<'w, '_, Self::Param>,
306        pass: &mut TrackedRenderPass<'w>,
307    ) -> RenderCommandResult {
308        // A borrow check workaround.
309        let mesh_allocator = mesh_allocator.into_inner();
310
311        let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(item.main_entity())
312        else {
313            return RenderCommandResult::Skip;
314        };
315        let Some(gpu_mesh) = meshes.into_inner().get(mesh_instance.mesh_asset_id()) else {
316            return RenderCommandResult::Skip;
317        };
318        let Some(instance_buffer) = instance_buffer else {
319            return RenderCommandResult::Skip;
320        };
321        let Some(vertex_buffer_slice) =
322            mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id())
323        else {
324            return RenderCommandResult::Skip;
325        };
326
327        pass.set_vertex_buffer(0, vertex_buffer_slice.buffer.slice(..));
328        pass.set_vertex_buffer(1, instance_buffer.buffer.slice(..));
329
330        match &gpu_mesh.buffer_info {
331            RenderMeshBufferInfo::Indexed {
332                index_format,
333                count,
334            } => {
335                let Some(index_buffer_slice) =
336                    mesh_allocator.mesh_index_slice(&mesh_instance.mesh_asset_id())
337                else {
338                    return RenderCommandResult::Skip;
339                };
340
341                pass.set_index_buffer(index_buffer_slice.buffer.slice(..), *index_format);
342                pass.draw_indexed(
343                    index_buffer_slice.range.start..(index_buffer_slice.range.start + count),
344                    vertex_buffer_slice.range.start as i32,
345                    0..instance_buffer.length as u32,
346                );
347            }
348            RenderMeshBufferInfo::NonIndexed => {
349                pass.draw(vertex_buffer_slice.range, 0..instance_buffer.length as u32);
350            }
351        }
352        RenderCommandResult::Success
353    }
examples/shader_advanced/specialized_mesh_pipeline.rs (line 351)
277fn queue_custom_mesh_pipeline(
278    pipeline_cache: Res<PipelineCache>,
279    custom_mesh_pipeline: Res<CustomMeshPipeline>,
280    (mut opaque_render_phases, opaque_draw_functions): (
281        ResMut<ViewBinnedRenderPhases<Opaque3d>>,
282        Res<DrawFunctions<Opaque3d>>,
283    ),
284    mut specialized_mesh_pipelines: ResMut<SpecializedMeshPipelines<CustomMeshPipeline>>,
285    views: Query<(&RenderVisibleEntities, &ExtractedView)>,
286    view_key_cache: Res<ViewKeyCache>,
287    (render_meshes, render_mesh_instances): (
288        Res<RenderAssets<RenderMesh>>,
289        Res<RenderMeshInstances>,
290    ),
291    mut change_tick: Local<Tick>,
292    mesh_allocator: Res<MeshAllocator>,
293    gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
294    dirty_specializations: Res<DirtySpecializations>,
295    mut pending_custom_mesh_queues: ResMut<PendingCustomMeshQueues>,
296) {
297    // Get the id for our custom draw function
298    let draw_function = opaque_draw_functions
299        .read()
300        .id::<DrawSpecializedPipelineCommands>();
301
302    // Render phases are per-view, so we need to iterate over all views so that
303    // the entity appears in them. (In this example, we have only one view, but
304    // it's good practice to loop over all views anyway.)
305    for (view_visible_entities, view) in views.iter() {
306        let Some(opaque_phase) = opaque_render_phases.get_mut(&view.retained_view_entity) else {
307            continue;
308        };
309
310        let Some(&view_key) = view_key_cache.get(&view.retained_view_entity) else {
311            continue;
312        };
313
314        let Some(render_visible_mesh_entities) =
315            view_visible_entities.get::<CustomRenderedEntity>()
316        else {
317            continue;
318        };
319
320        // Initialize the pending queues.
321        let view_pending_custom_mesh_queues =
322            pending_custom_mesh_queues.prepare_for_new_frame(view.retained_view_entity);
323
324        // First, remove meshes that need to be respecialized, and those that were removed, from the bins.
325        for &main_entity in dirty_specializations
326            .iter_to_dequeue(view.retained_view_entity, render_visible_mesh_entities)
327        {
328            opaque_phase.remove(main_entity);
329        }
330
331        // Find all the custom rendered entities that are visible from this
332        // view.
333        for (render_entity, visible_entity) in dirty_specializations.iter_to_queue(
334            view.retained_view_entity,
335            render_visible_mesh_entities,
336            &view_pending_custom_mesh_queues.prev_frame,
337        ) {
338            // Get the mesh instance
339            let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*visible_entity)
340            else {
341                // We couldn't fetch the mesh, probably because it hasn't been
342                // loaded yet. Add the entity to the list of pending custom
343                // meshes and bail.
344                view_pending_custom_mesh_queues
345                    .current_frame
346                    .insert((*render_entity, *visible_entity));
347                continue;
348            };
349
350            // Get the mesh data
351            let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id()) else {
352                continue;
353            };
354
355            let Some(mesh_slabs) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id()) else {
356                continue;
357            };
358
359            // Specialize the key for the current mesh entity
360            // For this example we only specialize based on the mesh topology
361            // but you could have more complex keys and that's where you'd need to create those keys
362            let mut mesh_key = view_key;
363            mesh_key |= MeshPipelineKey::from_primitive_topology_and_strip_index(
364                mesh.primitive_topology(),
365                mesh.index_format(),
366            );
367
368            // Finally, we can specialize the pipeline based on the key
369            let pipeline_id = specialized_mesh_pipelines
370                .specialize(
371                    &pipeline_cache,
372                    &custom_mesh_pipeline,
373                    mesh_key,
374                    &mesh.layout,
375                )
376                // This should never happen with this example, but if your pipeline
377                // specialization can fail you need to handle the error here
378                .expect("Failed to specialize mesh pipeline");
379
380            // Bump the change tick so that Bevy is forced to rebuild the bin.
381            let next_change_tick = change_tick.get() + 1;
382            change_tick.set(next_change_tick);
383
384            // Add the mesh with our specialized pipeline
385            opaque_phase.add(
386                Opaque3dBatchSetKey {
387                    draw_function,
388                    pipeline: pipeline_id,
389                    material_bind_group_index: None,
390                    slabs: mesh_slabs,
391                    lightmap_slab: None,
392                },
393                // For this example we can use the mesh asset id as the bin key,
394                // but you can use any asset_id as a key
395                Opaque3dBinKey {
396                    asset_id: mesh_instance.mesh_asset_id().into(),
397                },
398                (*render_entity, *visible_entity),
399                mesh_instance.current_uniform_index,
400                // This example supports batching and multi draw indirect,
401                // but if your pipeline doesn't support it you can use
402                // `BinnedRenderPhaseType::UnbatchableMesh`
403                BinnedRenderPhaseType::mesh(
404                    mesh_instance.should_batch(),
405                    &gpu_preprocessing_support,
406                ),
407            );
408        }
409    }
410}
Source

pub fn set_mesh_asset_id(&self, asset_id: AssetId<Mesh>)

Source

pub fn lightmap_slab_index(&self) -> Option<LightmapSlabIndex>

Source

pub fn set_lightmap_slab_index( &self, lightmap_slab_index: Option<LightmapSlabIndex>, )

Source

pub fn should_batch(&self) -> bool

Returns true if this entity is eligible to participate in automatic batching.

Examples found in repository?
examples/shader_advanced/custom_render_phase.rs (line 427)
408    fn get_index_and_compare_data(
409        (mesh_instances, _, _): &SystemParamItem<Self::Param>,
410        main_entity: MainEntity,
411    ) -> Option<(
412        NonMaxU32,
413        Option<(Self::BatchSetCompareData, Self::BatchCompareData)>,
414    )> {
415        // This should only be called during GPU building.
416        let RenderMeshInstances::GpuBuilding(ref mesh_instances) = **mesh_instances else {
417            error!(
418                "`get_index_and_compare_data` should never be called in CPU mesh uniform building \
419                mode"
420            );
421            return None;
422        };
423        let mesh_instance = mesh_instances.get(&main_entity)?;
424        Some((
425            NonMaxU32::new(mesh_instance.gpu_specific.current_uniform_index())?,
426            mesh_instance
427                .should_batch()
428                .then_some((mesh_instance.mesh_asset_id(), ())),
429        ))
430    }
More examples
Hide additional examples
examples/shader_advanced/specialized_mesh_pipeline.rs (line 404)
277fn queue_custom_mesh_pipeline(
278    pipeline_cache: Res<PipelineCache>,
279    custom_mesh_pipeline: Res<CustomMeshPipeline>,
280    (mut opaque_render_phases, opaque_draw_functions): (
281        ResMut<ViewBinnedRenderPhases<Opaque3d>>,
282        Res<DrawFunctions<Opaque3d>>,
283    ),
284    mut specialized_mesh_pipelines: ResMut<SpecializedMeshPipelines<CustomMeshPipeline>>,
285    views: Query<(&RenderVisibleEntities, &ExtractedView)>,
286    view_key_cache: Res<ViewKeyCache>,
287    (render_meshes, render_mesh_instances): (
288        Res<RenderAssets<RenderMesh>>,
289        Res<RenderMeshInstances>,
290    ),
291    mut change_tick: Local<Tick>,
292    mesh_allocator: Res<MeshAllocator>,
293    gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
294    dirty_specializations: Res<DirtySpecializations>,
295    mut pending_custom_mesh_queues: ResMut<PendingCustomMeshQueues>,
296) {
297    // Get the id for our custom draw function
298    let draw_function = opaque_draw_functions
299        .read()
300        .id::<DrawSpecializedPipelineCommands>();
301
302    // Render phases are per-view, so we need to iterate over all views so that
303    // the entity appears in them. (In this example, we have only one view, but
304    // it's good practice to loop over all views anyway.)
305    for (view_visible_entities, view) in views.iter() {
306        let Some(opaque_phase) = opaque_render_phases.get_mut(&view.retained_view_entity) else {
307            continue;
308        };
309
310        let Some(&view_key) = view_key_cache.get(&view.retained_view_entity) else {
311            continue;
312        };
313
314        let Some(render_visible_mesh_entities) =
315            view_visible_entities.get::<CustomRenderedEntity>()
316        else {
317            continue;
318        };
319
320        // Initialize the pending queues.
321        let view_pending_custom_mesh_queues =
322            pending_custom_mesh_queues.prepare_for_new_frame(view.retained_view_entity);
323
324        // First, remove meshes that need to be respecialized, and those that were removed, from the bins.
325        for &main_entity in dirty_specializations
326            .iter_to_dequeue(view.retained_view_entity, render_visible_mesh_entities)
327        {
328            opaque_phase.remove(main_entity);
329        }
330
331        // Find all the custom rendered entities that are visible from this
332        // view.
333        for (render_entity, visible_entity) in dirty_specializations.iter_to_queue(
334            view.retained_view_entity,
335            render_visible_mesh_entities,
336            &view_pending_custom_mesh_queues.prev_frame,
337        ) {
338            // Get the mesh instance
339            let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*visible_entity)
340            else {
341                // We couldn't fetch the mesh, probably because it hasn't been
342                // loaded yet. Add the entity to the list of pending custom
343                // meshes and bail.
344                view_pending_custom_mesh_queues
345                    .current_frame
346                    .insert((*render_entity, *visible_entity));
347                continue;
348            };
349
350            // Get the mesh data
351            let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id()) else {
352                continue;
353            };
354
355            let Some(mesh_slabs) = mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id()) else {
356                continue;
357            };
358
359            // Specialize the key for the current mesh entity
360            // For this example we only specialize based on the mesh topology
361            // but you could have more complex keys and that's where you'd need to create those keys
362            let mut mesh_key = view_key;
363            mesh_key |= MeshPipelineKey::from_primitive_topology_and_strip_index(
364                mesh.primitive_topology(),
365                mesh.index_format(),
366            );
367
368            // Finally, we can specialize the pipeline based on the key
369            let pipeline_id = specialized_mesh_pipelines
370                .specialize(
371                    &pipeline_cache,
372                    &custom_mesh_pipeline,
373                    mesh_key,
374                    &mesh.layout,
375                )
376                // This should never happen with this example, but if your pipeline
377                // specialization can fail you need to handle the error here
378                .expect("Failed to specialize mesh pipeline");
379
380            // Bump the change tick so that Bevy is forced to rebuild the bin.
381            let next_change_tick = change_tick.get() + 1;
382            change_tick.set(next_change_tick);
383
384            // Add the mesh with our specialized pipeline
385            opaque_phase.add(
386                Opaque3dBatchSetKey {
387                    draw_function,
388                    pipeline: pipeline_id,
389                    material_bind_group_index: None,
390                    slabs: mesh_slabs,
391                    lightmap_slab: None,
392                },
393                // For this example we can use the mesh asset id as the bin key,
394                // but you can use any asset_id as a key
395                Opaque3dBinKey {
396                    asset_id: mesh_instance.mesh_asset_id().into(),
397                },
398                (*render_entity, *visible_entity),
399                mesh_instance.current_uniform_index,
400                // This example supports batching and multi draw indirect,
401                // but if your pipeline doesn't support it you can use
402                // `BinnedRenderPhaseType::UnbatchableMesh`
403                BinnedRenderPhaseType::mesh(
404                    mesh_instance.should_batch(),
405                    &gpu_preprocessing_support,
406                ),
407            );
408        }
409    }
410}

Trait Implementations§

Source§

impl Deref for RenderMeshInstanceCpu

Source§

type Target = RenderMeshInstanceSharedFlatBlob

The resulting type after dereferencing.
Source§

fn deref(&self) -> &<RenderMeshInstanceCpu as Deref>::Target

Dereferences the value.
Source§

impl DerefMut for RenderMeshInstanceCpu

Source§

fn deref_mut(&mut self) -> &mut <RenderMeshInstanceCpu as Deref>::Target

Mutably dereferences the value.

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, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

Source§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

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

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

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

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> InitializeFromFunction<T> for T

Source§

fn initialize_from_function(f: fn() -> T) -> T

Create an instance of this type from an initialization function
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

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

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Settings for T
where T: 'static + Send + Sync,

Source§

impl<Ret> SpawnIfAsync<(), Ret> for Ret

Source§

fn spawn(self) -> Ret

Spawn the value into the dioxus runtime if it is an async block
Source§

impl<T, O> SuperFrom<T> for O
where O: From<T>,

Source§

fn super_from(input: T) -> O

Convert from a type to another type.
Source§

impl<T, O, M> SuperInto<O, M> for T
where O: SuperFrom<T, M>,

Source§

fn super_into(self) -> O

Convert from a type to another type.
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

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

Source§

impl<T> WasmNotSendSync for T

Source§

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

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more