bevy_render/render_phase/
draw_state.rs

1use crate::{
2    diagnostic::internal::{Pass, PassKind, WritePipelineStatistics, WriteTimestamp},
3    render_resource::{
4        BindGroup, BindGroupId, Buffer, BufferId, BufferSlice, RenderPipeline, RenderPipelineId,
5        ShaderStages,
6    },
7    renderer::RenderDevice,
8};
9use bevy_camera::Viewport;
10use bevy_color::LinearRgba;
11use bevy_utils::default;
12use core::ops::Range;
13use wgpu::{IndexFormat, QuerySet, RenderPass};
14
15#[cfg(feature = "detailed_trace")]
16use tracing::trace;
17
18type BufferSliceKey = (BufferId, wgpu::BufferAddress, wgpu::BufferSize);
19
20/// Tracks the state of a [`TrackedRenderPass`].
21///
22/// This is used to skip redundant operations on the [`TrackedRenderPass`] (e.g. setting an already
23/// set pipeline, binding an already bound bind group). These operations can otherwise be fairly
24/// costly due to IO to the GPU, so deduplicating these calls results in a speedup.
25#[derive(Debug, Default)]
26struct DrawState {
27    pipeline: Option<RenderPipelineId>,
28    bind_groups: Vec<(Option<BindGroupId>, Vec<u32>)>,
29    /// List of vertex buffers by [`BufferId`], offset, and size. See [`DrawState::buffer_slice_key`]
30    vertex_buffers: Vec<Option<BufferSliceKey>>,
31    index_buffer: Option<(BufferSliceKey, IndexFormat)>,
32
33    /// Stores whether this state is populated or empty for quick state invalidation
34    stores_state: bool,
35}
36
37impl DrawState {
38    /// Marks the `pipeline` as bound.
39    fn set_pipeline(&mut self, pipeline: RenderPipelineId) {
40        // TODO: do these need to be cleared?
41        // self.bind_groups.clear();
42        // self.vertex_buffers.clear();
43        // self.index_buffer = None;
44        self.pipeline = Some(pipeline);
45        self.stores_state = true;
46    }
47
48    /// Checks, whether the `pipeline` is already bound.
49    fn is_pipeline_set(&self, pipeline: RenderPipelineId) -> bool {
50        self.pipeline == Some(pipeline)
51    }
52
53    /// Marks the `bind_group` as bound to the `index`.
54    fn set_bind_group(&mut self, index: usize, bind_group: BindGroupId, dynamic_indices: &[u32]) {
55        let group = &mut self.bind_groups[index];
56        group.0 = Some(bind_group);
57        group.1.clear();
58        group.1.extend(dynamic_indices);
59        self.stores_state = true;
60    }
61
62    /// Checks, whether the `bind_group` is already bound to the `index`.
63    fn is_bind_group_set(
64        &self,
65        index: usize,
66        bind_group: BindGroupId,
67        dynamic_indices: &[u32],
68    ) -> bool {
69        if let Some(current_bind_group) = self.bind_groups.get(index) {
70            current_bind_group.0 == Some(bind_group) && dynamic_indices == current_bind_group.1
71        } else {
72            false
73        }
74    }
75
76    /// Marks the vertex `buffer` as bound to the `index`.
77    fn set_vertex_buffer(&mut self, index: usize, buffer_slice: BufferSlice) {
78        self.vertex_buffers[index] = Some(self.buffer_slice_key(&buffer_slice));
79        self.stores_state = true;
80    }
81
82    /// Checks, whether the vertex `buffer` is already bound to the `index`.
83    fn is_vertex_buffer_set(&self, index: usize, buffer_slice: &BufferSlice) -> bool {
84        if let Some(current) = self.vertex_buffers.get(index) {
85            *current == Some(self.buffer_slice_key(buffer_slice))
86        } else {
87            false
88        }
89    }
90
91    /// Returns the value used for checking whether `BufferSlice`s are equivalent.
92    fn buffer_slice_key(&self, buffer_slice: &BufferSlice) -> BufferSliceKey {
93        (
94            buffer_slice.id(),
95            buffer_slice.offset(),
96            buffer_slice.size(),
97        )
98    }
99
100    /// Marks the index `buffer` as bound.
101    fn set_index_buffer(&mut self, buffer_slice: &BufferSlice, index_format: IndexFormat) {
102        self.index_buffer = Some((self.buffer_slice_key(buffer_slice), index_format));
103        self.stores_state = true;
104    }
105
106    /// Checks, whether the index `buffer` is already bound.
107    fn is_index_buffer_set(&self, buffer: &BufferSlice, index_format: IndexFormat) -> bool {
108        self.index_buffer == Some((self.buffer_slice_key(buffer), index_format))
109    }
110
111    /// Resets tracking state
112    pub fn reset_tracking(&mut self) {
113        if !self.stores_state {
114            return;
115        }
116        self.pipeline = None;
117        self.bind_groups.iter_mut().for_each(|val| {
118            val.0 = None;
119            val.1.clear();
120        });
121        self.vertex_buffers.iter_mut().for_each(|val| {
122            *val = None;
123        });
124        self.index_buffer = None;
125        self.stores_state = false;
126    }
127}
128
129/// A [`RenderPass`], which tracks the current pipeline state to skip redundant operations.
130///
131/// It is used to set the current [`RenderPipeline`], [`BindGroup`]s and [`Buffer`]s.
132/// After all requirements are specified, draw calls can be issued.
133pub struct TrackedRenderPass<'a> {
134    pass: RenderPass<'a>,
135    state: DrawState,
136}
137
138impl<'a> TrackedRenderPass<'a> {
139    /// Tracks the supplied render pass.
140    pub fn new(device: &RenderDevice, pass: RenderPass<'a>) -> Self {
141        let limits = device.limits();
142        let max_bind_groups = limits.max_bind_groups as usize;
143        let max_vertex_buffers = limits.max_vertex_buffers as usize;
144        Self {
145            state: DrawState {
146                bind_groups: vec![(None, Vec::new()); max_bind_groups],
147                vertex_buffers: vec![None; max_vertex_buffers],
148                ..default()
149            },
150            pass,
151        }
152    }
153
154    /// Returns the wgpu [`RenderPass`].
155    ///
156    /// Function invalidates internal tracking state,
157    /// some redundant pipeline operations may not be skipped.
158    pub fn wgpu_pass(&mut self) -> &mut RenderPass<'a> {
159        self.state.reset_tracking();
160        &mut self.pass
161    }
162
163    /// Sets the active [`RenderPipeline`].
164    ///
165    /// Subsequent draw calls will exhibit the behavior defined by the `pipeline`.
166    pub fn set_render_pipeline(&mut self, pipeline: &'a RenderPipeline) {
167        #[cfg(feature = "detailed_trace")]
168        trace!("set pipeline: {:?}", pipeline);
169        if self.state.is_pipeline_set(pipeline.id()) {
170            return;
171        }
172        self.pass.set_pipeline(pipeline);
173        self.state.set_pipeline(pipeline.id());
174    }
175
176    /// Sets the active bind group for a given bind group index. The bind group layout
177    /// in the active pipeline when any `draw()` function is called must match the layout of
178    /// this bind group.
179    ///
180    /// If the bind group have dynamic offsets, provide them in binding order.
181    /// These offsets have to be aligned to [`WgpuLimits::min_uniform_buffer_offset_alignment`](crate::settings::WgpuLimits::min_uniform_buffer_offset_alignment)
182    /// or [`WgpuLimits::min_storage_buffer_offset_alignment`](crate::settings::WgpuLimits::min_storage_buffer_offset_alignment) appropriately.
183    pub fn set_bind_group(
184        &mut self,
185        index: usize,
186        bind_group: &'a BindGroup,
187        dynamic_uniform_indices: &[u32],
188    ) {
189        if self
190            .state
191            .is_bind_group_set(index, bind_group.id(), dynamic_uniform_indices)
192        {
193            #[cfg(feature = "detailed_trace")]
194            trace!(
195                "set bind_group {} (already set): {:?} ({:?})",
196                index,
197                bind_group,
198                dynamic_uniform_indices
199            );
200            return;
201        }
202        #[cfg(feature = "detailed_trace")]
203        trace!(
204            "set bind_group {}: {:?} ({:?})",
205            index,
206            bind_group,
207            dynamic_uniform_indices
208        );
209
210        self.pass
211            .set_bind_group(index as u32, bind_group, dynamic_uniform_indices);
212        self.state
213            .set_bind_group(index, bind_group.id(), dynamic_uniform_indices);
214    }
215
216    /// Assign a vertex buffer to a slot.
217    ///
218    /// Subsequent calls to [`draw`] and [`draw_indexed`] on this
219    /// [`TrackedRenderPass`] will use `buffer` as one of the source vertex buffers.
220    ///
221    /// The `slot_index` refers to the index of the matching descriptor in
222    /// [`VertexState::buffers`](crate::render_resource::VertexState::buffers).
223    ///
224    /// [`draw`]: TrackedRenderPass::draw
225    /// [`draw_indexed`]: TrackedRenderPass::draw_indexed
226    pub fn set_vertex_buffer(&mut self, slot_index: usize, buffer_slice: BufferSlice<'a>) {
227        if self.state.is_vertex_buffer_set(slot_index, &buffer_slice) {
228            #[cfg(feature = "detailed_trace")]
229            trace!(
230                "set vertex buffer {} (already set): {:?} (offset = {}, size = {})",
231                slot_index,
232                buffer_slice.id(),
233                buffer_slice.offset(),
234                buffer_slice.size(),
235            );
236            return;
237        }
238        #[cfg(feature = "detailed_trace")]
239        trace!(
240            "set vertex buffer {}: {:?} (offset = {}, size = {})",
241            slot_index,
242            buffer_slice.id(),
243            buffer_slice.offset(),
244            buffer_slice.size(),
245        );
246
247        self.pass
248            .set_vertex_buffer(slot_index as u32, *buffer_slice);
249        self.state.set_vertex_buffer(slot_index, buffer_slice);
250    }
251
252    /// Sets the active index buffer.
253    ///
254    /// Subsequent calls to [`TrackedRenderPass::draw_indexed`] will use the buffer referenced by
255    /// `buffer_slice` as the source index buffer.
256    pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
257        let already_set = self.state.is_index_buffer_set(&buffer_slice, index_format);
258        #[cfg(feature = "detailed_trace")]
259        trace!(
260            "set index buffer{}: {:?} (offset = {}, size = {})",
261            if already_set { " (already set)" } else { "" },
262            buffer_slice.id(),
263            buffer_slice.offset(),
264            buffer_slice.size(),
265        );
266        if already_set {
267            return;
268        }
269        self.pass.set_index_buffer(*buffer_slice, index_format);
270        self.state.set_index_buffer(&buffer_slice, index_format);
271    }
272
273    /// Draws primitives from the active vertex buffer(s).
274    ///
275    /// The active vertex buffer(s) can be set with [`TrackedRenderPass::set_vertex_buffer`].
276    pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
277        #[cfg(feature = "detailed_trace")]
278        trace!("draw: {:?} {:?}", vertices, instances);
279        self.pass.draw(vertices, instances);
280    }
281
282    /// Draws indexed primitives using the active index buffer and the active vertex buffer(s).
283    ///
284    /// The active index buffer can be set with [`TrackedRenderPass::set_index_buffer`], while the
285    /// active vertex buffer(s) can be set with [`TrackedRenderPass::set_vertex_buffer`].
286    pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
287        #[cfg(feature = "detailed_trace")]
288        trace!(
289            "draw indexed: {:?} {} {:?}",
290            indices,
291            base_vertex,
292            instances
293        );
294        self.pass.draw_indexed(indices, base_vertex, instances);
295    }
296
297    /// Draws primitives from the active vertex buffer(s) based on the contents of the
298    /// `indirect_buffer`.
299    ///
300    /// The active vertex buffers can be set with [`TrackedRenderPass::set_vertex_buffer`].
301    ///
302    /// The structure expected in `indirect_buffer` is the following:
303    ///
304    /// ```
305    /// #[repr(C)]
306    /// struct DrawIndirect {
307    ///     vertex_count: u32, // The number of vertices to draw.
308    ///     instance_count: u32, // The number of instances to draw.
309    ///     first_vertex: u32, // The Index of the first vertex to draw.
310    ///     first_instance: u32, // The instance ID of the first instance to draw.
311    ///     // has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`] is enabled.
312    /// }
313    /// ```
314    pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: u64) {
315        #[cfg(feature = "detailed_trace")]
316        trace!("draw indirect: {:?} {}", indirect_buffer, indirect_offset);
317        self.pass.draw_indirect(indirect_buffer, indirect_offset);
318    }
319
320    /// Draws indexed primitives using the active index buffer and the active vertex buffers,
321    /// based on the contents of the `indirect_buffer`.
322    ///
323    /// The active index buffer can be set with [`TrackedRenderPass::set_index_buffer`], while the
324    /// active vertex buffers can be set with [`TrackedRenderPass::set_vertex_buffer`].
325    ///
326    /// The structure expected in `indirect_buffer` is the following:
327    ///
328    /// ```
329    /// #[repr(C)]
330    /// struct DrawIndexedIndirect {
331    ///     vertex_count: u32, // The number of vertices to draw.
332    ///     instance_count: u32, // The number of instances to draw.
333    ///     first_index: u32, // The base index within the index buffer.
334    ///     vertex_offset: i32, // The value added to the vertex index before indexing into the vertex buffer.
335    ///     first_instance: u32, // The instance ID of the first instance to draw.
336    ///     // has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`] is enabled.
337    /// }
338    /// ```
339    pub fn draw_indexed_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: u64) {
340        #[cfg(feature = "detailed_trace")]
341        trace!(
342            "draw indexed indirect: {:?} {}",
343            indirect_buffer,
344            indirect_offset
345        );
346        self.pass
347            .draw_indexed_indirect(indirect_buffer, indirect_offset);
348    }
349
350    /// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of the
351    /// `indirect_buffer`.`count` draw calls are issued.
352    ///
353    /// The active vertex buffers can be set with [`TrackedRenderPass::set_vertex_buffer`].
354    ///
355    /// `indirect_buffer` should contain `count` tightly packed elements of the following structure:
356    ///
357    /// ```
358    /// #[repr(C)]
359    /// struct DrawIndirect {
360    ///     vertex_count: u32, // The number of vertices to draw.
361    ///     instance_count: u32, // The number of instances to draw.
362    ///     first_vertex: u32, // The Index of the first vertex to draw.
363    ///     first_instance: u32, // The instance ID of the first instance to draw.
364    ///     // has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`] is enabled.
365    /// }
366    /// ```
367    pub fn multi_draw_indirect(
368        &mut self,
369        indirect_buffer: &'a Buffer,
370        indirect_offset: u64,
371        count: u32,
372    ) {
373        #[cfg(feature = "detailed_trace")]
374        trace!(
375            "multi draw indirect: {:?} {}, {}x",
376            indirect_buffer,
377            indirect_offset,
378            count
379        );
380        self.pass
381            .multi_draw_indirect(indirect_buffer, indirect_offset, count);
382    }
383
384    /// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of
385    /// the `indirect_buffer`.
386    /// The count buffer is read to determine how many draws to issue.
387    ///
388    /// The indirect buffer must be long enough to account for `max_count` draws, however only
389    /// `count` elements will be read, where `count` is the value read from `count_buffer` capped
390    /// at `max_count`.
391    ///
392    /// The active vertex buffers can be set with [`TrackedRenderPass::set_vertex_buffer`].
393    ///
394    /// `indirect_buffer` should contain `count` tightly packed elements of the following structure:
395    ///
396    /// ```
397    /// #[repr(C)]
398    /// struct DrawIndirect {
399    ///     vertex_count: u32, // The number of vertices to draw.
400    ///     instance_count: u32, // The number of instances to draw.
401    ///     first_vertex: u32, // The Index of the first vertex to draw.
402    ///     first_instance: u32, // The instance ID of the first instance to draw.
403    ///     // has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`] is enabled.
404    /// }
405    /// ```
406    pub fn multi_draw_indirect_count(
407        &mut self,
408        indirect_buffer: &'a Buffer,
409        indirect_offset: u64,
410        count_buffer: &'a Buffer,
411        count_offset: u64,
412        max_count: u32,
413    ) {
414        #[cfg(feature = "detailed_trace")]
415        trace!(
416            "multi draw indirect count: {:?} {}, ({:?} {})x, max {}x",
417            indirect_buffer,
418            indirect_offset,
419            count_buffer,
420            count_offset,
421            max_count
422        );
423        self.pass.multi_draw_indirect_count(
424            indirect_buffer,
425            indirect_offset,
426            count_buffer,
427            count_offset,
428            max_count,
429        );
430    }
431
432    /// Dispatches multiple draw calls from the active index buffer and the active vertex buffers,
433    /// based on the contents of the `indirect_buffer`. `count` draw calls are issued.
434    ///
435    /// The active index buffer can be set with [`TrackedRenderPass::set_index_buffer`], while the
436    /// active vertex buffers can be set with [`TrackedRenderPass::set_vertex_buffer`].
437    ///
438    /// `indirect_buffer` should contain `count` tightly packed elements of the following structure:
439    ///
440    /// ```
441    /// #[repr(C)]
442    /// struct DrawIndexedIndirect {
443    ///     vertex_count: u32, // The number of vertices to draw.
444    ///     instance_count: u32, // The number of instances to draw.
445    ///     first_index: u32, // The base index within the index buffer.
446    ///     vertex_offset: i32, // The value added to the vertex index before indexing into the vertex buffer.
447    ///     first_instance: u32, // The instance ID of the first instance to draw.
448    ///     // has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`] is enabled.
449    /// }
450    /// ```
451    pub fn multi_draw_indexed_indirect(
452        &mut self,
453        indirect_buffer: &'a Buffer,
454        indirect_offset: u64,
455        count: u32,
456    ) {
457        #[cfg(feature = "detailed_trace")]
458        trace!(
459            "multi draw indexed indirect: {:?} {}, {}x",
460            indirect_buffer,
461            indirect_offset,
462            count
463        );
464        self.pass
465            .multi_draw_indexed_indirect(indirect_buffer, indirect_offset, count);
466    }
467
468    /// Dispatches multiple draw calls from the active index buffer and the active vertex buffers,
469    /// based on the contents of the `indirect_buffer`.
470    /// The count buffer is read to determine how many draws to issue.
471    ///
472    /// The indirect buffer must be long enough to account for `max_count` draws, however only
473    /// `count` elements will be read, where `count` is the value read from `count_buffer` capped
474    /// at `max_count`.
475    ///
476    /// The active index buffer can be set with [`TrackedRenderPass::set_index_buffer`], while the
477    /// active vertex buffers can be set with [`TrackedRenderPass::set_vertex_buffer`].
478    ///
479    /// `indirect_buffer` should contain `count` tightly packed elements of the following structure:
480    ///
481    /// ```
482    /// #[repr(C)]
483    /// struct DrawIndexedIndirect {
484    ///     vertex_count: u32, // The number of vertices to draw.
485    ///     instance_count: u32, // The number of instances to draw.
486    ///     first_index: u32, // The base index within the index buffer.
487    ///     vertex_offset: i32, // The value added to the vertex index before indexing into the vertex buffer.
488    ///     first_instance: u32, // The instance ID of the first instance to draw.
489    ///     // has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`] is enabled.
490    /// }
491    /// ```
492    pub fn multi_draw_indexed_indirect_count(
493        &mut self,
494        indirect_buffer: &'a Buffer,
495        indirect_offset: u64,
496        count_buffer: &'a Buffer,
497        count_offset: u64,
498        max_count: u32,
499    ) {
500        #[cfg(feature = "detailed_trace")]
501        trace!(
502            "multi draw indexed indirect count: {:?} {}, ({:?} {})x, max {}x",
503            indirect_buffer,
504            indirect_offset,
505            count_buffer,
506            count_offset,
507            max_count
508        );
509        self.pass.multi_draw_indexed_indirect_count(
510            indirect_buffer,
511            indirect_offset,
512            count_buffer,
513            count_offset,
514            max_count,
515        );
516    }
517
518    /// Sets the stencil reference.
519    ///
520    /// Subsequent stencil tests will test against this value.
521    pub fn set_stencil_reference(&mut self, reference: u32) {
522        #[cfg(feature = "detailed_trace")]
523        trace!("set stencil reference: {}", reference);
524        self.pass.set_stencil_reference(reference);
525    }
526
527    /// Sets the scissor region.
528    ///
529    /// Subsequent draw calls will discard any fragments that fall outside this region.
530    pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
531        #[cfg(feature = "detailed_trace")]
532        trace!("set_scissor_rect: {} {} {} {}", x, y, width, height);
533        self.pass.set_scissor_rect(x, y, width, height);
534    }
535
536    /// Set push constant data.
537    ///
538    /// `Features::PUSH_CONSTANTS` must be enabled on the device in order to call these functions.
539    pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
540        #[cfg(feature = "detailed_trace")]
541        trace!(
542            "set push constants: {:?} offset: {} data.len: {}",
543            stages,
544            offset,
545            data.len()
546        );
547        self.pass.set_push_constants(stages, offset, data);
548    }
549
550    /// Set the rendering viewport.
551    ///
552    /// Subsequent draw calls will be projected into that viewport.
553    pub fn set_viewport(
554        &mut self,
555        x: f32,
556        y: f32,
557        width: f32,
558        height: f32,
559        min_depth: f32,
560        max_depth: f32,
561    ) {
562        #[cfg(feature = "detailed_trace")]
563        trace!(
564            "set viewport: {} {} {} {} {} {}",
565            x,
566            y,
567            width,
568            height,
569            min_depth,
570            max_depth
571        );
572        self.pass
573            .set_viewport(x, y, width, height, min_depth, max_depth);
574    }
575
576    /// Set the rendering viewport to the given camera [`Viewport`].
577    ///
578    /// Subsequent draw calls will be projected into that viewport.
579    pub fn set_camera_viewport(&mut self, viewport: &Viewport) {
580        self.set_viewport(
581            viewport.physical_position.x as f32,
582            viewport.physical_position.y as f32,
583            viewport.physical_size.x as f32,
584            viewport.physical_size.y as f32,
585            viewport.depth.start,
586            viewport.depth.end,
587        );
588    }
589
590    /// Insert a single debug marker.
591    ///
592    /// This is a GPU debugging feature. This has no effect on the rendering itself.
593    pub fn insert_debug_marker(&mut self, label: &str) {
594        #[cfg(feature = "detailed_trace")]
595        trace!("insert debug marker: {}", label);
596        self.pass.insert_debug_marker(label);
597    }
598
599    /// Start a new debug group.
600    ///
601    /// Push a new debug group over the internal stack. Subsequent render commands and debug
602    /// markers are grouped into this new group, until [`pop_debug_group`] is called.
603    ///
604    /// ```
605    /// # fn example(mut pass: bevy_render::render_phase::TrackedRenderPass<'static>) {
606    /// pass.push_debug_group("Render the car");
607    /// // [setup pipeline etc...]
608    /// pass.draw(0..64, 0..1);
609    /// pass.pop_debug_group();
610    /// # }
611    /// ```
612    ///
613    /// Note that [`push_debug_group`] and [`pop_debug_group`] must always be called in pairs.
614    ///
615    /// This is a GPU debugging feature. This has no effect on the rendering itself.
616    ///
617    /// [`push_debug_group`]: TrackedRenderPass::push_debug_group
618    /// [`pop_debug_group`]: TrackedRenderPass::pop_debug_group
619    pub fn push_debug_group(&mut self, label: &str) {
620        #[cfg(feature = "detailed_trace")]
621        trace!("push_debug_group marker: {}", label);
622        self.pass.push_debug_group(label);
623    }
624
625    /// End the current debug group.
626    ///
627    /// Subsequent render commands and debug markers are not grouped anymore in
628    /// this group, but in the previous one (if any) or the default top-level one
629    /// if the debug group was the last one on the stack.
630    ///
631    /// Note that [`push_debug_group`] and [`pop_debug_group`] must always be called in pairs.
632    ///
633    /// This is a GPU debugging feature. This has no effect on the rendering itself.
634    ///
635    /// [`push_debug_group`]: TrackedRenderPass::push_debug_group
636    /// [`pop_debug_group`]: TrackedRenderPass::pop_debug_group
637    pub fn pop_debug_group(&mut self) {
638        #[cfg(feature = "detailed_trace")]
639        trace!("pop_debug_group");
640        self.pass.pop_debug_group();
641    }
642
643    /// Sets the blend color as used by some of the blending modes.
644    ///
645    /// Subsequent blending tests will test against this value.
646    pub fn set_blend_constant(&mut self, color: LinearRgba) {
647        #[cfg(feature = "detailed_trace")]
648        trace!("set blend constant: {:?}", color);
649        self.pass.set_blend_constant(wgpu::Color::from(color));
650    }
651}
652
653impl WriteTimestamp for TrackedRenderPass<'_> {
654    fn write_timestamp(&mut self, query_set: &QuerySet, index: u32) {
655        self.pass.write_timestamp(query_set, index);
656    }
657}
658
659impl WritePipelineStatistics for TrackedRenderPass<'_> {
660    fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, index: u32) {
661        self.pass.begin_pipeline_statistics_query(query_set, index);
662    }
663
664    fn end_pipeline_statistics_query(&mut self) {
665        self.pass.end_pipeline_statistics_query();
666    }
667}
668
669impl Pass for TrackedRenderPass<'_> {
670    const KIND: PassKind = PassKind::Render;
671}