Skip to main content

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