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}