wgpu_core/device/trace/
record.rs

1use alloc::{borrow::Cow, string::ToString, sync::Arc, vec::Vec};
2use core::{any::Any, convert::Infallible};
3use std::io::Write as _;
4
5use crate::{
6    command::{
7        ArcCommand, ArcComputeCommand, ArcPassTimestampWrites, ArcReferences, ArcRenderCommand,
8        BasePass, ColorAttachments, Command, ComputeCommand, 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    /// Store `[u8]` data in the trace.
76    ///
77    /// Using a string `kind` is probably a bug, but should work as long as the
78    /// data is UTF-8.
79    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    /// Store `str` data in the trace.
87    ///
88    /// Using a binary `kind` is fine, but it's not clear why not use
89    /// `make_binary` instead.
90    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    /// Store `[u8]` data in the trace.
132    ///
133    /// Using a string `kind` is probably a bug, but should work as long as the
134    /// data is UTF-8.
135    fn make_binary(&mut self, kind: DataKind, data: &[u8]) -> Data {
136        Data::Binary(kind, data.to_vec())
137    }
138
139    /// Store `str` data in the trace.
140    ///
141    /// Using a binary `kind` is fine, but it's not clear why not use
142    /// `make_binary` instead.
143    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
178impl IntoTrace for ArcCommand {
179    type Output = Command<PointerReferences>;
180    fn into_trace(self) -> Self::Output {
181        match self {
182            ArcCommand::CopyBufferToBuffer {
183                src,
184                src_offset,
185                dst,
186                dst_offset,
187                size,
188            } => Command::CopyBufferToBuffer {
189                src: src.to_trace(),
190                src_offset,
191                dst: dst.to_trace(),
192                dst_offset,
193                size,
194            },
195            ArcCommand::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture {
196                src: src.into_trace(),
197                dst: dst.into_trace(),
198                size,
199            },
200            ArcCommand::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer {
201                src: src.into_trace(),
202                dst: dst.into_trace(),
203                size,
204            },
205            ArcCommand::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture {
206                src: src.into_trace(),
207                dst: dst.into_trace(),
208                size,
209            },
210            ArcCommand::ClearBuffer { dst, offset, size } => Command::ClearBuffer {
211                dst: dst.to_trace(),
212                offset,
213                size,
214            },
215            ArcCommand::ClearTexture {
216                dst,
217                subresource_range,
218            } => Command::ClearTexture {
219                dst: dst.to_trace(),
220                subresource_range,
221            },
222            ArcCommand::WriteTimestamp {
223                query_set,
224                query_index,
225            } => Command::WriteTimestamp {
226                query_set: query_set.to_trace(),
227                query_index,
228            },
229            ArcCommand::ResolveQuerySet {
230                query_set,
231                start_query,
232                query_count,
233                destination,
234                destination_offset,
235            } => Command::ResolveQuerySet {
236                query_set: query_set.to_trace(),
237                start_query,
238                query_count,
239                destination: destination.to_trace(),
240                destination_offset,
241            },
242            ArcCommand::PushDebugGroup(label) => Command::PushDebugGroup(label),
243            ArcCommand::PopDebugGroup => Command::PopDebugGroup,
244            ArcCommand::InsertDebugMarker(label) => Command::InsertDebugMarker(label),
245            ArcCommand::RunComputePass {
246                pass,
247                timestamp_writes,
248            } => Command::RunComputePass {
249                pass: pass.into_trace(),
250                timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
251            },
252            ArcCommand::RunRenderPass {
253                pass,
254                color_attachments,
255                depth_stencil_attachment,
256                timestamp_writes,
257                occlusion_query_set,
258                multiview_mask,
259            } => Command::RunRenderPass {
260                pass: pass.into_trace(),
261                color_attachments: color_attachments.into_trace(),
262                depth_stencil_attachment: depth_stencil_attachment.map(|d| d.into_trace()),
263                timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
264                occlusion_query_set: occlusion_query_set.map(|q| q.to_trace()),
265                multiview_mask,
266            },
267            ArcCommand::BuildAccelerationStructures { blas, tlas } => {
268                Command::BuildAccelerationStructures {
269                    blas: blas.into_iter().map(|b| b.into_trace()).collect(),
270                    tlas: tlas.into_iter().map(|b| b.into_trace()).collect(),
271                }
272            }
273            ArcCommand::TransitionResources {
274                buffer_transitions: _,
275                texture_transitions: _,
276            } => {
277                // TransitionResources does not exist in Command, so skip or handle as needed.
278                // If you want to ignore, you could panic or return a default.
279                panic!("TransitionResources cannot be converted to Command");
280            }
281        }
282    }
283}
284
285impl<T: IntoTrace> IntoTrace for wgt::TexelCopyBufferInfo<T> {
286    type Output = wgt::TexelCopyBufferInfo<T::Output>;
287    fn into_trace(self) -> Self::Output {
288        wgt::TexelCopyBufferInfo {
289            buffer: self.buffer.into_trace(),
290            layout: self.layout,
291        }
292    }
293}
294
295impl<T: IntoTrace> IntoTrace for wgt::TexelCopyTextureInfo<T> {
296    type Output = wgt::TexelCopyTextureInfo<T::Output>;
297    fn into_trace(self) -> Self::Output {
298        wgt::TexelCopyTextureInfo {
299            texture: self.texture.into_trace(),
300            mip_level: self.mip_level,
301            origin: self.origin,
302            aspect: self.aspect,
303        }
304    }
305}
306
307impl IntoTrace for ArcPassTimestampWrites {
308    type Output = crate::command::PassTimestampWrites<PointerId<markers::QuerySet>>;
309    fn into_trace(self) -> Self::Output {
310        crate::command::PassTimestampWrites {
311            query_set: self.query_set.into_trace(),
312            beginning_of_pass_write_index: self.beginning_of_pass_write_index,
313            end_of_pass_write_index: self.end_of_pass_write_index,
314        }
315    }
316}
317
318impl IntoTrace for ColorAttachments {
319    type Output = ColorAttachments<PointerId<markers::TextureView>>;
320    fn into_trace(self) -> Self::Output {
321        self.into_iter()
322            .map(|opt| {
323                opt.map(|att| RenderPassColorAttachment {
324                    view: att.view.into_trace(),
325                    depth_slice: att.depth_slice,
326                    resolve_target: att.resolve_target.map(|r| r.into_trace()),
327                    load_op: att.load_op,
328                    store_op: att.store_op,
329                })
330            })
331            .collect()
332    }
333}
334
335impl<TV: IntoTrace> IntoTrace for ResolvedRenderPassDepthStencilAttachment<TV> {
336    type Output = ResolvedRenderPassDepthStencilAttachment<TV::Output>;
337    fn into_trace(self) -> Self::Output {
338        ResolvedRenderPassDepthStencilAttachment {
339            view: self.view.into_trace(),
340            depth: self.depth,
341            stencil: self.stencil,
342        }
343    }
344}
345
346impl IntoTrace for crate::ray_tracing::OwnedBlasBuildEntry<ArcReferences> {
347    type Output = crate::ray_tracing::OwnedBlasBuildEntry<PointerReferences>;
348    fn into_trace(self) -> Self::Output {
349        crate::ray_tracing::OwnedBlasBuildEntry {
350            blas: self.blas.into_trace(),
351            geometries: self.geometries.into_trace(),
352        }
353    }
354}
355
356impl IntoTrace for crate::ray_tracing::OwnedBlasGeometries<ArcReferences> {
357    type Output = crate::ray_tracing::OwnedBlasGeometries<PointerReferences>;
358    fn into_trace(self) -> Self::Output {
359        match self {
360            crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => {
361                crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(
362                    geos.into_iter().map(|g| g.into_trace()).collect(),
363                )
364            }
365            crate::ray_tracing::OwnedBlasGeometries::AabbGeometries(geos) => {
366                crate::ray_tracing::OwnedBlasGeometries::AabbGeometries(
367                    geos.into_iter().map(|g| g.into_trace()).collect(),
368                )
369            }
370        }
371    }
372}
373
374impl IntoTrace for crate::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> {
375    type Output = crate::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>;
376    fn into_trace(self) -> Self::Output {
377        crate::ray_tracing::OwnedBlasTriangleGeometry {
378            size: self.size,
379            vertex_buffer: self.vertex_buffer.into_trace(),
380            index_buffer: self.index_buffer.map(|b| b.into_trace()),
381            transform_buffer: self.transform_buffer.map(|b| b.into_trace()),
382            first_vertex: self.first_vertex,
383            vertex_stride: self.vertex_stride,
384            first_index: self.first_index,
385            transform_buffer_offset: self.transform_buffer_offset,
386        }
387    }
388}
389
390impl IntoTrace for crate::ray_tracing::OwnedBlasAabbGeometry<ArcReferences> {
391    type Output = crate::ray_tracing::OwnedBlasAabbGeometry<PointerReferences>;
392    fn into_trace(self) -> Self::Output {
393        crate::ray_tracing::OwnedBlasAabbGeometry {
394            size: self.size,
395            stride: self.stride,
396            aabb_buffer: self.aabb_buffer.into_trace(),
397            primitive_offset: self.primitive_offset,
398        }
399    }
400}
401
402impl IntoTrace for crate::ray_tracing::OwnedTlasPackage<ArcReferences> {
403    type Output = crate::ray_tracing::OwnedTlasPackage<PointerReferences>;
404    fn into_trace(self) -> Self::Output {
405        crate::ray_tracing::OwnedTlasPackage {
406            tlas: self.tlas.into_trace(),
407            instances: self
408                .instances
409                .into_iter()
410                .map(|opt| opt.map(|inst| inst.into_trace()))
411                .collect(),
412            lowest_unmodified: self.lowest_unmodified,
413        }
414    }
415}
416
417impl IntoTrace for crate::ray_tracing::OwnedTlasInstance<ArcReferences> {
418    type Output = crate::ray_tracing::OwnedTlasInstance<PointerReferences>;
419    fn into_trace(self) -> Self::Output {
420        crate::ray_tracing::OwnedTlasInstance {
421            blas: self.blas.into_trace(),
422            transform: self.transform,
423            custom_data: self.custom_data,
424            mask: self.mask,
425        }
426    }
427}
428
429impl<C: IntoTrace> IntoTrace for BasePass<C, Infallible> {
430    type Output = BasePass<C::Output, Infallible>;
431
432    fn into_trace(self) -> Self::Output {
433        BasePass {
434            label: self.label,
435            error: self.error,
436            commands: self
437                .commands
438                .into_iter()
439                .map(|cmd| cmd.into_trace())
440                .collect(),
441            dynamic_offsets: self.dynamic_offsets,
442            string_data: self.string_data,
443            immediates_data: self.immediates_data,
444        }
445    }
446}
447
448impl IntoTrace for ArcComputeCommand {
449    type Output = ComputeCommand<PointerReferences>;
450    fn into_trace(self) -> Self::Output {
451        use ComputeCommand as C;
452        match self {
453            C::SetBindGroup {
454                index,
455                num_dynamic_offsets,
456                bind_group,
457            } => C::SetBindGroup {
458                index,
459                num_dynamic_offsets,
460                bind_group: bind_group.map(|bg| bg.into_trace()),
461            },
462            C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
463            C::SetImmediate {
464                offset,
465                size_bytes,
466                values_offset,
467            } => C::SetImmediate {
468                offset,
469                size_bytes,
470                values_offset,
471            },
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 {
569                offset,
570                size_bytes,
571                values_offset,
572            } => C::SetImmediate {
573                offset,
574                size_bytes,
575                values_offset,
576            },
577            C::Draw {
578                vertex_count,
579                instance_count,
580                first_vertex,
581                first_instance,
582            } => C::Draw {
583                vertex_count,
584                instance_count,
585                first_vertex,
586                first_instance,
587            },
588            C::DrawIndexed {
589                index_count,
590                instance_count,
591                first_index,
592                base_vertex,
593                first_instance,
594            } => C::DrawIndexed {
595                index_count,
596                instance_count,
597                first_index,
598                base_vertex,
599                first_instance,
600            },
601            C::DrawMeshTasks {
602                group_count_x,
603                group_count_y,
604                group_count_z,
605            } => C::DrawMeshTasks {
606                group_count_x,
607                group_count_y,
608                group_count_z,
609            },
610            C::DrawIndirect {
611                buffer,
612                offset,
613                count,
614                family,
615                vertex_or_index_limit,
616                instance_limit,
617            } => C::DrawIndirect {
618                buffer: buffer.into_trace(),
619                offset,
620                count,
621                family,
622                vertex_or_index_limit,
623                instance_limit,
624            },
625            C::MultiDrawIndirectCount {
626                buffer,
627                offset,
628                count_buffer,
629                count_buffer_offset,
630                max_count,
631                family,
632            } => C::MultiDrawIndirectCount {
633                buffer: buffer.into_trace(),
634                offset,
635                count_buffer: count_buffer.into_trace(),
636                count_buffer_offset,
637                max_count,
638                family,
639            },
640            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
641            C::PopDebugGroup => C::PopDebugGroup,
642            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
643            C::WriteTimestamp {
644                query_set,
645                query_index,
646            } => C::WriteTimestamp {
647                query_set: query_set.into_trace(),
648                query_index,
649            },
650            C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index },
651            C::EndOcclusionQuery => C::EndOcclusionQuery,
652            C::BeginPipelineStatisticsQuery {
653                query_set,
654                query_index,
655            } => C::BeginPipelineStatisticsQuery {
656                query_set: query_set.into_trace(),
657                query_index,
658            },
659            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
660            C::ExecuteBundle(bundle) => C::ExecuteBundle(bundle.into_trace()),
661        }
662    }
663}
664
665impl IntoTrace for crate::binding_model::ResolvedPipelineLayoutDescriptor<'_> {
666    type Output = crate::binding_model::PipelineLayoutDescriptor<
667        'static,
668        PointerId<markers::BindGroupLayout>,
669    >;
670    fn into_trace(self) -> Self::Output {
671        crate::binding_model::PipelineLayoutDescriptor {
672            label: self.label.map(|l| Cow::Owned(l.into_owned())),
673            bind_group_layouts: self
674                .bind_group_layouts
675                .iter()
676                .map(|bgl| bgl.to_trace())
677                .collect(),
678            immediate_size: self.immediate_size,
679        }
680    }
681}
682
683impl<'a> IntoTrace for &'_ crate::binding_model::ResolvedBindGroupDescriptor<'a> {
684    type Output = TraceBindGroupDescriptor<'a>;
685
686    fn into_trace(self) -> Self::Output {
687        use crate::binding_model::{
688            BindGroupEntry, BindingResource, BufferBinding, ResolvedBindingResource,
689        };
690        TraceBindGroupDescriptor {
691            label: self.label.clone(),
692            layout: self.layout.to_trace(),
693            entries: Cow::Owned(
694                self.entries
695                    .iter()
696                    .map(|entry| {
697                        let resource = match &entry.resource {
698                            ResolvedBindingResource::Buffer(buffer_binding) => {
699                                BindingResource::Buffer(BufferBinding {
700                                    buffer: buffer_binding.buffer.to_trace(),
701                                    offset: buffer_binding.offset,
702                                    size: buffer_binding.size,
703                                })
704                            }
705                            ResolvedBindingResource::BufferArray(buffer_bindings) => {
706                                let resolved_buffers: Vec<_> = buffer_bindings
707                                    .iter()
708                                    .map(|bb| BufferBinding {
709                                        buffer: bb.buffer.to_trace(),
710                                        offset: bb.offset,
711                                        size: bb.size,
712                                    })
713                                    .collect();
714                                BindingResource::BufferArray(Cow::Owned(resolved_buffers))
715                            }
716                            ResolvedBindingResource::Sampler(sampler_id) => {
717                                BindingResource::Sampler(sampler_id.to_trace())
718                            }
719                            ResolvedBindingResource::SamplerArray(sampler_ids) => {
720                                let resolved: Vec<_> =
721                                    sampler_ids.iter().map(|id| id.to_trace()).collect();
722                                BindingResource::SamplerArray(Cow::Owned(resolved))
723                            }
724                            ResolvedBindingResource::TextureView(texture_view_id) => {
725                                BindingResource::TextureView(texture_view_id.to_trace())
726                            }
727                            ResolvedBindingResource::TextureViewArray(texture_view_ids) => {
728                                let resolved: Vec<_> =
729                                    texture_view_ids.iter().map(|id| id.to_trace()).collect();
730                                BindingResource::TextureViewArray(Cow::Owned(resolved))
731                            }
732                            ResolvedBindingResource::AccelerationStructure(tlas_id) => {
733                                BindingResource::AccelerationStructure(tlas_id.to_trace())
734                            }
735                            ResolvedBindingResource::AccelerationStructureArray(tlas_ids) => {
736                                let resolved: Vec<_> =
737                                    tlas_ids.iter().map(|id| id.to_trace()).collect();
738                                BindingResource::AccelerationStructureArray(Cow::Owned(resolved))
739                            }
740                            ResolvedBindingResource::ExternalTexture(external_texture_id) => {
741                                BindingResource::ExternalTexture(external_texture_id.to_trace())
742                            }
743                        };
744                        BindGroupEntry {
745                            binding: entry.binding,
746                            resource,
747                        }
748                    })
749                    .collect(),
750            ),
751        }
752    }
753}
754
755impl<'a> IntoTrace for crate::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> {
756    type Output = TraceGeneralRenderPipelineDescriptor<'a>;
757
758    fn into_trace(self) -> Self::Output {
759        TraceGeneralRenderPipelineDescriptor {
760            label: self.label,
761            layout: self.layout.into_trace(),
762            vertex: self.vertex.into_trace(),
763            primitive: self.primitive,
764            depth_stencil: self.depth_stencil,
765            multisample: self.multisample,
766            fragment: self.fragment.map(|f| f.into_trace()),
767            multiview_mask: self.multiview_mask,
768            cache: self.cache.map(|c| c.into_trace()),
769        }
770    }
771}
772
773impl<'a> IntoTrace for crate::pipeline::ResolvedComputePipelineDescriptor<'a> {
774    type Output = TraceComputePipelineDescriptor<'a>;
775
776    fn into_trace(self) -> Self::Output {
777        TraceComputePipelineDescriptor {
778            label: self.label,
779            layout: self.layout.into_trace(),
780            stage: self.stage.into_trace(),
781            cache: self.cache.map(|c| c.into_trace()),
782        }
783    }
784}
785
786impl<'a> IntoTrace for crate::pipeline::ResolvedProgrammableStageDescriptor<'a> {
787    type Output =
788        crate::pipeline::ProgrammableStageDescriptor<'a, PointerId<markers::ShaderModule>>;
789    fn into_trace(self) -> Self::Output {
790        crate::pipeline::ProgrammableStageDescriptor {
791            module: self.module.into_trace(),
792            entry_point: self.entry_point,
793            constants: self.constants,
794            zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
795        }
796    }
797}
798
799impl<'a> IntoTrace
800    for crate::pipeline::RenderPipelineVertexProcessor<'a, Arc<crate::pipeline::ShaderModule>>
801{
802    type Output =
803        crate::pipeline::RenderPipelineVertexProcessor<'a, PointerId<markers::ShaderModule>>;
804    fn into_trace(self) -> Self::Output {
805        match self {
806            crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex) => {
807                crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex.into_trace())
808            }
809            crate::pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => {
810                crate::pipeline::RenderPipelineVertexProcessor::Mesh(
811                    task.map(|t| t.into_trace()),
812                    mesh.into_trace(),
813                )
814            }
815        }
816    }
817}
818
819impl<'a> IntoTrace for crate::pipeline::ResolvedTaskState<'a> {
820    type Output = crate::pipeline::TaskState<'a, PointerId<markers::ShaderModule>>;
821    fn into_trace(self) -> Self::Output {
822        crate::pipeline::TaskState {
823            stage: self.stage.into_trace(),
824        }
825    }
826}
827
828impl<'a> IntoTrace for crate::pipeline::ResolvedMeshState<'a> {
829    type Output = crate::pipeline::MeshState<'a, PointerId<markers::ShaderModule>>;
830    fn into_trace(self) -> Self::Output {
831        crate::pipeline::MeshState {
832            stage: self.stage.into_trace(),
833        }
834    }
835}
836
837impl<'a> IntoTrace for crate::pipeline::ResolvedVertexState<'a> {
838    type Output = crate::pipeline::VertexState<'a, PointerId<markers::ShaderModule>>;
839    fn into_trace(self) -> Self::Output {
840        crate::pipeline::VertexState {
841            stage: self.stage.into_trace(),
842            buffers: self.buffers,
843        }
844    }
845}
846
847impl<'a> IntoTrace for crate::pipeline::ResolvedFragmentState<'a> {
848    type Output = crate::pipeline::FragmentState<'a, PointerId<markers::ShaderModule>>;
849    fn into_trace(self) -> Self::Output {
850        crate::pipeline::FragmentState {
851            stage: self.stage.into_trace(),
852            targets: self.targets,
853        }
854    }
855}
856
857impl<T: IntoTrace> IntoTrace for Option<T> {
858    type Output = Option<T::Output>;
859    fn into_trace(self) -> Self::Output {
860        self.map(|v| v.into_trace())
861    }
862}
863
864/// For selected `Action`s (mostly actions containing only owned data), return a
865/// copy with `'static` lifetime.
866///
867/// This is used for in-memory tracing.
868///
869/// # Panics
870///
871/// If `action` is not supported for in-memory tracing (likely because it
872/// contains borrowed data).
873fn action_to_owned(action: Action<'_, PointerReferences>) -> Action<'static, PointerReferences> {
874    use Action as A;
875    match action {
876        A::Init { desc, backend } => A::Init {
877            desc: wgt::DeviceDescriptor {
878                label: desc.label.map(|l| Cow::Owned(l.into_owned())),
879                required_features: desc.required_features,
880                required_limits: desc.required_limits,
881                experimental_features: desc.experimental_features,
882                memory_hints: desc.memory_hints,
883                trace: desc.trace,
884            },
885            backend,
886        },
887        A::ConfigureSurface(surface, config) => A::ConfigureSurface(surface, config),
888        A::CreateBuffer(buffer, desc) => A::CreateBuffer(
889            buffer,
890            wgt::BufferDescriptor {
891                label: desc.label.map(|l| Cow::Owned(l.into_owned())),
892                size: desc.size,
893                usage: desc.usage,
894                mapped_at_creation: desc.mapped_at_creation,
895            },
896        ),
897        A::FreeBuffer(buffer) => A::FreeBuffer(buffer),
898        A::DestroyBuffer(buffer) => A::DestroyBuffer(buffer),
899        A::FreeTexture(texture) => A::FreeTexture(texture),
900        A::DestroyTexture(texture) => A::DestroyTexture(texture),
901        A::DestroyTextureView(texture_view) => A::DestroyTextureView(texture_view),
902        A::FreeExternalTexture(external_texture) => A::FreeExternalTexture(external_texture),
903        A::DestroyExternalTexture(external_texture) => A::DestroyExternalTexture(external_texture),
904        A::DestroySampler(sampler) => A::DestroySampler(sampler),
905        A::GetSurfaceTexture { id, parent } => A::GetSurfaceTexture { id, parent },
906        A::Present(surface) => A::Present(surface),
907        A::DiscardSurfaceTexture(surface) => A::DiscardSurfaceTexture(surface),
908        A::DestroyBindGroupLayout(layout) => A::DestroyBindGroupLayout(layout),
909        A::GetRenderPipelineBindGroupLayout {
910            id,
911            pipeline,
912            index,
913        } => A::GetRenderPipelineBindGroupLayout {
914            id,
915            pipeline,
916            index,
917        },
918        A::GetComputePipelineBindGroupLayout {
919            id,
920            pipeline,
921            index,
922        } => A::GetComputePipelineBindGroupLayout {
923            id,
924            pipeline,
925            index,
926        },
927        A::DestroyPipelineLayout(layout) => A::DestroyPipelineLayout(layout),
928        A::DestroyBindGroup(bind_group) => A::DestroyBindGroup(bind_group),
929        A::DestroyShaderModule(shader_module) => A::DestroyShaderModule(shader_module),
930        A::DestroyComputePipeline(pipeline) => A::DestroyComputePipeline(pipeline),
931        A::DestroyRenderPipeline(pipeline) => A::DestroyRenderPipeline(pipeline),
932        A::DestroyPipelineCache(cache) => A::DestroyPipelineCache(cache),
933        A::DestroyRenderBundle(render_bundle) => A::DestroyRenderBundle(render_bundle),
934        A::DestroyQuerySet(query_set) => A::DestroyQuerySet(query_set),
935        A::WriteBuffer {
936            id,
937            data,
938            offset,
939            size,
940            queued,
941        } => A::WriteBuffer {
942            id,
943            data,
944            offset,
945            size,
946            queued,
947        },
948        A::WriteTexture {
949            to,
950            data,
951            layout,
952            size,
953        } => A::WriteTexture {
954            to,
955            data,
956            layout,
957            size,
958        },
959        A::Submit(index, commands) => A::Submit(index, commands),
960        A::FailedCommands {
961            commands,
962            failed_at_submit,
963            error,
964        } => A::FailedCommands {
965            commands,
966            failed_at_submit,
967            error,
968        },
969        A::DestroyBlas(blas) => A::DestroyBlas(blas),
970        A::DestroyTlas(tlas) => A::DestroyTlas(tlas),
971
972        A::CreateTexture(..)
973        | A::CreateTextureView { .. }
974        | A::CreateExternalTexture { .. }
975        | A::CreateSampler(..)
976        | A::CreateBindGroupLayout(..)
977        | A::CreatePipelineLayout(..)
978        | A::CreateBindGroup(..)
979        | A::CreateShaderModule { .. }
980        | A::CreateShaderModulePassthrough { .. }
981        | A::CreateComputePipeline { .. }
982        | A::CreateGeneralRenderPipeline { .. }
983        | A::CreatePipelineCache { .. }
984        | A::CreateRenderBundle { .. }
985        | A::CreateQuerySet { .. }
986        | A::CreateBlas { .. }
987        | A::CreateTlas { .. } => panic!("Unsupported action for tracing: {action:?}"),
988    }
989}