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