1use alloc::{borrow::Cow, string::ToString, sync::Arc, vec::Vec};
2use core::{any::Any, convert::Infallible, marker::PhantomData};
3use std::io::Write as _;
4
5use crate::{
6 command::{
7 ArcCommand, ArcComputeCommand, ArcReferences, ArcRenderCommand, BasePass, ColorAttachments,
8 Command, ComputeCommand, PassTimestampWrites, PointerReferences, RenderCommand,
9 RenderPassColorAttachment, ResolvedRenderPassDepthStencilAttachment,
10 },
11 device::trace::{Data, DataKind},
12 id::{markers, PointerId},
13 storage::StorageItem,
14};
15
16use super::{
17 Action, TraceBindGroupDescriptor, TraceComputePipelineDescriptor,
18 TraceGeneralRenderPipelineDescriptor, FILE_NAME,
19};
20
21pub(crate) fn new_render_bundle_encoder_descriptor(
22 label: crate::Label<'_>,
23 context: &crate::device::RenderPassContext,
24 depth_read_only: bool,
25 stencil_read_only: bool,
26) -> crate::command::RenderBundleEncoderDescriptor<'static> {
27 crate::command::RenderBundleEncoderDescriptor {
28 label: label.map(|l| Cow::from(l.to_string())),
29 color_formats: Cow::from(context.attachments.colors.to_vec()),
30 depth_stencil: context.attachments.depth_stencil.map(|format| {
31 wgt::RenderBundleDepthStencil {
32 format,
33 depth_read_only,
34 stencil_read_only,
35 }
36 }),
37 sample_count: context.sample_count,
38 multiview: context.multiview_mask,
39 }
40}
41
42pub trait Trace: Any + Send + Sync {
43 fn make_binary(&mut self, kind: DataKind, data: &[u8]) -> Data;
44
45 fn make_string(&mut self, kind: DataKind, data: &str) -> Data;
46
47 fn add(&mut self, action: Action<'_, PointerReferences>)
48 where
49 for<'a> Action<'a, PointerReferences>: serde::Serialize;
50}
51
52#[derive(Debug)]
53pub struct DiskTrace {
54 path: std::path::PathBuf,
55 file: std::fs::File,
56 config: ron::ser::PrettyConfig,
57 data_id: usize,
58}
59
60impl DiskTrace {
61 pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> {
62 log::debug!("Tracing into '{path:?}'");
63 let mut file = std::fs::File::create(path.join(FILE_NAME))?;
64 file.write_all(b"[\n")?;
65 Ok(Self {
66 path,
67 file,
68 config: ron::ser::PrettyConfig::default(),
69 data_id: 0,
70 })
71 }
72}
73
74impl Trace for DiskTrace {
75 fn make_binary(&mut self, kind: DataKind, data: &[u8]) -> Data {
80 self.data_id += 1;
81 let name = std::format!("data{}.{}", self.data_id, kind);
82 let _ = std::fs::write(self.path.join(&name), data);
83 Data::File(name)
84 }
85
86 fn make_string(&mut self, kind: DataKind, data: &str) -> Data {
91 self.make_binary(kind, data.as_bytes())
92 }
93
94 fn add(&mut self, action: Action<'_, PointerReferences>)
95 where
96 for<'a> Action<'a, PointerReferences>: serde::Serialize,
97 {
98 match ron::ser::to_string_pretty(&action, self.config.clone()) {
99 Ok(string) => {
100 let _ = writeln!(self.file, "{string},");
101 }
102 Err(e) => {
103 log::warn!("RON serialization failure: {e:?}");
104 }
105 }
106 }
107}
108
109impl Drop for DiskTrace {
110 fn drop(&mut self) {
111 let _ = self.file.write_all(b"]");
112 }
113}
114
115#[derive(Default)]
116pub struct MemoryTrace {
117 actions: Vec<Action<'static, PointerReferences>>,
118}
119
120impl MemoryTrace {
121 pub fn new() -> Self {
122 Self::default()
123 }
124
125 pub fn actions(&self) -> &[Action<'static, PointerReferences>] {
126 &self.actions
127 }
128}
129
130impl Trace for MemoryTrace {
131 fn make_binary(&mut self, kind: DataKind, data: &[u8]) -> Data {
136 Data::Binary(kind, data.to_vec())
137 }
138
139 fn make_string(&mut self, kind: DataKind, data: &str) -> Data {
144 Data::String(kind, data.to_string())
145 }
146
147 fn add(&mut self, action: Action<'_, PointerReferences>)
148 where
149 for<'a> Action<'a, PointerReferences>: serde::Serialize,
150 {
151 self.actions.push(action_to_owned(action))
152 }
153}
154
155pub(crate) trait IntoTrace {
156 type Output;
157 fn into_trace(self) -> Self::Output;
158
159 fn to_trace(&self) -> Self::Output
160 where
161 Self: Sized + Clone,
162 {
163 self.clone().into_trace()
164 }
165}
166
167impl<T: StorageItem> IntoTrace for Arc<T> {
168 type Output = PointerId<T::Marker>;
169 fn into_trace(self) -> Self::Output {
170 self.to_trace()
171 }
172
173 fn to_trace(&self) -> Self::Output {
174 PointerId::from(self)
175 }
176}
177
178pub(crate) unsafe fn to_trace<T: StorageItem>(t: &T) -> PointerId<T::Marker> {
180 PointerId::PointerId(
181 #[expect(trivial_casts)]
182 core::num::NonZeroUsize::new(t as *const T as usize).unwrap(),
183 PhantomData,
184 )
185}
186
187impl IntoTrace for ArcCommand {
188 type Output = Command<PointerReferences>;
189 fn into_trace(self) -> Self::Output {
190 match self {
191 ArcCommand::CopyBufferToBuffer {
192 src,
193 src_offset,
194 dst,
195 dst_offset,
196 size,
197 } => Command::CopyBufferToBuffer {
198 src: src.to_trace(),
199 src_offset,
200 dst: dst.to_trace(),
201 dst_offset,
202 size,
203 },
204 ArcCommand::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture {
205 src: src.into_trace(),
206 dst: dst.into_trace(),
207 size,
208 },
209 ArcCommand::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer {
210 src: src.into_trace(),
211 dst: dst.into_trace(),
212 size,
213 },
214 ArcCommand::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture {
215 src: src.into_trace(),
216 dst: dst.into_trace(),
217 size,
218 },
219 ArcCommand::ClearBuffer { dst, offset, size } => Command::ClearBuffer {
220 dst: dst.to_trace(),
221 offset,
222 size,
223 },
224 ArcCommand::ClearTexture {
225 dst,
226 subresource_range,
227 } => Command::ClearTexture {
228 dst: dst.to_trace(),
229 subresource_range,
230 },
231 ArcCommand::WriteTimestamp {
232 query_set,
233 query_index,
234 } => Command::WriteTimestamp {
235 query_set: query_set.to_trace(),
236 query_index,
237 },
238 ArcCommand::ResolveQuerySet {
239 query_set,
240 start_query,
241 query_count,
242 destination,
243 destination_offset,
244 } => Command::ResolveQuerySet {
245 query_set: query_set.to_trace(),
246 start_query,
247 query_count,
248 destination: destination.to_trace(),
249 destination_offset,
250 },
251 ArcCommand::PushDebugGroup(label) => Command::PushDebugGroup(label),
252 ArcCommand::PopDebugGroup => Command::PopDebugGroup,
253 ArcCommand::InsertDebugMarker(label) => Command::InsertDebugMarker(label),
254 ArcCommand::RunComputePass {
255 pass,
256 timestamp_writes,
257 } => Command::RunComputePass {
258 pass: pass.into_trace(),
259 timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
260 },
261 ArcCommand::RunRenderPass {
262 pass,
263 color_attachments,
264 depth_stencil_attachment,
265 timestamp_writes,
266 occlusion_query_set,
267 multiview_mask,
268 } => Command::RunRenderPass {
269 pass: pass.into_trace(),
270 color_attachments: color_attachments.into_trace(),
271 depth_stencil_attachment: depth_stencil_attachment.map(|d| d.into_trace()),
272 timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
273 occlusion_query_set: occlusion_query_set.map(|q| q.to_trace()),
274 multiview_mask,
275 },
276 ArcCommand::BuildAccelerationStructures { blas, tlas } => {
277 Command::BuildAccelerationStructures {
278 blas: blas.into_iter().map(|b| b.into_trace()).collect(),
279 tlas: tlas.into_iter().map(|b| b.into_trace()).collect(),
280 }
281 }
282 ArcCommand::TransitionResources {
283 buffer_transitions: _,
284 texture_transitions: _,
285 } => {
286 panic!("TransitionResources cannot be converted to Command");
289 }
290 }
291 }
292}
293
294impl<T: IntoTrace> IntoTrace for wgt::TexelCopyBufferInfo<T> {
295 type Output = wgt::TexelCopyBufferInfo<T::Output>;
296 fn into_trace(self) -> Self::Output {
297 wgt::TexelCopyBufferInfo {
298 buffer: self.buffer.into_trace(),
299 layout: self.layout,
300 }
301 }
302}
303
304impl<T: IntoTrace> IntoTrace for wgt::TexelCopyTextureInfo<T> {
305 type Output = wgt::TexelCopyTextureInfo<T::Output>;
306 fn into_trace(self) -> Self::Output {
307 wgt::TexelCopyTextureInfo {
308 texture: self.texture.into_trace(),
309 mip_level: self.mip_level,
310 origin: self.origin,
311 aspect: self.aspect,
312 }
313 }
314}
315
316impl IntoTrace for PassTimestampWrites {
317 type Output = PassTimestampWrites<PointerId<markers::QuerySet>>;
318 fn into_trace(self) -> Self::Output {
319 PassTimestampWrites {
320 query_set: self.query_set.into_trace(),
321 beginning_of_pass_write_index: self.beginning_of_pass_write_index,
322 end_of_pass_write_index: self.end_of_pass_write_index,
323 }
324 }
325}
326
327impl IntoTrace for ColorAttachments {
328 type Output = ColorAttachments<PointerId<markers::TextureView>>;
329 fn into_trace(self) -> Self::Output {
330 self.into_iter()
331 .map(|opt| {
332 opt.map(|att| RenderPassColorAttachment {
333 view: att.view.into_trace(),
334 depth_slice: att.depth_slice,
335 resolve_target: att.resolve_target.map(|r| r.into_trace()),
336 load_op: att.load_op,
337 store_op: att.store_op,
338 })
339 })
340 .collect()
341 }
342}
343
344impl<TV: IntoTrace> IntoTrace for ResolvedRenderPassDepthStencilAttachment<TV> {
345 type Output = ResolvedRenderPassDepthStencilAttachment<TV::Output>;
346 fn into_trace(self) -> Self::Output {
347 ResolvedRenderPassDepthStencilAttachment {
348 view: self.view.into_trace(),
349 depth: self.depth,
350 stencil: self.stencil,
351 }
352 }
353}
354
355impl IntoTrace for crate::ray_tracing::OwnedBlasBuildEntry<ArcReferences> {
356 type Output = crate::ray_tracing::OwnedBlasBuildEntry<PointerReferences>;
357 fn into_trace(self) -> Self::Output {
358 crate::ray_tracing::OwnedBlasBuildEntry {
359 blas: self.blas.into_trace(),
360 geometries: self.geometries.into_trace(),
361 }
362 }
363}
364
365impl IntoTrace for crate::ray_tracing::OwnedBlasGeometries<ArcReferences> {
366 type Output = crate::ray_tracing::OwnedBlasGeometries<PointerReferences>;
367 fn into_trace(self) -> Self::Output {
368 match self {
369 crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => {
370 crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(
371 geos.into_iter().map(|g| g.into_trace()).collect(),
372 )
373 }
374 crate::ray_tracing::OwnedBlasGeometries::AabbGeometries(geos) => {
375 crate::ray_tracing::OwnedBlasGeometries::AabbGeometries(
376 geos.into_iter().map(|g| g.into_trace()).collect(),
377 )
378 }
379 }
380 }
381}
382
383impl IntoTrace for crate::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> {
384 type Output = crate::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>;
385 fn into_trace(self) -> Self::Output {
386 crate::ray_tracing::OwnedBlasTriangleGeometry {
387 size: self.size,
388 vertex_buffer: self.vertex_buffer.into_trace(),
389 index_buffer: self.index_buffer.map(|b| b.into_trace()),
390 transform_buffer: self.transform_buffer.map(|b| b.into_trace()),
391 first_vertex: self.first_vertex,
392 vertex_stride: self.vertex_stride,
393 first_index: self.first_index,
394 transform_buffer_offset: self.transform_buffer_offset,
395 }
396 }
397}
398
399impl IntoTrace for crate::ray_tracing::OwnedBlasAabbGeometry<ArcReferences> {
400 type Output = crate::ray_tracing::OwnedBlasAabbGeometry<PointerReferences>;
401 fn into_trace(self) -> Self::Output {
402 crate::ray_tracing::OwnedBlasAabbGeometry {
403 size: self.size,
404 stride: self.stride,
405 aabb_buffer: self.aabb_buffer.into_trace(),
406 primitive_offset: self.primitive_offset,
407 }
408 }
409}
410
411impl IntoTrace for crate::ray_tracing::OwnedTlasPackage<ArcReferences> {
412 type Output = crate::ray_tracing::OwnedTlasPackage<PointerReferences>;
413 fn into_trace(self) -> Self::Output {
414 crate::ray_tracing::OwnedTlasPackage {
415 tlas: self.tlas.into_trace(),
416 instances: self
417 .instances
418 .into_iter()
419 .map(|opt| opt.map(|inst| inst.into_trace()))
420 .collect(),
421 lowest_unmodified: self.lowest_unmodified,
422 }
423 }
424}
425
426impl IntoTrace for crate::ray_tracing::OwnedTlasInstance<ArcReferences> {
427 type Output = crate::ray_tracing::OwnedTlasInstance<PointerReferences>;
428 fn into_trace(self) -> Self::Output {
429 crate::ray_tracing::OwnedTlasInstance {
430 blas: self.blas.into_trace(),
431 transform: self.transform,
432 custom_data: self.custom_data,
433 mask: self.mask,
434 }
435 }
436}
437
438impl<C: IntoTrace> IntoTrace for BasePass<C, Infallible> {
439 type Output = BasePass<C::Output, Infallible>;
440
441 fn into_trace(self) -> Self::Output {
442 BasePass {
443 label: self.label,
444 error: self.error,
445 commands: self
446 .commands
447 .into_iter()
448 .map(|cmd| cmd.into_trace())
449 .collect(),
450 dynamic_offsets: self.dynamic_offsets,
451 string_data: self.string_data,
452 }
453 }
454}
455
456impl IntoTrace for ArcComputeCommand {
457 type Output = ComputeCommand<PointerReferences>;
458 fn into_trace(self) -> Self::Output {
459 use ComputeCommand as C;
460 match self {
461 C::SetBindGroup {
462 index,
463 num_dynamic_offsets,
464 bind_group,
465 } => C::SetBindGroup {
466 index,
467 num_dynamic_offsets,
468 bind_group: bind_group.map(|bg| bg.into_trace()),
469 },
470 C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
471 C::SetImmediate { offset, data } => C::SetImmediate { offset, data },
472 C::DispatchWorkgroups(groups) => C::DispatchWorkgroups(groups),
473 C::DispatchWorkgroupsIndirect { buffer, offset } => C::DispatchWorkgroupsIndirect {
474 buffer: buffer.into_trace(),
475 offset,
476 },
477 C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
478 C::PopDebugGroup => C::PopDebugGroup,
479 C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
480 C::WriteTimestamp {
481 query_set,
482 query_index,
483 } => C::WriteTimestamp {
484 query_set: query_set.into_trace(),
485 query_index,
486 },
487 C::BeginPipelineStatisticsQuery {
488 query_set,
489 query_index,
490 } => C::BeginPipelineStatisticsQuery {
491 query_set: query_set.into_trace(),
492 query_index,
493 },
494 C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
495 C::TransitionResources {
496 buffer_transitions,
497 texture_transitions,
498 } => C::TransitionResources {
499 buffer_transitions: buffer_transitions
500 .into_iter()
501 .map(|buffer_transition| wgt::BufferTransition {
502 buffer: buffer_transition.buffer.into_trace(),
503 state: buffer_transition.state,
504 })
505 .collect(),
506 texture_transitions: texture_transitions
507 .into_iter()
508 .map(|texture_transition| wgt::TextureTransition {
509 texture: texture_transition.texture.into_trace(),
510 selector: texture_transition.selector,
511 state: texture_transition.state,
512 })
513 .collect(),
514 },
515 }
516 }
517}
518
519impl IntoTrace for ArcRenderCommand {
520 type Output = RenderCommand<PointerReferences>;
521 fn into_trace(self) -> Self::Output {
522 use RenderCommand as C;
523 match self {
524 C::SetBindGroup {
525 index,
526 num_dynamic_offsets,
527 bind_group,
528 } => C::SetBindGroup {
529 index,
530 num_dynamic_offsets,
531 bind_group: bind_group.map(|bg| bg.into_trace()),
532 },
533 C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
534 C::SetIndexBuffer {
535 buffer,
536 index_format,
537 offset,
538 size,
539 } => C::SetIndexBuffer {
540 buffer: buffer.into_trace(),
541 index_format,
542 offset,
543 size,
544 },
545 C::SetVertexBuffer {
546 slot,
547 buffer,
548 offset,
549 size,
550 } => C::SetVertexBuffer {
551 slot,
552 buffer: buffer.into_trace(),
553 offset,
554 size,
555 },
556 C::SetBlendConstant(color) => C::SetBlendConstant(color),
557 C::SetStencilReference(val) => C::SetStencilReference(val),
558 C::SetViewport {
559 rect,
560 depth_min,
561 depth_max,
562 } => C::SetViewport {
563 rect,
564 depth_min,
565 depth_max,
566 },
567 C::SetScissor(rect) => C::SetScissor(rect),
568 C::SetImmediate { offset, data } => C::SetImmediate { offset, data },
569 C::Draw {
570 vertex_count,
571 instance_count,
572 first_vertex,
573 first_instance,
574 } => C::Draw {
575 vertex_count,
576 instance_count,
577 first_vertex,
578 first_instance,
579 },
580 C::DrawIndexed {
581 index_count,
582 instance_count,
583 first_index,
584 base_vertex,
585 first_instance,
586 } => C::DrawIndexed {
587 index_count,
588 instance_count,
589 first_index,
590 base_vertex,
591 first_instance,
592 },
593 C::DrawMeshTasks {
594 group_count_x,
595 group_count_y,
596 group_count_z,
597 } => C::DrawMeshTasks {
598 group_count_x,
599 group_count_y,
600 group_count_z,
601 },
602 C::DrawIndirect {
603 buffer,
604 offset,
605 count,
606 family,
607 vertex_or_index_limit,
608 instance_limit,
609 } => C::DrawIndirect {
610 buffer: buffer.into_trace(),
611 offset,
612 count,
613 family,
614 vertex_or_index_limit,
615 instance_limit,
616 },
617 C::MultiDrawIndirectCount {
618 buffer,
619 offset,
620 count_buffer,
621 count_buffer_offset,
622 max_count,
623 family,
624 } => C::MultiDrawIndirectCount {
625 buffer: buffer.into_trace(),
626 offset,
627 count_buffer: count_buffer.into_trace(),
628 count_buffer_offset,
629 max_count,
630 family,
631 },
632 C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
633 C::PopDebugGroup => C::PopDebugGroup,
634 C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
635 C::WriteTimestamp {
636 query_set,
637 query_index,
638 } => C::WriteTimestamp {
639 query_set: query_set.into_trace(),
640 query_index,
641 },
642 C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index },
643 C::EndOcclusionQuery => C::EndOcclusionQuery,
644 C::BeginPipelineStatisticsQuery {
645 query_set,
646 query_index,
647 } => C::BeginPipelineStatisticsQuery {
648 query_set: query_set.into_trace(),
649 query_index,
650 },
651 C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
652 C::ExecuteBundle(bundle) => C::ExecuteBundle(bundle.into_trace()),
653 }
654 }
655}
656
657impl IntoTrace for crate::binding_model::PipelineLayoutDescriptor<'_> {
658 type Output = crate::binding_model::PipelineLayoutDescriptor<
659 'static,
660 PointerId<markers::BindGroupLayout>,
661 >;
662 fn into_trace(self) -> Self::Output {
663 crate::binding_model::PipelineLayoutDescriptor {
664 label: self.label.map(|l| Cow::Owned(l.into_owned())),
665 bind_group_layouts: self
666 .bind_group_layouts
667 .iter()
668 .map(|bgl| bgl.to_trace())
669 .collect(),
670 immediate_size: self.immediate_size,
671 }
672 }
673}
674
675impl<'a> IntoTrace for &'_ crate::binding_model::BindGroupDescriptor<'a> {
676 type Output = TraceBindGroupDescriptor<'a>;
677
678 fn into_trace(self) -> Self::Output {
679 use crate::binding_model::{BindGroupEntry, BindingResource, BufferBinding};
680 TraceBindGroupDescriptor {
681 label: self.label.clone(),
682 layout: self.layout.to_trace(),
683 entries: Cow::Owned(
684 self.entries
685 .iter()
686 .map(|entry| {
687 let resource = match &entry.resource {
688 BindingResource::Buffer(buffer_binding) => {
689 BindingResource::Buffer(BufferBinding {
690 buffer: buffer_binding.buffer.to_trace(),
691 offset: buffer_binding.offset,
692 size: buffer_binding.size,
693 })
694 }
695 BindingResource::BufferArray(buffer_bindings) => {
696 let resolved_buffers: Vec<_> = buffer_bindings
697 .iter()
698 .map(|bb| BufferBinding {
699 buffer: bb.buffer.to_trace(),
700 offset: bb.offset,
701 size: bb.size,
702 })
703 .collect();
704 BindingResource::BufferArray(Cow::Owned(resolved_buffers))
705 }
706 BindingResource::Sampler(sampler_id) => {
707 BindingResource::Sampler(sampler_id.to_trace())
708 }
709 BindingResource::SamplerArray(sampler_ids) => {
710 let resolved: Vec<_> =
711 sampler_ids.iter().map(|id| id.to_trace()).collect();
712 BindingResource::SamplerArray(Cow::Owned(resolved))
713 }
714 BindingResource::TextureView(texture_view_id) => {
715 BindingResource::TextureView(texture_view_id.to_trace())
716 }
717 BindingResource::TextureViewArray(texture_view_ids) => {
718 let resolved: Vec<_> =
719 texture_view_ids.iter().map(|id| id.to_trace()).collect();
720 BindingResource::TextureViewArray(Cow::Owned(resolved))
721 }
722 BindingResource::AccelerationStructure(tlas_id) => {
723 BindingResource::AccelerationStructure(tlas_id.to_trace())
724 }
725 BindingResource::AccelerationStructureArray(tlas_ids) => {
726 let resolved: Vec<_> =
727 tlas_ids.iter().map(|id| id.to_trace()).collect();
728 BindingResource::AccelerationStructureArray(Cow::Owned(resolved))
729 }
730 BindingResource::ExternalTexture(external_texture_id) => {
731 BindingResource::ExternalTexture(external_texture_id.to_trace())
732 }
733 };
734 BindGroupEntry {
735 binding: entry.binding,
736 resource,
737 }
738 })
739 .collect(),
740 ),
741 }
742 }
743}
744
745impl<'a> IntoTrace for crate::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> {
746 type Output = TraceGeneralRenderPipelineDescriptor<'a>;
747
748 fn into_trace(self) -> Self::Output {
749 TraceGeneralRenderPipelineDescriptor {
750 label: self.label,
751 layout: self.layout.into_trace(),
752 vertex: self.vertex.into_trace(),
753 primitive: self.primitive,
754 depth_stencil: self.depth_stencil,
755 multisample: self.multisample,
756 fragment: self.fragment.map(|f| f.into_trace()),
757 multiview_mask: self.multiview_mask,
758 cache: self.cache.map(|c| c.into_trace()),
759 }
760 }
761}
762
763impl<'a> IntoTrace for crate::pipeline::ComputePipelineDescriptor<'a> {
764 type Output = TraceComputePipelineDescriptor<'a>;
765
766 fn into_trace(self) -> Self::Output {
767 TraceComputePipelineDescriptor {
768 label: self.label,
769 layout: self.layout.into_trace(),
770 stage: self.stage.into_trace(),
771 cache: self.cache.map(|c| c.into_trace()),
772 }
773 }
774}
775
776impl<'a> IntoTrace for crate::pipeline::ProgrammableStageDescriptor<'a> {
777 type Output =
778 crate::pipeline::ProgrammableStageDescriptor<'a, PointerId<markers::ShaderModule>>;
779 fn into_trace(self) -> Self::Output {
780 crate::pipeline::ProgrammableStageDescriptor {
781 module: self.module.into_trace(),
782 entry_point: self.entry_point,
783 constants: self.constants,
784 zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
785 }
786 }
787}
788
789impl<'a> IntoTrace
790 for crate::pipeline::RenderPipelineVertexProcessor<'a, Arc<crate::pipeline::ShaderModule>>
791{
792 type Output =
793 crate::pipeline::RenderPipelineVertexProcessor<'a, PointerId<markers::ShaderModule>>;
794 fn into_trace(self) -> Self::Output {
795 match self {
796 crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex) => {
797 crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex.into_trace())
798 }
799 crate::pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => {
800 crate::pipeline::RenderPipelineVertexProcessor::Mesh(
801 task.map(|t| t.into_trace()),
802 mesh.into_trace(),
803 )
804 }
805 }
806 }
807}
808
809impl<'a> IntoTrace for crate::pipeline::TaskState<'a> {
810 type Output = crate::pipeline::TaskState<'a, PointerId<markers::ShaderModule>>;
811 fn into_trace(self) -> Self::Output {
812 crate::pipeline::TaskState {
813 stage: self.stage.into_trace(),
814 }
815 }
816}
817
818impl<'a> IntoTrace for crate::pipeline::MeshState<'a> {
819 type Output = crate::pipeline::MeshState<'a, PointerId<markers::ShaderModule>>;
820 fn into_trace(self) -> Self::Output {
821 crate::pipeline::MeshState {
822 stage: self.stage.into_trace(),
823 }
824 }
825}
826
827impl<'a> IntoTrace for crate::pipeline::VertexState<'a> {
828 type Output = crate::pipeline::VertexState<'a, PointerId<markers::ShaderModule>>;
829 fn into_trace(self) -> Self::Output {
830 crate::pipeline::VertexState {
831 stage: self.stage.into_trace(),
832 buffers: self.buffers,
833 }
834 }
835}
836
837impl<'a> IntoTrace for crate::pipeline::FragmentState<'a> {
838 type Output = crate::pipeline::FragmentState<'a, PointerId<markers::ShaderModule>>;
839 fn into_trace(self) -> Self::Output {
840 crate::pipeline::FragmentState {
841 stage: self.stage.into_trace(),
842 targets: self.targets,
843 }
844 }
845}
846
847impl<T: IntoTrace> IntoTrace for Option<T> {
848 type Output = Option<T::Output>;
849 fn into_trace(self) -> Self::Output {
850 self.map(|v| v.into_trace())
851 }
852}
853
854fn action_to_owned(action: Action<'_, PointerReferences>) -> Action<'static, PointerReferences> {
858 use Action as A;
859 match action {
860 A::Init { desc, backend } => A::Init {
861 desc: desc.map_label(owned_label),
862 backend,
863 },
864 A::ConfigureSurface(surface, config) => A::ConfigureSurface(surface, config),
865 A::CreateBuffer(buffer, desc) => A::CreateBuffer(buffer, desc.map_label(owned_label)),
866 A::DestroyBuffer(buffer) => A::DestroyBuffer(buffer),
867 A::DropBuffer(buffer) => A::DropBuffer(buffer),
868 A::DestroyTexture(texture) => A::DestroyTexture(texture),
869 A::DropTexture(texture) => A::DropTexture(texture),
870 A::DropTextureView(texture_view) => A::DropTextureView(texture_view),
871 A::DestroyExternalTexture(external_texture) => A::DestroyExternalTexture(external_texture),
872 A::DropExternalTexture(external_texture) => A::DropExternalTexture(external_texture),
873 A::DropSampler(sampler) => A::DropSampler(sampler),
874 A::GetSurfaceTexture { id, parent } => A::GetSurfaceTexture { id, parent },
875 A::Present(surface) => A::Present(surface),
876 A::DiscardSurfaceTexture(surface) => A::DiscardSurfaceTexture(surface),
877 A::ReleaseSurfaceTexture(surface) => A::ReleaseSurfaceTexture(surface),
878 A::DropBindGroupLayout(layout) => A::DropBindGroupLayout(layout),
879 A::GetRenderPipelineBindGroupLayout {
880 id,
881 pipeline,
882 index,
883 } => A::GetRenderPipelineBindGroupLayout {
884 id,
885 pipeline,
886 index,
887 },
888 A::GetComputePipelineBindGroupLayout {
889 id,
890 pipeline,
891 index,
892 } => A::GetComputePipelineBindGroupLayout {
893 id,
894 pipeline,
895 index,
896 },
897 A::DropPipelineLayout(layout) => A::DropPipelineLayout(layout),
898 A::DropBindGroup(bind_group) => A::DropBindGroup(bind_group),
899 A::DropShaderModule(shader_module) => A::DropShaderModule(shader_module),
900 A::DropComputePipeline(pipeline) => A::DropComputePipeline(pipeline),
901 A::DropRenderPipeline(pipeline) => A::DropRenderPipeline(pipeline),
902 A::DropPipelineCache(cache) => A::DropPipelineCache(cache),
903 A::DropRenderBundle(render_bundle) => A::DropRenderBundle(render_bundle),
904 A::DestroyQuerySet(query_set) => A::DestroyQuerySet(query_set),
905 A::DropQuerySet(query_set) => A::DropQuerySet(query_set),
906 A::WriteBuffer {
907 id,
908 data,
909 offset,
910 size,
911 queued,
912 } => A::WriteBuffer {
913 id,
914 data,
915 offset,
916 size,
917 queued,
918 },
919 A::WriteTexture {
920 to,
921 data,
922 layout,
923 size,
924 } => A::WriteTexture {
925 to,
926 data,
927 layout,
928 size,
929 },
930 A::Submit(index, commands) => A::Submit(index, commands),
931 A::FailedCommands {
932 commands,
933 failed_at_submit,
934 error,
935 } => A::FailedCommands {
936 commands,
937 failed_at_submit,
938 error,
939 },
940 A::DropBlas(blas) => A::DropBlas(blas),
941 A::DropTlas(tlas) => A::DropTlas(tlas),
942
943 A::CreateTexture(id, desc) => A::CreateTexture(id, desc.map_label(owned_label)),
944 A::CreateTextureError(id, desc) => A::CreateTextureError(id, desc.map_label(owned_label)),
945 A::CreateTextureView { id, parent, desc } => A::CreateTextureView {
946 id,
947 parent,
948 desc: crate::resource::TextureViewDescriptor {
949 label: owned_label(&desc.label),
950 format: desc.format,
951 dimension: desc.dimension,
952 usage: desc.usage,
953 range: desc.range,
954 },
955 },
956 A::CreateExternalTexture { id, desc, planes } => A::CreateExternalTexture {
957 id,
958 desc: desc.map_label(owned_label),
959 planes,
960 },
961 A::CreateSampler(id, desc) => A::CreateSampler(
962 id,
963 crate::resource::SamplerDescriptor {
964 label: owned_label(&desc.label),
965 address_modes: desc.address_modes,
966 mag_filter: desc.mag_filter,
967 min_filter: desc.min_filter,
968 mipmap_filter: desc.mipmap_filter,
969 lod_min_clamp: desc.lod_min_clamp,
970 lod_max_clamp: desc.lod_max_clamp,
971 compare: desc.compare,
972 anisotropy_clamp: desc.anisotropy_clamp,
973 border_color: desc.border_color,
974 },
975 ),
976 A::CreateBindGroupLayout(id, desc) => A::CreateBindGroupLayout(
977 id,
978 crate::binding_model::BindGroupLayoutDescriptor {
979 label: owned_label(&desc.label),
980 entries: Cow::Owned(desc.entries.into_owned()),
981 },
982 ),
983 A::CreatePipelineLayout(id, desc) => A::CreatePipelineLayout(
984 id,
985 crate::binding_model::PipelineLayoutDescriptor {
986 label: owned_label(&desc.label),
987 bind_group_layouts: Cow::Owned(desc.bind_group_layouts.into_owned()),
988 immediate_size: desc.immediate_size,
989 },
990 ),
991 A::CreateBindGroup(id, desc) => A::CreateBindGroup(
992 id,
993 crate::binding_model::BindGroupDescriptor {
994 label: owned_label(&desc.label),
995 layout: desc.layout,
996 entries: desc
997 .entries
998 .iter()
999 .map(|e| crate::binding_model::BindGroupEntry {
1000 binding: e.binding,
1001 resource: match &e.resource {
1002 crate::binding_model::BindingResource::Buffer(buffer_binding) => {
1003 crate::binding_model::BindingResource::Buffer(
1004 buffer_binding.clone(),
1005 )
1006 }
1007 crate::binding_model::BindingResource::BufferArray(cow) => {
1008 crate::binding_model::BindingResource::BufferArray(Cow::Owned(
1009 cow.clone().into_owned(),
1010 ))
1011 }
1012 crate::binding_model::BindingResource::Sampler(sampler) => {
1013 crate::binding_model::BindingResource::Sampler(*sampler)
1014 }
1015 crate::binding_model::BindingResource::SamplerArray(cow) => {
1016 crate::binding_model::BindingResource::SamplerArray(Cow::Owned(
1017 cow.clone().into_owned(),
1018 ))
1019 }
1020 crate::binding_model::BindingResource::TextureView(texture_view) => {
1021 crate::binding_model::BindingResource::TextureView(*texture_view)
1022 }
1023 crate::binding_model::BindingResource::TextureViewArray(cow) => {
1024 crate::binding_model::BindingResource::TextureViewArray(Cow::Owned(
1025 cow.clone().into_owned(),
1026 ))
1027 }
1028 crate::binding_model::BindingResource::AccelerationStructure(
1029 acceleration_structure,
1030 ) => crate::binding_model::BindingResource::AccelerationStructure(
1031 *acceleration_structure,
1032 ),
1033 crate::binding_model::BindingResource::AccelerationStructureArray(
1034 cow,
1035 ) => crate::binding_model::BindingResource::AccelerationStructureArray(
1036 Cow::Owned(cow.clone().into_owned()),
1037 ),
1038 crate::binding_model::BindingResource::ExternalTexture(
1039 external_texture,
1040 ) => crate::binding_model::BindingResource::ExternalTexture(
1041 *external_texture,
1042 ),
1043 },
1044 })
1045 .collect(),
1046 },
1047 ),
1048 A::CreateShaderModule { id, desc, data } => A::CreateShaderModule {
1049 id,
1050 desc: crate::pipeline::ShaderModuleDescriptor {
1051 label: owned_label(&desc.label),
1052 runtime_checks: desc.runtime_checks,
1053 },
1054 data,
1055 },
1056 A::CreateShaderModulePassthrough {
1057 id,
1058 data,
1059 label,
1060 entry_points,
1061 } => A::CreateShaderModulePassthrough {
1062 id,
1063 data,
1064 label: owned_label(&label),
1065 entry_points: entry_points
1066 .iter()
1067 .map(|ep| wgt::PassthroughShaderEntryPoint {
1068 name: Cow::Owned(ep.name.to_string()),
1069 workgroup_size: ep.workgroup_size,
1070 })
1071 .collect(),
1072 },
1073 A::CreateComputePipeline { id, desc } => A::CreateComputePipeline {
1074 id,
1075 desc: crate::pipeline::ComputePipelineDescriptor {
1076 label: owned_label(&desc.label),
1077 layout: desc.layout,
1078 stage: owned_stage(desc.stage),
1079 cache: desc.cache,
1080 },
1081 },
1082 A::CreateGeneralRenderPipeline { id, desc } => A::CreateGeneralRenderPipeline {
1083 id,
1084 desc: crate::pipeline::GeneralRenderPipelineDescriptor {
1085 label: owned_label(&desc.label),
1086 layout: desc.layout,
1087 vertex: match desc.vertex {
1088 crate::pipeline::RenderPipelineVertexProcessor::Vertex(
1089 crate::pipeline::VertexState { stage, buffers },
1090 ) => crate::pipeline::RenderPipelineVertexProcessor::Vertex(
1091 crate::pipeline::VertexState {
1092 stage: owned_stage(stage),
1093 buffers: buffers
1094 .iter()
1095 .map(|b| {
1096 b.clone().map(|buffer| crate::pipeline::VertexBufferLayout {
1097 array_stride: buffer.array_stride,
1098 step_mode: buffer.step_mode,
1099 attributes: Cow::Owned(buffer.attributes.into_owned()),
1100 })
1101 })
1102 .collect(),
1103 },
1104 ),
1105 crate::pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => {
1106 crate::pipeline::RenderPipelineVertexProcessor::Mesh(
1107 task.map(|t| crate::pipeline::TaskState {
1108 stage: owned_stage(t.stage),
1109 }),
1110 crate::pipeline::MeshState {
1111 stage: owned_stage(mesh.stage),
1112 },
1113 )
1114 }
1115 },
1116 primitive: desc.primitive,
1117 depth_stencil: desc.depth_stencil,
1118 multisample: desc.multisample,
1119 fragment: desc.fragment.map(|f| crate::pipeline::FragmentState {
1120 stage: owned_stage(f.stage),
1121 targets: Cow::Owned(f.targets.into_owned()),
1122 }),
1123 multiview_mask: desc.multiview_mask,
1124 cache: desc.cache,
1125 },
1126 },
1127 A::CreatePipelineCache { id, desc } => A::CreatePipelineCache {
1128 id,
1129 desc: crate::pipeline::PipelineCacheDescriptor {
1130 label: owned_label(&desc.label),
1131 data: desc.data.map(|d| Cow::Owned(d.to_vec())),
1132 fallback: desc.fallback,
1133 },
1134 },
1135 A::CreateRenderBundle { id, desc, base } => A::CreateRenderBundle {
1136 id,
1137 desc: crate::command::RenderBundleEncoderDescriptor {
1138 label: owned_label(&desc.label),
1139 color_formats: Cow::Owned(desc.color_formats.into_owned()),
1140 depth_stencil: desc.depth_stencil,
1141 sample_count: desc.sample_count,
1142 multiview: desc.multiview,
1143 },
1144 base,
1145 },
1146 A::CreateQuerySet { id, desc } => A::CreateQuerySet {
1147 id,
1148 desc: desc.map_label(owned_label),
1149 },
1150 A::CreateBlas { id, desc, sizes } => A::CreateBlas {
1151 id,
1152 desc: desc.map_label(owned_label),
1153 sizes,
1154 },
1155 A::CreateTlas { id, desc } => A::CreateTlas {
1156 id,
1157 desc: desc.map_label(owned_label),
1158 },
1159 }
1160}
1161
1162fn owned_stage<SM>(
1163 stage: crate::pipeline::ProgrammableStageDescriptor<'_, SM>,
1164) -> crate::pipeline::ProgrammableStageDescriptor<'static, SM> {
1165 crate::pipeline::ProgrammableStageDescriptor {
1166 module: stage.module,
1167 entry_point: owned_label(&stage.entry_point),
1168 constants: stage.constants,
1169 zero_initialize_workgroup_memory: stage.zero_initialize_workgroup_memory,
1170 }
1171}
1172
1173fn owned_label(l: &Option<Cow<'_, str>>) -> Option<Cow<'static, str>> {
1174 l.as_ref().map(|l| Cow::Owned(l.to_string()))
1175}