Skip to main content

PipelineCache

Struct PipelineCache 

Source
pub struct PipelineCache { /* private fields */ }
Available on crate feature bevy_render only.
Expand description

Cache for render and compute pipelines.

The cache stores existing render and compute pipelines allocated on the GPU, as well as pending creation. Pipelines inserted into the cache are identified by a unique ID, which can be used to retrieve the actual GPU object once it’s ready. The creation of the GPU pipeline object is deferred to the RenderSystems::Render step, just before the render graph starts being processed, as this requires access to the GPU.

Note that the cache does not perform automatic deduplication of identical pipelines. It is up to the user not to insert the same pipeline twice to avoid wasting GPU resources.

Implementations§

Source§

impl PipelineCache

Source

pub fn pipelines(&self) -> impl Iterator<Item = &CachedPipeline>

Returns an iterator over the pipelines in the pipeline cache.

Source

pub fn waiting_pipelines(&self) -> impl Iterator<Item = usize>

Returns a iterator of the IDs of all currently waiting pipelines.

Examples found in repository?
examples/showcase/loading_screen.rs (line 302)
300    fn update_pipelines_ready(mut main_world: ResMut<MainWorld>, pipelines: Res<PipelineCache>) {
301        if let Some(mut pipelines_ready) = main_world.get_resource_mut::<PipelinesReady>() {
302            pipelines_ready.0 = pipelines.waiting_pipelines().count() == 0;
303        }
304    }
Source

pub fn new( device: RenderDevice, synchronous_pipeline_compilation: bool, ) -> PipelineCache

Create a new pipeline cache associated with the given render device.

Source

pub fn get_render_pipeline_state( &self, id: CachedRenderPipelineId, ) -> &CachedPipelineState

Get the state of a cached render pipeline.

See PipelineCache::queue_render_pipeline().

Source

pub fn get_compute_pipeline_state( &self, id: CachedComputePipelineId, ) -> &CachedPipelineState

Get the state of a cached compute pipeline.

See PipelineCache::queue_compute_pipeline().

Examples found in repository?
examples/shader/compute_shader_game_of_life.rs (line 229)
221fn update(
222    pipeline: Res<GameOfLifePipeline>,
223    pipeline_cache: Res<PipelineCache>,
224    mut state: ResMut<GameOfLifeState>,
225) {
226    // if the corresponding pipeline has loaded, transition to the next stage
227    match *state {
228        GameOfLifeState::Loading => {
229            match pipeline_cache.get_compute_pipeline_state(pipeline.init_pipeline) {
230                CachedPipelineState::Ok(_) => {
231                    *state = GameOfLifeState::Init;
232                }
233                // If the shader hasn't loaded yet, just wait.
234                CachedPipelineState::Err(ShaderCacheError::ShaderNotLoaded(_)) => {}
235                CachedPipelineState::Err(err) => {
236                    panic!("Initializing assets/{SHADER_ASSET_PATH}:\n{err}")
237                }
238                _ => {}
239            }
240        }
241        GameOfLifeState::Init => {
242            if let CachedPipelineState::Ok(_) =
243                pipeline_cache.get_compute_pipeline_state(pipeline.update_pipeline)
244            {
245                *state = GameOfLifeState::Update(1);
246            }
247        }
248        GameOfLifeState::Update(0) => {
249            *state = GameOfLifeState::Update(1);
250        }
251        GameOfLifeState::Update(1) => {
252            *state = GameOfLifeState::Update(0);
253        }
254        GameOfLifeState::Update(_) => unreachable!(),
255    }
256}
Source

pub fn get_render_pipeline_descriptor( &self, id: CachedRenderPipelineId, ) -> &RenderPipelineDescriptor

Get the render pipeline descriptor a cached render pipeline was inserted from.

See PipelineCache::queue_render_pipeline().

Note: Be careful calling this method. It will panic if called with a pipeline that has been queued but has not yet been processed by PipelineCache::process_queue().

Source

pub fn get_compute_pipeline_descriptor( &self, id: CachedComputePipelineId, ) -> &ComputePipelineDescriptor

Get the compute pipeline descriptor a cached render pipeline was inserted from.

See PipelineCache::queue_compute_pipeline().

Note: Be careful calling this method. It will panic if called with a pipeline that has been queued but has not yet been processed by PipelineCache::process_queue().

Source

pub fn get_mesh_pipeline_descriptor( &self, id: CachedRenderPipelineId, ) -> &MeshPipelineDescriptor

Get the mesh pipeline descriptor a cached mesh pipeline was inserted from.

See PipelineCache::queue_mesh_pipeline().

Note: Be careful calling this method. It will panic if called with a pipeline that has been queued but has not yet been processed by PipelineCache::process_queue().

Source

pub fn get_render_pipeline( &self, id: CachedRenderPipelineId, ) -> Option<&RenderPipeline>

Try to retrieve a render pipeline GPU object from a cached ID.

§Returns

This method returns a successfully created render pipeline if any, or None if the pipeline was not created yet or if there was an error during creation. You can check the actual creation state with PipelineCache::get_render_pipeline_state().

Examples found in repository?
examples/shader_advanced/mesh_shader_intro.rs (line 217)
202fn draw_mesh_shader_cubes(
203    mut views: Query<(
204        &ExtractedCamera,
205        &ExtractedView,
206        &ViewTarget,
207        &ViewDepthStencilTexture,
208        &ViewUniformOffset,
209        Option<&MainPassResolutionOverride>,
210    )>,
211    mut render_context: RenderContext,
212    data: Res<MyMeshShaderDrawNode>,
213    view_uniforms: Res<ViewUniforms>,
214    globals: Res<GlobalsBuffer>,
215    pipeline_cache: Res<PipelineCache>,
216) {
217    let Some(mesh_pipeline) = pipeline_cache.get_render_pipeline(data.mesh_pipeline) else {
218        return;
219    };
220
221    for (camera, _, target, depth, view_uniform_offset, resolution_override) in &mut views {
222        let Some(view_binding) = view_uniforms.uniforms.binding() else {
223            return;
224        };
225        let Some(globals_binding) = globals.buffer.binding() else {
226            return;
227        };
228        let bind_group = render_context.render_device().create_bind_group(
229            "custom_task_mesh_bind_group",
230            &pipeline_cache.get_bind_group_layout(&data.layout),
231            &BindGroupEntries::sequential((globals_binding, view_binding)),
232        );
233
234        {
235            let mut pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
236                label: Some("custom_mesh_shader_pass"),
237                // Write directly to the view target
238                color_attachments: &[Some(target.get_color_attachment())],
239                depth_stencil_attachment: Some(depth.get_attachment(StoreOp::Store)),
240                timestamp_writes: None,
241                occlusion_query_set: None,
242                multiview_mask: None,
243            });
244
245            pass.set_render_pipeline(mesh_pipeline);
246            pass.set_bind_group(0, &bind_group, &[view_uniform_offset.offset]);
247            if let Some(viewport) =
248                Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
249            {
250                pass.set_camera_viewport(&viewport);
251            }
252
253            // Since this MeshPipeline has a task shader, this call
254            // dispatches the task shader workgroup
255            pass.draw_mesh_tasks(1, 1, 1);
256        }
257    }
258}
More examples
Hide additional examples
examples/shader_advanced/deferred_raymarch.rs (line 244)
229fn raymarch_gbuffer_pass(
230    view: ViewQuery<(
231        &ViewUniformOffset,
232        &ViewDepthStencilTexture,
233        &ViewPrepassTextures,
234    )>,
235    pipeline: Option<Res<RaymarchGBufferPipeline>>,
236    pipeline_cache: Res<PipelineCache>,
237    view_uniforms: Res<ViewUniforms>,
238    globals: Res<GlobalsBuffer>,
239    mut ctx: RenderContext,
240) {
241    let Some(pipeline) = pipeline else {
242        return;
243    };
244    let Some(render_pipeline) = pipeline_cache.get_render_pipeline(pipeline.pipeline_id) else {
245        return;
246    };
247
248    let (view_uniform_offset, view_depth, view_prepass_textures) = view.into_inner();
249
250    let (Some(deferred), Some(lighting_pass_id)) = (
251        &view_prepass_textures.deferred,
252        &view_prepass_textures.deferred_lighting_pass_id,
253    ) else {
254        return;
255    };
256
257    let Some(bind_group) = raymarch_bind_group(
258        &ctx,
259        &pipeline_cache,
260        &pipeline.layout,
261        &view_uniforms,
262        &globals,
263    ) else {
264        return;
265    };
266
267    {
268        // We load rather than clear because we only want to overwrite the pixels which the deferred mesh
269        // prepass didn't write
270        let mut pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {
271            label: Some("raymarch_gbuffer_pass"),
272            color_attachments: &[
273                Some(deferred.get_attachment()),
274                Some(lighting_pass_id.get_attachment()),
275            ],
276            depth_stencil_attachment: Some(view_depth.get_attachment(StoreOp::Store)),
277            timestamp_writes: None,
278            occlusion_query_set: None,
279            multiview_mask: None,
280        });
281
282        pass.set_render_pipeline(render_pipeline);
283        pass.set_bind_group(0, &bind_group, &[view_uniform_offset.offset]);
284        pass.draw(0..3, 0..1);
285    }
286
287    // The deferred lighting pass reconstructs world position from the prepass depth
288    // texture, not the depth attachment we just wrote, so we have to do a copy.
289    if let Some(prepass_depth) = &view_prepass_textures.depth {
290        ctx.command_encoder().copy_texture_to_texture(
291            view_depth.texture().as_image_copy(),
292            prepass_depth.texture.texture.as_image_copy(),
293            view_prepass_textures.size,
294        );
295    }
296}
297
298fn raymarch_directional_shadow_pass(
299    view: ViewQuery<&ViewLightEntities>,
300    shadow_views: Query<(&ShadowView, &ViewUniformOffset)>,
301    pipeline: Option<Res<RaymarchShadowPipeline>>,
302    pipeline_cache: Res<PipelineCache>,
303    view_uniforms: Res<ViewUniforms>,
304    globals: Res<GlobalsBuffer>,
305    mut ctx: RenderContext,
306) {
307    let Some(pipeline) = pipeline else {
308        return;
309    };
310    let Some(render_pipeline) = pipeline_cache.get_render_pipeline(pipeline.pipeline_id) else {
311        return;
312    };
313
314    let view_lights = view.into_inner();
315    for light_entity in view_lights.lights.iter().copied() {
316        let Ok((shadow_view, view_uniform_offset)) = shadow_views.get(light_entity) else {
317            continue;
318        };
319        draw_raymarch_shadow(
320            &mut ctx,
321            &pipeline_cache,
322            &pipeline.layout,
323            &view_uniforms,
324            &globals,
325            render_pipeline,
326            shadow_view,
327            view_uniform_offset,
328        );
329    }
330}
331
332fn raymarch_shared_shadow_pass(
333    view: ViewQuery<(&ShadowView, &ViewUniformOffset)>,
334    pipeline: Option<Res<RaymarchShadowPipeline>>,
335    pipeline_cache: Res<PipelineCache>,
336    view_uniforms: Res<ViewUniforms>,
337    globals: Res<GlobalsBuffer>,
338    mut ctx: RenderContext,
339) {
340    let Some(pipeline) = pipeline else {
341        return;
342    };
343    let Some(render_pipeline) = pipeline_cache.get_render_pipeline(pipeline.pipeline_id) else {
344        return;
345    };
346
347    let (shadow_view, view_uniform_offset) = view.into_inner();
348    draw_raymarch_shadow(
349        &mut ctx,
350        &pipeline_cache,
351        &pipeline.layout,
352        &view_uniforms,
353        &globals,
354        render_pipeline,
355        shadow_view,
356        view_uniform_offset,
357    );
358}
examples/shader_advanced/custom_post_processing.rs (line 156)
140fn post_process_system(
141    view: ViewQuery<(
142        &ViewTarget,
143        &DynamicUniformIndex<PostProcessSettings>,
144        &PostProcessBindGroups,
145    )>,
146    post_process_pipeline: Option<Res<PostProcessPipeline>>,
147    pipeline_cache: Res<PipelineCache>,
148    mut ctx: RenderContext,
149) {
150    let Some(post_process_pipeline) = post_process_pipeline else {
151        return;
152    };
153
154    let (view_target, settings_index, bind_groups) = view.into_inner();
155
156    let Some(pipeline) = pipeline_cache.get_render_pipeline(post_process_pipeline.pipeline_id)
157    else {
158        return;
159    };
160
161    // This will start a new "post process write", obtaining two texture
162    // views from the view target - a `source` and a `destination`.
163    // `source` is the "current" main texture and you _must_ write into
164    // `destination` because calling `post_process_write()` on the
165    // [`ViewTarget`] will internally flip the [`ViewTarget`]'s main
166    // texture to the `destination` texture. Failing to do so will cause
167    // the current main texture information to be lost.
168    let post_process = view_target.post_process_write();
169
170    // We prepared the bind group ahead of time but now we need to make sure
171    // we pick the bind group associated with the source texture
172    let (_, bind_group) = if bind_groups.a.0 == post_process.source.id() {
173        &bind_groups.a
174    } else {
175        &bind_groups.b
176    };
177
178    let mut render_pass = ctx
179        .command_encoder()
180        .begin_render_pass(&RenderPassDescriptor {
181            label: Some("post_process_pass"),
182            color_attachments: &[Some(RenderPassColorAttachment {
183                // We need to specify the post process destination view here
184                // to make sure we write to the appropriate texture.
185                view: post_process.destination,
186                depth_slice: None,
187                resolve_target: None,
188                ops: Operations::default(),
189            })],
190            depth_stencil_attachment: None,
191            timestamp_writes: None,
192            occlusion_query_set: None,
193            multiview_mask: None,
194        });
195
196    render_pass.set_pipeline(pipeline);
197    // By passing in the index of the post process settings on this view, we ensure
198    // that in the event that multiple settings were sent to the GPU (as would be the
199    // case with multiple cameras), we use the correct one.
200    render_pass.set_bind_group(0, bind_group, &[settings_index.index()]);
201    render_pass.draw(0..3, 0..1);
202}
Source

pub fn block_on_render_pipeline(&mut self, id: CachedRenderPipelineId)

Wait for a render pipeline to finish compiling.

Source

pub fn get_compute_pipeline( &self, id: CachedComputePipelineId, ) -> Option<&ComputePipeline>

Try to retrieve a compute pipeline GPU object from a cached ID.

§Returns

This method returns a successfully created compute pipeline if any, or None if the pipeline was not created yet or if there was an error during creation. You can check the actual creation state with PipelineCache::get_compute_pipeline_state().

Examples found in repository?
examples/shader/gpu_readback.rs (line 220)
214fn compute(
215    mut render_context: RenderContext,
216    pipeline_cache: Res<PipelineCache>,
217    pipeline: Res<ComputePipeline>,
218    bind_group: Res<GpuBufferBindGroup>,
219) {
220    if let Some(init_pipeline) = pipeline_cache.get_compute_pipeline(pipeline.pipeline) {
221        let mut pass =
222            render_context
223                .command_encoder()
224                .begin_compute_pass(&ComputePassDescriptor {
225                    label: Some("GPU readback compute pass"),
226                    ..default()
227                });
228
229        pass.set_bind_group(0, &bind_group.0, &[]);
230        pass.set_pipeline(init_pipeline);
231        pass.dispatch_workgroups(BUFFER_LEN as u32, 1, 1);
232    }
233}
More examples
Hide additional examples
examples/shader_advanced/compute_mesh.rs (line 185)
174fn prepare_chunks(
175    meshes_to_generate: Query<&GenerateMesh>,
176    mut chunks: ResMut<ChunksToProcess>,
177    pipeline_cache: Res<PipelineCache>,
178    pipeline: Res<ComputePipeline>,
179    mut processed: Local<HashSet<AssetId<Mesh>>>,
180) {
181    // If the pipeline isn't ready, then meshes
182    // won't be processed. So we want to wait until
183    // the pipeline is ready before considering any mesh processed.
184    if pipeline_cache
185        .get_compute_pipeline(pipeline.pipeline)
186        .is_some()
187    {
188        // get the AssetId for each Handle<Mesh>
189        // which we'll use later to get the relevant buffers
190        // from the mesh_allocator
191        let chunk_data: Vec<AssetId<Mesh>> = meshes_to_generate
192            .iter()
193            .filter_map(|gmesh| {
194                let id = gmesh.0.id();
195                processed.contains(&id).not().then_some(id)
196            })
197            .collect();
198
199        // Cache any meshes we're going to process this frame
200        for id in &chunk_data {
201            processed.insert(*id);
202        }
203
204        chunks.0 = chunk_data;
205    }
206}
207
208#[derive(Resource)]
209struct ComputePipeline {
210    layout: BindGroupLayoutDescriptor,
211    pipeline: CachedComputePipelineId,
212}
213
214// init only happens once
215fn init_compute_pipeline(
216    mut commands: Commands,
217    asset_server: Res<AssetServer>,
218    pipeline_cache: Res<PipelineCache>,
219) {
220    let layout = BindGroupLayoutDescriptor::new(
221        "",
222        &BindGroupLayoutEntries::sequential(
223            ShaderStages::COMPUTE,
224            (
225                // offsets
226                uniform_buffer::<DataRanges>(false),
227                // vertices
228                storage_buffer::<Vec<f32>>(false),
229                // indices
230                storage_buffer::<Vec<u32>>(false),
231            ),
232        ),
233    );
234    let shader = asset_server.load(SHADER_ASSET_PATH);
235    let pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
236        label: Some("Mesh generation compute shader".into()),
237        layout: vec![layout.clone()],
238        shader: shader.clone(),
239        ..default()
240    });
241    commands.insert_resource(ComputePipeline { layout, pipeline });
242}
243
244// A uniform that holds the vertex and index offsets
245// for the vertex/index mesh_allocator buffer slabs
246#[derive(ShaderType)]
247struct DataRanges {
248    vertex_start: u32,
249    vertex_end: u32,
250    index_start: u32,
251    index_end: u32,
252}
253
254fn compute_mesh(
255    mut render_context: RenderContext,
256    chunks: Res<ChunksToProcess>,
257    mesh_allocator: Res<MeshAllocator>,
258    pipeline_cache: Res<PipelineCache>,
259    pipeline: Res<ComputePipeline>,
260    render_queue: Res<RenderQueue>,
261) {
262    let Some(init_pipeline) = pipeline_cache.get_compute_pipeline(pipeline.pipeline) else {
263        return;
264    };
265
266    for mesh_id in &chunks.0 {
267        info!(?mesh_id, "processing mesh");
268
269        // the mesh_allocator holds slabs of meshes, so the buffers we get here
270        // can contain more data than just the mesh we're asking for.
271        // That's why there is a range field.
272        // You should *not* touch data in these buffers that is outside of the range.
273        let vertex_buffer_slice = mesh_allocator.mesh_vertex_slice(mesh_id).unwrap();
274        let index_buffer_slice = mesh_allocator.mesh_index_slice(mesh_id).unwrap();
275
276        let first = DataRanges {
277            // there are 8 vertex data values (pos, normal, uv) per vertex
278            // and the vertex_buffer_slice.range.start is in "vertex elements"
279            // which includes all of that data, so each index is worth 8 indices
280            // to our shader code.
281            vertex_start: vertex_buffer_slice.range.start * 8,
282            vertex_end: vertex_buffer_slice.range.end * 8,
283            // but each vertex index is a single value, so the index of the
284            // vertex indices is exactly what the value is
285            index_start: index_buffer_slice.range.start,
286            index_end: index_buffer_slice.range.end,
287        };
288
289        let mut uniforms = UniformBuffer::from(first);
290        uniforms.write_buffer(render_context.render_device(), &render_queue);
291
292        // pass in the full mesh_allocator slabs as well as the first index
293        // offsets for the vertex and index buffers
294        let bind_group = render_context.render_device().create_bind_group(
295            None,
296            &pipeline_cache.get_bind_group_layout(&pipeline.layout),
297            &BindGroupEntries::sequential((
298                &uniforms,
299                vertex_buffer_slice.buffer.as_entire_buffer_binding(),
300                index_buffer_slice.buffer.as_entire_buffer_binding(),
301            )),
302        );
303
304        let mut pass =
305            render_context
306                .command_encoder()
307                .begin_compute_pass(&ComputePassDescriptor {
308                    label: Some("Mesh generation compute pass"),
309                    ..default()
310                });
311        pass.push_debug_group("compute_mesh");
312
313        pass.set_bind_group(0, &bind_group, &[]);
314        pass.set_pipeline(init_pipeline);
315        // we only dispatch 1,1,1 workgroup here, but a real compute shader
316        // would take advantage of more and larger size workgroups
317        pass.dispatch_workgroups(1, 1, 1);
318
319        pass.pop_debug_group();
320    }
321}
examples/shader/compute_shader_game_of_life.rs (line 274)
258fn game_of_life(
259    mut render_context: RenderContext,
260    bind_groups: Res<GameOfLifeImageBindGroups>,
261    pipeline_cache: Res<PipelineCache>,
262    pipeline: Res<GameOfLifePipeline>,
263    state: Res<GameOfLifeState>,
264) {
265    let mut pass = render_context
266        .command_encoder()
267        .begin_compute_pass(&ComputePassDescriptor::default());
268
269    // select the pipeline based on the current state
270    match *state {
271        GameOfLifeState::Loading => {}
272        GameOfLifeState::Init => {
273            let init_pipeline = pipeline_cache
274                .get_compute_pipeline(pipeline.init_pipeline)
275                .unwrap();
276            pass.set_bind_group(0, &bind_groups.0[0], &[]);
277            pass.set_pipeline(init_pipeline);
278            pass.dispatch_workgroups(SIZE.x / WORKGROUP_SIZE, SIZE.y / WORKGROUP_SIZE, 1);
279        }
280        GameOfLifeState::Update(index) => {
281            let update_pipeline = pipeline_cache
282                .get_compute_pipeline(pipeline.update_pipeline)
283                .unwrap();
284            pass.set_bind_group(0, &bind_groups.0[index], &[]);
285            pass.set_pipeline(update_pipeline);
286            pass.dispatch_workgroups(SIZE.x / WORKGROUP_SIZE, SIZE.y / WORKGROUP_SIZE, 1);
287        }
288    }
289}
Source

pub fn queue_render_pipeline( &self, descriptor: RenderPipelineDescriptor, ) -> CachedRenderPipelineId

Insert a render pipeline into the cache, and queue its creation.

The pipeline is always inserted and queued for creation. There is no attempt to deduplicate it with an already cached pipeline.

§Returns

This method returns the unique render shader ID of the cached pipeline, which can be used to query the caching state with get_render_pipeline_state() and to retrieve the created GPU pipeline once it’s ready with get_render_pipeline().

Examples found in repository?
examples/shader_advanced/custom_post_processing.rs (lines 244-260)
212fn init_post_process_pipeline(
213    mut commands: Commands,
214    render_device: Res<RenderDevice>,
215    asset_server: Res<AssetServer>,
216    fullscreen_shader: Res<FullscreenShader>,
217    pipeline_cache: Res<PipelineCache>,
218) {
219    // We need to define the bind group layout used for our pipeline
220    let layout = BindGroupLayoutDescriptor::new(
221        "post_process_bind_group_layout",
222        &BindGroupLayoutEntries::sequential(
223            // The layout entries will only be visible in the fragment stage
224            ShaderStages::FRAGMENT,
225            (
226                // The screen texture
227                texture_2d(TextureSampleType::Float { filterable: true }),
228                // The sampler that will be used to sample the screen texture
229                sampler(SamplerBindingType::Filtering),
230                // The settings uniform that will control the effect
231                uniform_buffer::<PostProcessSettings>(true),
232            ),
233        ),
234    );
235    // We can create the sampler here since it won't change at runtime and doesn't depend on the view
236    let sampler = render_device.create_sampler(&SamplerDescriptor::default());
237
238    // Get the shader handle
239    let shader = asset_server.load(SHADER_ASSET_PATH);
240    // This will setup a fullscreen triangle for the vertex state.
241    let vertex_state = fullscreen_shader.to_vertex_state();
242    let pipeline_id = pipeline_cache
243        // This will add the pipeline to the cache and queue its creation
244        .queue_render_pipeline(RenderPipelineDescriptor {
245            label: Some("post_process_pipeline".into()),
246            layout: vec![layout.clone()],
247            vertex: vertex_state,
248            fragment: Some(FragmentState {
249                shader,
250                // Make sure this matches the entry point of your shader.
251                // It can be anything as long as it matches here and in the shader.
252                targets: vec![Some(ColorTargetState {
253                    format: TextureFormat::Rgba8UnormSrgb,
254                    blend: None,
255                    write_mask: ColorWrites::ALL,
256                })],
257                ..default()
258            }),
259            ..default()
260        });
261    commands.insert_resource(PostProcessPipeline {
262        layout,
263        sampler,
264        pipeline_id,
265    });
266}
More examples
Hide additional examples
examples/shader_advanced/deferred_raymarch.rs (lines 164-187)
135fn init_raymarch_pipelines(
136    mut commands: Commands,
137    asset_server: Res<AssetServer>,
138    fullscreen_shader: Res<FullscreenShader>,
139    pipeline_cache: Res<PipelineCache>,
140) {
141    let layout = BindGroupLayoutDescriptor::new(
142        "raymarch_bind_group_layout",
143        &BindGroupLayoutEntries::sequential(
144            ShaderStages::FRAGMENT,
145            (
146                uniform_buffer::<ViewUniform>(true),
147                uniform_buffer::<GlobalsUniform>(false),
148            ),
149        ),
150    );
151
152    let shader = asset_server.load::<Shader>(SHADER_ASSET_PATH);
153    let vertex_state = fullscreen_shader.to_vertex_state();
154
155    // Writing depth lets the SDF sort against meshes
156    let depth_stencil = DepthStencilState {
157        format: CORE_3D_DEPTH_FORMAT,
158        depth_write_enabled: Some(true),
159        depth_compare: Some(CompareFunction::GreaterEqual),
160        stencil: StencilState::default(),
161        bias: DepthBiasState::default(),
162    };
163
164    let gbuffer_pipeline_id = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
165        label: Some("raymarch_gbuffer_pipeline".into()),
166        layout: vec![layout.clone()],
167        vertex: vertex_state.clone(),
168        fragment: Some(FragmentState {
169            shader: shader.clone(),
170            entry_point: Some("fragment".into()),
171            targets: vec![
172                Some(ColorTargetState {
173                    format: DEFERRED_PREPASS_FORMAT,
174                    blend: None,
175                    write_mask: ColorWrites::ALL,
176                }),
177                Some(ColorTargetState {
178                    format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
179                    blend: None,
180                    write_mask: ColorWrites::ALL,
181                }),
182            ],
183            ..default()
184        }),
185        depth_stencil: Some(depth_stencil.clone()),
186        ..default()
187    });
188
189    let shadow_pipeline_id = pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
190        label: Some("raymarch_shadow_pipeline".into()),
191        layout: vec![layout.clone()],
192        vertex: vertex_state,
193        fragment: Some(FragmentState {
194            shader,
195            entry_point: Some("fragment_shadow".into()),
196            targets: vec![],
197            ..default()
198        }),
199        depth_stencil: Some(depth_stencil),
200        ..default()
201    });
202
203    commands.insert_resource(RaymarchGBufferPipeline {
204        layout: layout.clone(),
205        pipeline_id: gbuffer_pipeline_id,
206    });
207    commands.insert_resource(RaymarchShadowPipeline {
208        layout,
209        pipeline_id: shadow_pipeline_id,
210    });
211}
Source

pub fn queue_compute_pipeline( &self, descriptor: ComputePipelineDescriptor, ) -> CachedComputePipelineId

Insert a compute pipeline into the cache, and queue its creation.

The pipeline is always inserted and queued for creation. There is no attempt to deduplicate it with an already cached pipeline.

§Returns

This method returns the unique compute shader ID of the cached pipeline, which can be used to query the caching state with get_compute_pipeline_state() and to retrieve the created GPU pipeline once it’s ready with get_compute_pipeline().

Examples found in repository?
examples/shader/gpu_readback.rs (lines 205-210)
189fn init_compute_pipeline(
190    mut commands: Commands,
191    asset_server: Res<AssetServer>,
192    pipeline_cache: Res<PipelineCache>,
193) {
194    let layout = BindGroupLayoutDescriptor::new(
195        "",
196        &BindGroupLayoutEntries::sequential(
197            ShaderStages::COMPUTE,
198            (
199                storage_buffer::<Vec<u32>>(false),
200                texture_storage_2d(TextureFormat::R32Uint, StorageTextureAccess::WriteOnly),
201            ),
202        ),
203    );
204    let shader = asset_server.load(SHADER_ASSET_PATH);
205    let pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
206        label: Some("GPU readback compute shader".into()),
207        layout: vec![layout.clone()],
208        shader: shader.clone(),
209        ..default()
210    });
211    commands.insert_resource(ComputePipeline { layout, pipeline });
212}
More examples
Hide additional examples
examples/shader_advanced/compute_mesh.rs (lines 235-240)
215fn init_compute_pipeline(
216    mut commands: Commands,
217    asset_server: Res<AssetServer>,
218    pipeline_cache: Res<PipelineCache>,
219) {
220    let layout = BindGroupLayoutDescriptor::new(
221        "",
222        &BindGroupLayoutEntries::sequential(
223            ShaderStages::COMPUTE,
224            (
225                // offsets
226                uniform_buffer::<DataRanges>(false),
227                // vertices
228                storage_buffer::<Vec<f32>>(false),
229                // indices
230                storage_buffer::<Vec<u32>>(false),
231            ),
232        ),
233    );
234    let shader = asset_server.load(SHADER_ASSET_PATH);
235    let pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
236        label: Some("Mesh generation compute shader".into()),
237        layout: vec![layout.clone()],
238        shader: shader.clone(),
239        ..default()
240    });
241    commands.insert_resource(ComputePipeline { layout, pipeline });
242}
examples/shader/compute_shader_game_of_life.rs (lines 193-198)
176fn init_game_of_life_pipeline(
177    mut commands: Commands,
178    asset_server: Res<AssetServer>,
179    pipeline_cache: Res<PipelineCache>,
180) {
181    let texture_bind_group_layout = BindGroupLayoutDescriptor::new(
182        "GameOfLifeImages",
183        &BindGroupLayoutEntries::sequential(
184            ShaderStages::COMPUTE,
185            (
186                texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::ReadOnly),
187                texture_storage_2d(TextureFormat::Rgba32Float, StorageTextureAccess::WriteOnly),
188                uniform_buffer::<GameOfLifeUniforms>(false),
189            ),
190        ),
191    );
192    let shader = asset_server.load(SHADER_ASSET_PATH);
193    let init_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
194        layout: vec![texture_bind_group_layout.clone()],
195        shader: shader.clone(),
196        entry_point: Some(Cow::from("init")),
197        ..default()
198    });
199    let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
200        layout: vec![texture_bind_group_layout.clone()],
201        shader,
202        entry_point: Some(Cow::from("update")),
203        ..default()
204    });
205
206    commands.insert_resource(GameOfLifePipeline {
207        texture_bind_group_layout,
208        init_pipeline,
209        update_pipeline,
210    });
211}
Source

pub fn queue_mesh_pipeline( &self, descriptor: MeshPipelineDescriptor, ) -> CachedRenderPipelineId

Insert a mesh pipeline into the cache, and queue its creation.

The pipeline is always inserted and queued for creation. There is no attempt to deduplicate it with an already cached pipeline.

§Returns

This method returns the unique mesh shader ID of the cached pipeline, which can be used to query the caching state with get_render_pipeline_state() and to retrieve the created GPU pipeline once it’s ready with get_render_pipeline().

Examples found in repository?
examples/shader_advanced/mesh_shader_intro.rs (lines 157-185)
129fn init_mesh_pipelines(
130    mut commands: Commands,
131    asset_server: Res<AssetServer>,
132    pipeline_cache: Res<PipelineCache>,
133) {
134    let task_shader = asset_server.load::<Shader>("shaders/mesh_shader_intro/task.wesl");
135    let mesh_shader = asset_server.load::<Shader>("shaders/mesh_shader_intro/mesh.wesl");
136    let fragment_shader = asset_server.load::<Shader>("shaders/mesh_shader_intro/fragment.wesl");
137
138    let layout = BindGroupLayoutDescriptor::new(
139        "custom_mesh_shader_bind_group_layout",
140        &BindGroupLayoutEntries::sequential(
141            ShaderStages::MESH | ShaderStages::TASK | ShaderStages::FRAGMENT,
142            (
143                uniform_buffer::<GlobalsUniform>(false),
144                uniform_buffer::<ViewUniform>(true),
145            ),
146        ),
147    );
148
149    let depth_stencil = DepthStencilState {
150        format: CORE_3D_DEPTH_FORMAT,
151        depth_write_enabled: Some(true),
152        depth_compare: Some(CompareFunction::GreaterEqual),
153        stencil: StencilState::default(),
154        bias: DepthBiasState::default(),
155    };
156
157    let cached_pipeline_id = pipeline_cache.queue_mesh_pipeline(MeshPipelineDescriptor {
158        label: Some("custom_mesh_shader_pipeline".into()),
159        layout: vec![layout.clone()],
160        immediate_size: 0,
161        task: Some(TaskState {
162            shader: task_shader,
163            entry_point: Some("task".into()),
164            ..default()
165        }),
166        mesh: MeshState {
167            shader: mesh_shader,
168            entry_point: Some("mesh".into()),
169            ..default()
170        },
171        primitive: Default::default(),
172        depth_stencil: Some(depth_stencil),
173        multisample: Default::default(),
174        fragment: Some(FragmentState {
175            shader: fragment_shader,
176            entry_point: Some("fragment".into()),
177            targets: vec![Some(ColorTargetState {
178                format: TextureFormat::Rgba8UnormSrgb,
179                blend: None,
180                write_mask: ColorWrites::ALL,
181            })],
182            ..default()
183        }),
184        zero_initialize_workgroup_memory: false,
185    });
186
187    commands.insert_resource(MyMeshShaderDrawNode {
188        mesh_pipeline: cached_pipeline_id,
189        layout,
190    });
191}
Source

pub fn get_bind_group_layout( &self, bind_group_layout_descriptor: &BindGroupLayoutDescriptor, ) -> BindGroupLayout

Examples found in repository?
examples/shader_advanced/deferred_raymarch.rs (line 224)
213fn raymarch_bind_group(
214    ctx: &RenderContext,
215    pipeline_cache: &PipelineCache,
216    layout: &BindGroupLayoutDescriptor,
217    view_uniforms: &ViewUniforms,
218    globals: &GlobalsBuffer,
219) -> Option<BindGroup> {
220    let view_binding = view_uniforms.uniforms.binding()?;
221    let globals_binding = globals.buffer.binding()?;
222    Some(ctx.render_device().create_bind_group(
223        "raymarch_bind_group",
224        &pipeline_cache.get_bind_group_layout(layout),
225        &BindGroupEntries::sequential((view_binding, globals_binding)),
226    ))
227}
More examples
Hide additional examples
examples/shader/gpu_readback.rs (line 174)
160fn prepare_bind_group(
161    mut commands: Commands,
162    pipeline: Res<ComputePipeline>,
163    render_device: Res<RenderDevice>,
164    pipeline_cache: Res<PipelineCache>,
165    buffer: Res<ReadbackBuffer>,
166    image: Res<ReadbackImage>,
167    buffers: Res<RenderAssets<GpuShaderBuffer>>,
168    images: Res<RenderAssets<GpuImage>>,
169) {
170    let buffer = buffers.get(&buffer.0).unwrap();
171    let image = images.get(&image.0).unwrap();
172    let bind_group = render_device.create_bind_group(
173        None,
174        &pipeline_cache.get_bind_group_layout(&pipeline.layout),
175        &BindGroupEntries::sequential((
176            buffer.buffer.as_entire_buffer_binding(),
177            image.texture_view.into_binding(),
178        )),
179    );
180    commands.insert_resource(GpuBufferBindGroup(bind_group));
181}
examples/shader/compute_shader_game_of_life.rs (line 150)
130fn prepare_bind_group(
131    mut commands: Commands,
132    pipeline: Res<GameOfLifePipeline>,
133    gpu_images: Res<RenderAssets<GpuImage>>,
134    game_of_life_images: Res<GameOfLifeImages>,
135    game_of_life_uniforms: Res<GameOfLifeUniforms>,
136    render_device: Res<RenderDevice>,
137    pipeline_cache: Res<PipelineCache>,
138    queue: Res<RenderQueue>,
139) {
140    let view_a = gpu_images.get(&game_of_life_images.texture_a).unwrap();
141    let view_b = gpu_images.get(&game_of_life_images.texture_b).unwrap();
142
143    // Uniform buffer is used here to demonstrate how to set up a uniform in a compute shader
144    // Alternatives such as storage buffers or push constants may be more suitable for your use case
145    let mut uniform_buffer = UniformBuffer::from(game_of_life_uniforms.into_inner());
146    uniform_buffer.write_buffer(&render_device, &queue);
147
148    let bind_group_0 = render_device.create_bind_group(
149        None,
150        &pipeline_cache.get_bind_group_layout(&pipeline.texture_bind_group_layout),
151        &BindGroupEntries::sequential((
152            &view_a.texture_view,
153            &view_b.texture_view,
154            &uniform_buffer,
155        )),
156    );
157    let bind_group_1 = render_device.create_bind_group(
158        None,
159        &pipeline_cache.get_bind_group_layout(&pipeline.texture_bind_group_layout),
160        &BindGroupEntries::sequential((
161            &view_b.texture_view,
162            &view_a.texture_view,
163            &uniform_buffer,
164        )),
165    );
166    commands.insert_resource(GameOfLifeImageBindGroups([bind_group_0, bind_group_1]));
167}
examples/shader_advanced/texture_binding_array.rs (line 138)
105    fn as_bind_group(
106        &self,
107        layout: &BindGroupLayoutDescriptor,
108        render_device: &RenderDevice,
109        pipeline_cache: &PipelineCache,
110        _: &FallbackBuffer,
111        shader_buffer_assets: &RenderAssets<GpuShaderBuffer>,
112        (image_assets, fallback_image): &mut SystemParamItem<'_, '_, Self::Param>,
113    ) -> Result<PreparedBindGroup, AsBindGroupError> {
114        let _ = shader_buffer_assets;
115        // retrieve the render resources from handles
116        let mut images = vec![];
117        for handle in self.textures.iter().take(MAX_TEXTURE_COUNT) {
118            match image_assets.get(handle) {
119                Some(image) => images.push(image),
120                None => return Err(AsBindGroupError::RetryNextUpdate),
121            }
122        }
123
124        let fallback_image = &fallback_image.d2;
125
126        let textures = vec![&fallback_image.texture_view; MAX_TEXTURE_COUNT];
127
128        // convert bevy's resource types to WGPU's references
129        let mut textures: Vec<_> = textures.into_iter().map(|texture| &**texture).collect();
130
131        // fill in up to the first `MAX_TEXTURE_COUNT` textures and samplers to the arrays
132        for (id, image) in images.into_iter().enumerate() {
133            textures[id] = &*image.texture_view;
134        }
135
136        let bind_group = render_device.create_bind_group(
137            Self::label(),
138            &pipeline_cache.get_bind_group_layout(layout),
139            &BindGroupEntries::sequential((&textures[..], &fallback_image.sampler)),
140        );
141
142        Ok(PreparedBindGroup {
143            bindings: BindingResources(vec![]),
144            bind_group,
145        })
146    }
examples/shader_advanced/custom_post_processing.rs (line 108)
88fn prepare_bind_groups(
89    mut commands: Commands,
90    mut views: Query<(Entity, &ViewTarget, Option<&mut PostProcessBindGroups>)>,
91    post_process_pipeline: Option<Res<PostProcessPipeline>>,
92    pipeline_cache: Res<PipelineCache>,
93    settings_uniforms: Res<ComponentUniforms<PostProcessSettings>>,
94    render_device: Res<RenderDevice>,
95) {
96    let Some(post_process_pipeline) = post_process_pipeline else {
97        return;
98    };
99    let Some(settings_binding) = settings_uniforms.uniforms().binding() else {
100        return;
101    };
102
103    let create_bind_group = |texture: &TextureView| {
104        (
105            texture.id(),
106            render_device.create_bind_group(
107                "post_process_bind_group",
108                &pipeline_cache.get_bind_group_layout(&post_process_pipeline.layout),
109                &BindGroupEntries::sequential((
110                    texture,
111                    &post_process_pipeline.sampler,
112                    settings_binding.clone(),
113                )),
114            ),
115        )
116    };
117
118    for (entity, view_target, mut maybe_bind_groups) in &mut views {
119        let main_texture_view = view_target.main_texture_view();
120        let main_texture_other_view = view_target.main_texture_other_view();
121
122        // Only update the cached bind groups if the main texture has changed
123        if let Some(bind_groups) = &mut maybe_bind_groups {
124            if bind_groups.a.0 != main_texture_view.id() {
125                bind_groups.a = create_bind_group(main_texture_view);
126            }
127            if bind_groups.b.0 != main_texture_other_view.id() {
128                bind_groups.b = create_bind_group(main_texture_other_view);
129            }
130        } else {
131            // Create the bind groups and add them to the view
132            commands.entity(entity).insert(PostProcessBindGroups {
133                a: create_bind_group(main_texture_view),
134                b: create_bind_group(main_texture_other_view),
135            });
136        }
137    }
138}
examples/shader_advanced/mesh_shader_intro.rs (line 230)
202fn draw_mesh_shader_cubes(
203    mut views: Query<(
204        &ExtractedCamera,
205        &ExtractedView,
206        &ViewTarget,
207        &ViewDepthStencilTexture,
208        &ViewUniformOffset,
209        Option<&MainPassResolutionOverride>,
210    )>,
211    mut render_context: RenderContext,
212    data: Res<MyMeshShaderDrawNode>,
213    view_uniforms: Res<ViewUniforms>,
214    globals: Res<GlobalsBuffer>,
215    pipeline_cache: Res<PipelineCache>,
216) {
217    let Some(mesh_pipeline) = pipeline_cache.get_render_pipeline(data.mesh_pipeline) else {
218        return;
219    };
220
221    for (camera, _, target, depth, view_uniform_offset, resolution_override) in &mut views {
222        let Some(view_binding) = view_uniforms.uniforms.binding() else {
223            return;
224        };
225        let Some(globals_binding) = globals.buffer.binding() else {
226            return;
227        };
228        let bind_group = render_context.render_device().create_bind_group(
229            "custom_task_mesh_bind_group",
230            &pipeline_cache.get_bind_group_layout(&data.layout),
231            &BindGroupEntries::sequential((globals_binding, view_binding)),
232        );
233
234        {
235            let mut pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
236                label: Some("custom_mesh_shader_pass"),
237                // Write directly to the view target
238                color_attachments: &[Some(target.get_color_attachment())],
239                depth_stencil_attachment: Some(depth.get_attachment(StoreOp::Store)),
240                timestamp_writes: None,
241                occlusion_query_set: None,
242                multiview_mask: None,
243            });
244
245            pass.set_render_pipeline(mesh_pipeline);
246            pass.set_bind_group(0, &bind_group, &[view_uniform_offset.offset]);
247            if let Some(viewport) =
248                Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
249            {
250                pass.set_camera_viewport(&viewport);
251            }
252
253            // Since this MeshPipeline has a task shader, this call
254            // dispatches the task shader workgroup
255            pass.draw_mesh_tasks(1, 1, 1);
256        }
257    }
258}
Source

pub fn set_shader(&mut self, id: AssetId<Shader>, shader: Shader)

Inserts a Shader into this cache with the provided AssetId.

Source

pub fn remove_shader(&mut self, shader: AssetId<Shader>)

Removes a Shader from this cache if it exists.

Source

pub fn process_queue(&mut self)

Process the pipeline queue and create all pending pipelines if possible.

This is generally called automatically during the RenderSystems::Render step, but can be called manually to force creation at a different time.

Trait Implementations§

Source§

impl Component for PipelineCache
where PipelineCache: Send + Sync + 'static,

Source§

const STORAGE_TYPE: StorageType = bevy_ecs::component::StorageType::SparseSet

A constant indicating the storage type used for this component.
Source§

type Mutability = Mutable

A marker type to assist Bevy with determining if this component is mutable, or immutable. Mutable components will have Component<Mutability = Mutable>, while immutable components will instead have Component<Mutability = Immutable>. Read more
Source§

fn register_required_components( _requiree: ComponentId, required_components: &mut RequiredComponentsRegistrator<'_, '_>, )

Registers required components. Read more
Source§

fn clone_behavior() -> ComponentCloneBehavior

Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component. Read more
Source§

fn relationship_accessor() -> Option<ComponentRelationshipAccessor<PipelineCache>>

Returns ComponentRelationshipAccessor required for working with relationships in dynamic contexts. Read more
Source§

fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_add ComponentHook for this Component if one is defined.
Source§

fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_insert ComponentHook for this Component if one is defined.
Source§

fn on_discard() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_discard ComponentHook for this Component if one is defined.
Source§

fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_remove ComponentHook for this Component if one is defined.
Source§

fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_despawn ComponentHook for this Component if one is defined.
Source§

fn map_entities<E>(_this: &mut Self, _mapper: &mut E)
where E: EntityMapper,

Maps the entities on this component using the given EntityMapper. This is used to remap entities in contexts like scenes and entity cloning. When deriving Component, this is populated by annotating fields containing entities with #[entities] Read more
Source§

const HAS_SUMMARY_TICK: bool = false

Set this constant to true if the component should track a summary tick. Read more
Source§

impl Resource for PipelineCache
where PipelineCache: Send + Sync + 'static,

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<C> Bundle for C
where C: Component,

Source§

fn component_ids( components: &mut ComponentsRegistrator<'_>, ) -> impl Iterator<Item = ComponentId> + use<C>

Source§

fn get_component_ids( components: &Components, ) -> impl Iterator<Item = Option<ComponentId>>

Returns an iterator over this Bundle’s component ids. This will be None if the component has not been registered.
Source§

impl<C> BundleFromComponents for C
where C: Component,

Source§

unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> C
where F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>, C: Sized,

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<C> DynamicBundle for C
where C: Component,

Source§

type Effect = ()

An operation on the entity that happens after inserting this bundle.
Source§

unsafe fn get_components( ptr: MovingPtr<'_, C>, func: &mut impl FnMut(StorageType, OwningPtr<'_>), ) -> <C as DynamicBundle>::Effect

Moves the components out of the bundle. Read more
Source§

unsafe fn apply_effect( _ptr: MovingPtr<'_, MaybeUninit<C>>, _entity: &mut EntityWorldMut<'_>, )

Applies the after-effects of spawning this bundle. Read more
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<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<C> SceneEffect for C
where C: Component,

Source§

fn apply( self, context: &mut TemplateContext<'_, '_>, bundle_writer: &mut BundleWriter<'_>, )

Applies the scene effect to the current context.
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 = !

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

fn try_from(value: U) -> Result<T, !>

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