bevy_render/render_phase/
draw_state.rs

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