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        }
366    }
367}
368
369impl IntoTrace for crate::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> {
370    type Output = crate::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>;
371    fn into_trace(self) -> Self::Output {
372        crate::ray_tracing::OwnedBlasTriangleGeometry {
373            size: self.size,
374            vertex_buffer: self.vertex_buffer.into_trace(),
375            index_buffer: self.index_buffer.map(|b| b.into_trace()),
376            transform_buffer: self.transform_buffer.map(|b| b.into_trace()),
377            first_vertex: self.first_vertex,
378            vertex_stride: self.vertex_stride,
379            first_index: self.first_index,
380            transform_buffer_offset: self.transform_buffer_offset,
381        }
382    }
383}
384
385impl IntoTrace for crate::ray_tracing::OwnedTlasPackage<ArcReferences> {
386    type Output = crate::ray_tracing::OwnedTlasPackage<PointerReferences>;
387    fn into_trace(self) -> Self::Output {
388        crate::ray_tracing::OwnedTlasPackage {
389            tlas: self.tlas.into_trace(),
390            instances: self
391                .instances
392                .into_iter()
393                .map(|opt| opt.map(|inst| inst.into_trace()))
394                .collect(),
395            lowest_unmodified: self.lowest_unmodified,
396        }
397    }
398}
399
400impl IntoTrace for crate::ray_tracing::OwnedTlasInstance<ArcReferences> {
401    type Output = crate::ray_tracing::OwnedTlasInstance<PointerReferences>;
402    fn into_trace(self) -> Self::Output {
403        crate::ray_tracing::OwnedTlasInstance {
404            blas: self.blas.into_trace(),
405            transform: self.transform,
406            custom_data: self.custom_data,
407            mask: self.mask,
408        }
409    }
410}
411
412impl<C: IntoTrace> IntoTrace for BasePass<C, Infallible> {
413    type Output = BasePass<C::Output, Infallible>;
414
415    fn into_trace(self) -> Self::Output {
416        BasePass {
417            label: self.label,
418            error: self.error,
419            commands: self
420                .commands
421                .into_iter()
422                .map(|cmd| cmd.into_trace())
423                .collect(),
424            dynamic_offsets: self.dynamic_offsets,
425            string_data: self.string_data,
426            immediates_data: self.immediates_data,
427        }
428    }
429}
430
431impl IntoTrace for ArcComputeCommand {
432    type Output = ComputeCommand<PointerReferences>;
433    fn into_trace(self) -> Self::Output {
434        use ComputeCommand as C;
435        match self {
436            C::SetBindGroup {
437                index,
438                num_dynamic_offsets,
439                bind_group,
440            } => C::SetBindGroup {
441                index,
442                num_dynamic_offsets,
443                bind_group: bind_group.map(|bg| bg.into_trace()),
444            },
445            C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
446            C::SetImmediate {
447                offset,
448                size_bytes,
449                values_offset,
450            } => C::SetImmediate {
451                offset,
452                size_bytes,
453                values_offset,
454            },
455            C::Dispatch(groups) => C::Dispatch(groups),
456            C::DispatchIndirect { buffer, offset } => C::DispatchIndirect {
457                buffer: buffer.into_trace(),
458                offset,
459            },
460            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
461            C::PopDebugGroup => C::PopDebugGroup,
462            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
463            C::WriteTimestamp {
464                query_set,
465                query_index,
466            } => C::WriteTimestamp {
467                query_set: query_set.into_trace(),
468                query_index,
469            },
470            C::BeginPipelineStatisticsQuery {
471                query_set,
472                query_index,
473            } => C::BeginPipelineStatisticsQuery {
474                query_set: query_set.into_trace(),
475                query_index,
476            },
477            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
478        }
479    }
480}
481
482impl IntoTrace for ArcRenderCommand {
483    type Output = RenderCommand<PointerReferences>;
484    fn into_trace(self) -> Self::Output {
485        use RenderCommand as C;
486        match self {
487            C::SetBindGroup {
488                index,
489                num_dynamic_offsets,
490                bind_group,
491            } => C::SetBindGroup {
492                index,
493                num_dynamic_offsets,
494                bind_group: bind_group.map(|bg| bg.into_trace()),
495            },
496            C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
497            C::SetIndexBuffer {
498                buffer,
499                index_format,
500                offset,
501                size,
502            } => C::SetIndexBuffer {
503                buffer: buffer.into_trace(),
504                index_format,
505                offset,
506                size,
507            },
508            C::SetVertexBuffer {
509                slot,
510                buffer,
511                offset,
512                size,
513            } => C::SetVertexBuffer {
514                slot,
515                buffer: buffer.into_trace(),
516                offset,
517                size,
518            },
519            C::SetBlendConstant(color) => C::SetBlendConstant(color),
520            C::SetStencilReference(val) => C::SetStencilReference(val),
521            C::SetViewport {
522                rect,
523                depth_min,
524                depth_max,
525            } => C::SetViewport {
526                rect,
527                depth_min,
528                depth_max,
529            },
530            C::SetScissor(rect) => C::SetScissor(rect),
531            C::SetImmediate {
532                offset,
533                size_bytes,
534                values_offset,
535            } => C::SetImmediate {
536                offset,
537                size_bytes,
538                values_offset,
539            },
540            C::Draw {
541                vertex_count,
542                instance_count,
543                first_vertex,
544                first_instance,
545            } => C::Draw {
546                vertex_count,
547                instance_count,
548                first_vertex,
549                first_instance,
550            },
551            C::DrawIndexed {
552                index_count,
553                instance_count,
554                first_index,
555                base_vertex,
556                first_instance,
557            } => C::DrawIndexed {
558                index_count,
559                instance_count,
560                first_index,
561                base_vertex,
562                first_instance,
563            },
564            C::DrawMeshTasks {
565                group_count_x,
566                group_count_y,
567                group_count_z,
568            } => C::DrawMeshTasks {
569                group_count_x,
570                group_count_y,
571                group_count_z,
572            },
573            C::DrawIndirect {
574                buffer,
575                offset,
576                count,
577                family,
578                vertex_or_index_limit,
579                instance_limit,
580            } => C::DrawIndirect {
581                buffer: buffer.into_trace(),
582                offset,
583                count,
584                family,
585                vertex_or_index_limit,
586                instance_limit,
587            },
588            C::MultiDrawIndirectCount {
589                buffer,
590                offset,
591                count_buffer,
592                count_buffer_offset,
593                max_count,
594                family,
595            } => C::MultiDrawIndirectCount {
596                buffer: buffer.into_trace(),
597                offset,
598                count_buffer: count_buffer.into_trace(),
599                count_buffer_offset,
600                max_count,
601                family,
602            },
603            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
604            C::PopDebugGroup => C::PopDebugGroup,
605            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
606            C::WriteTimestamp {
607                query_set,
608                query_index,
609            } => C::WriteTimestamp {
610                query_set: query_set.into_trace(),
611                query_index,
612            },
613            C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index },
614            C::EndOcclusionQuery => C::EndOcclusionQuery,
615            C::BeginPipelineStatisticsQuery {
616                query_set,
617                query_index,
618            } => C::BeginPipelineStatisticsQuery {
619                query_set: query_set.into_trace(),
620                query_index,
621            },
622            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
623            C::ExecuteBundle(bundle) => C::ExecuteBundle(bundle.into_trace()),
624        }
625    }
626}
627
628impl IntoTrace for crate::binding_model::ResolvedPipelineLayoutDescriptor<'_> {
629    type Output = crate::binding_model::PipelineLayoutDescriptor<
630        'static,
631        PointerId<markers::BindGroupLayout>,
632    >;
633    fn into_trace(self) -> Self::Output {
634        crate::binding_model::PipelineLayoutDescriptor {
635            label: self.label.map(|l| Cow::Owned(l.into_owned())),
636            bind_group_layouts: self
637                .bind_group_layouts
638                .iter()
639                .map(|bgl| bgl.to_trace())
640                .collect(),
641            immediate_size: self.immediate_size,
642        }
643    }
644}
645
646impl<'a> IntoTrace for &'_ crate::binding_model::ResolvedBindGroupDescriptor<'a> {
647    type Output = TraceBindGroupDescriptor<'a>;
648
649    fn into_trace(self) -> Self::Output {
650        use crate::binding_model::{
651            BindGroupEntry, BindingResource, BufferBinding, ResolvedBindingResource,
652        };
653        TraceBindGroupDescriptor {
654            label: self.label.clone(),
655            layout: self.layout.to_trace(),
656            entries: Cow::Owned(
657                self.entries
658                    .iter()
659                    .map(|entry| {
660                        let resource = match &entry.resource {
661                            ResolvedBindingResource::Buffer(buffer_binding) => {
662                                BindingResource::Buffer(BufferBinding {
663                                    buffer: buffer_binding.buffer.to_trace(),
664                                    offset: buffer_binding.offset,
665                                    size: buffer_binding.size,
666                                })
667                            }
668                            ResolvedBindingResource::BufferArray(buffer_bindings) => {
669                                let resolved_buffers: Vec<_> = buffer_bindings
670                                    .iter()
671                                    .map(|bb| BufferBinding {
672                                        buffer: bb.buffer.to_trace(),
673                                        offset: bb.offset,
674                                        size: bb.size,
675                                    })
676                                    .collect();
677                                BindingResource::BufferArray(Cow::Owned(resolved_buffers))
678                            }
679                            ResolvedBindingResource::Sampler(sampler_id) => {
680                                BindingResource::Sampler(sampler_id.to_trace())
681                            }
682                            ResolvedBindingResource::SamplerArray(sampler_ids) => {
683                                let resolved: Vec<_> =
684                                    sampler_ids.iter().map(|id| id.to_trace()).collect();
685                                BindingResource::SamplerArray(Cow::Owned(resolved))
686                            }
687                            ResolvedBindingResource::TextureView(texture_view_id) => {
688                                BindingResource::TextureView(texture_view_id.to_trace())
689                            }
690                            ResolvedBindingResource::TextureViewArray(texture_view_ids) => {
691                                let resolved: Vec<_> =
692                                    texture_view_ids.iter().map(|id| id.to_trace()).collect();
693                                BindingResource::TextureViewArray(Cow::Owned(resolved))
694                            }
695                            ResolvedBindingResource::AccelerationStructure(tlas_id) => {
696                                BindingResource::AccelerationStructure(tlas_id.to_trace())
697                            }
698                            ResolvedBindingResource::ExternalTexture(external_texture_id) => {
699                                BindingResource::ExternalTexture(external_texture_id.to_trace())
700                            }
701                        };
702                        BindGroupEntry {
703                            binding: entry.binding,
704                            resource,
705                        }
706                    })
707                    .collect(),
708            ),
709        }
710    }
711}
712
713impl<'a> IntoTrace for crate::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> {
714    type Output = TraceGeneralRenderPipelineDescriptor<'a>;
715
716    fn into_trace(self) -> Self::Output {
717        TraceGeneralRenderPipelineDescriptor {
718            label: self.label,
719            layout: self.layout.into_trace(),
720            vertex: self.vertex.into_trace(),
721            primitive: self.primitive,
722            depth_stencil: self.depth_stencil,
723            multisample: self.multisample,
724            fragment: self.fragment.map(|f| f.into_trace()),
725            multiview_mask: self.multiview_mask,
726            cache: self.cache.map(|c| c.into_trace()),
727        }
728    }
729}
730
731impl<'a> IntoTrace for crate::pipeline::ResolvedComputePipelineDescriptor<'a> {
732    type Output = TraceComputePipelineDescriptor<'a>;
733
734    fn into_trace(self) -> Self::Output {
735        TraceComputePipelineDescriptor {
736            label: self.label,
737            layout: self.layout.into_trace(),
738            stage: self.stage.into_trace(),
739            cache: self.cache.map(|c| c.into_trace()),
740        }
741    }
742}
743
744impl<'a> IntoTrace for crate::pipeline::ResolvedProgrammableStageDescriptor<'a> {
745    type Output =
746        crate::pipeline::ProgrammableStageDescriptor<'a, PointerId<markers::ShaderModule>>;
747    fn into_trace(self) -> Self::Output {
748        crate::pipeline::ProgrammableStageDescriptor {
749            module: self.module.into_trace(),
750            entry_point: self.entry_point,
751            constants: self.constants,
752            zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
753        }
754    }
755}
756
757impl<'a> IntoTrace
758    for crate::pipeline::RenderPipelineVertexProcessor<'a, Arc<crate::pipeline::ShaderModule>>
759{
760    type Output =
761        crate::pipeline::RenderPipelineVertexProcessor<'a, PointerId<markers::ShaderModule>>;
762    fn into_trace(self) -> Self::Output {
763        match self {
764            crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex) => {
765                crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex.into_trace())
766            }
767            crate::pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => {
768                crate::pipeline::RenderPipelineVertexProcessor::Mesh(
769                    task.map(|t| t.into_trace()),
770                    mesh.into_trace(),
771                )
772            }
773        }
774    }
775}
776
777impl<'a> IntoTrace for crate::pipeline::ResolvedTaskState<'a> {
778    type Output = crate::pipeline::TaskState<'a, PointerId<markers::ShaderModule>>;
779    fn into_trace(self) -> Self::Output {
780        crate::pipeline::TaskState {
781            stage: self.stage.into_trace(),
782        }
783    }
784}
785
786impl<'a> IntoTrace for crate::pipeline::ResolvedMeshState<'a> {
787    type Output = crate::pipeline::MeshState<'a, PointerId<markers::ShaderModule>>;
788    fn into_trace(self) -> Self::Output {
789        crate::pipeline::MeshState {
790            stage: self.stage.into_trace(),
791        }
792    }
793}
794
795impl<'a> IntoTrace for crate::pipeline::ResolvedVertexState<'a> {
796    type Output = crate::pipeline::VertexState<'a, PointerId<markers::ShaderModule>>;
797    fn into_trace(self) -> Self::Output {
798        crate::pipeline::VertexState {
799            stage: self.stage.into_trace(),
800            buffers: self.buffers,
801        }
802    }
803}
804
805impl<'a> IntoTrace for crate::pipeline::ResolvedFragmentState<'a> {
806    type Output = crate::pipeline::FragmentState<'a, PointerId<markers::ShaderModule>>;
807    fn into_trace(self) -> Self::Output {
808        crate::pipeline::FragmentState {
809            stage: self.stage.into_trace(),
810            targets: self.targets,
811        }
812    }
813}
814
815impl<T: IntoTrace> IntoTrace for Option<T> {
816    type Output = Option<T::Output>;
817    fn into_trace(self) -> Self::Output {
818        self.map(|v| v.into_trace())
819    }
820}
821
822/// For selected `Action`s (mostly actions containing only owned data), return a
823/// copy with `'static` lifetime.
824///
825/// This is used for in-memory tracing.
826///
827/// # Panics
828///
829/// If `action` is not supported for in-memory tracing (likely because it
830/// contains borrowed data).
831fn action_to_owned(action: Action<'_, PointerReferences>) -> Action<'static, PointerReferences> {
832    use Action as A;
833    match action {
834        A::Init { desc, backend } => A::Init {
835            desc: wgt::DeviceDescriptor {
836                label: desc.label.map(|l| Cow::Owned(l.into_owned())),
837                required_features: desc.required_features,
838                required_limits: desc.required_limits,
839                experimental_features: desc.experimental_features,
840                memory_hints: desc.memory_hints,
841                trace: desc.trace,
842            },
843            backend,
844        },
845        A::ConfigureSurface(surface, config) => A::ConfigureSurface(surface, config),
846        A::CreateBuffer(buffer, desc) => A::CreateBuffer(
847            buffer,
848            wgt::BufferDescriptor {
849                label: desc.label.map(|l| Cow::Owned(l.into_owned())),
850                size: desc.size,
851                usage: desc.usage,
852                mapped_at_creation: desc.mapped_at_creation,
853            },
854        ),
855        A::FreeBuffer(buffer) => A::FreeBuffer(buffer),
856        A::DestroyBuffer(buffer) => A::DestroyBuffer(buffer),
857        A::FreeTexture(texture) => A::FreeTexture(texture),
858        A::DestroyTexture(texture) => A::DestroyTexture(texture),
859        A::DestroyTextureView(texture_view) => A::DestroyTextureView(texture_view),
860        A::FreeExternalTexture(external_texture) => A::FreeExternalTexture(external_texture),
861        A::DestroyExternalTexture(external_texture) => A::DestroyExternalTexture(external_texture),
862        A::DestroySampler(sampler) => A::DestroySampler(sampler),
863        A::GetSurfaceTexture { id, parent } => A::GetSurfaceTexture { id, parent },
864        A::Present(surface) => A::Present(surface),
865        A::DiscardSurfaceTexture(surface) => A::DiscardSurfaceTexture(surface),
866        A::DestroyBindGroupLayout(layout) => A::DestroyBindGroupLayout(layout),
867        A::GetRenderPipelineBindGroupLayout {
868            id,
869            pipeline,
870            index,
871        } => A::GetRenderPipelineBindGroupLayout {
872            id,
873            pipeline,
874            index,
875        },
876        A::GetComputePipelineBindGroupLayout {
877            id,
878            pipeline,
879            index,
880        } => A::GetComputePipelineBindGroupLayout {
881            id,
882            pipeline,
883            index,
884        },
885        A::DestroyPipelineLayout(layout) => A::DestroyPipelineLayout(layout),
886        A::DestroyBindGroup(bind_group) => A::DestroyBindGroup(bind_group),
887        A::DestroyShaderModule(shader_module) => A::DestroyShaderModule(shader_module),
888        A::DestroyComputePipeline(pipeline) => A::DestroyComputePipeline(pipeline),
889        A::DestroyRenderPipeline(pipeline) => A::DestroyRenderPipeline(pipeline),
890        A::DestroyPipelineCache(cache) => A::DestroyPipelineCache(cache),
891        A::DestroyRenderBundle(render_bundle) => A::DestroyRenderBundle(render_bundle),
892        A::DestroyQuerySet(query_set) => A::DestroyQuerySet(query_set),
893        A::WriteBuffer {
894            id,
895            data,
896            range,
897            queued,
898        } => A::WriteBuffer {
899            id,
900            data,
901            range,
902            queued,
903        },
904        A::WriteTexture {
905            to,
906            data,
907            layout,
908            size,
909        } => A::WriteTexture {
910            to,
911            data,
912            layout,
913            size,
914        },
915        A::Submit(index, commands) => A::Submit(index, commands),
916        A::FailedCommands {
917            commands,
918            failed_at_submit,
919            error,
920        } => A::FailedCommands {
921            commands,
922            failed_at_submit,
923            error,
924        },
925        A::DestroyBlas(blas) => A::DestroyBlas(blas),
926        A::DestroyTlas(tlas) => A::DestroyTlas(tlas),
927
928        A::CreateTexture(..)
929        | A::CreateTextureView { .. }
930        | A::CreateExternalTexture { .. }
931        | A::CreateSampler(..)
932        | A::CreateBindGroupLayout(..)
933        | A::CreatePipelineLayout(..)
934        | A::CreateBindGroup(..)
935        | A::CreateShaderModule { .. }
936        | A::CreateShaderModulePassthrough { .. }
937        | A::CreateComputePipeline { .. }
938        | A::CreateGeneralRenderPipeline { .. }
939        | A::CreatePipelineCache { .. }
940        | A::CreateRenderBundle { .. }
941        | A::CreateQuerySet { .. }
942        | A::CreateBlas { .. }
943        | A::CreateTlas { .. } => panic!("Unsupported action for tracing: {action:?}"),
944    }
945}