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}