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