wgpu_core/device/trace/
record.rs

1use alloc::{
2    borrow::Cow,
3    string::{String, ToString},
4    sync::Arc,
5    vec::Vec,
6};
7use core::convert::Infallible;
8use std::io::Write as _;
9
10use crate::{
11    command::{
12        ArcCommand, ArcComputeCommand, ArcPassTimestampWrites, ArcReferences, ArcRenderCommand,
13        BasePass, ColorAttachments, Command, ComputeCommand, PointerReferences, RenderCommand,
14        RenderPassColorAttachment, ResolvedRenderPassDepthStencilAttachment,
15    },
16    id::{markers, PointerId},
17    storage::StorageItem,
18};
19
20use super::{
21    Action, TraceBindGroupDescriptor, TraceComputePipelineDescriptor,
22    TraceGeneralRenderPipelineDescriptor, FILE_NAME,
23};
24
25pub(crate) fn new_render_bundle_encoder_descriptor(
26    label: crate::Label<'_>,
27    context: &crate::device::RenderPassContext,
28    depth_read_only: bool,
29    stencil_read_only: bool,
30) -> crate::command::RenderBundleEncoderDescriptor<'static> {
31    crate::command::RenderBundleEncoderDescriptor {
32        label: label.map(|l| Cow::from(l.to_string())),
33        color_formats: Cow::from(context.attachments.colors.to_vec()),
34        depth_stencil: context.attachments.depth_stencil.map(|format| {
35            wgt::RenderBundleDepthStencil {
36                format,
37                depth_read_only,
38                stencil_read_only,
39            }
40        }),
41        sample_count: context.sample_count,
42        multiview: context.multiview_mask,
43    }
44}
45
46#[derive(Debug)]
47pub struct Trace {
48    path: std::path::PathBuf,
49    file: std::fs::File,
50    config: ron::ser::PrettyConfig,
51    binary_id: usize,
52}
53
54impl Trace {
55    pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> {
56        log::debug!("Tracing into '{path:?}'");
57        let mut file = std::fs::File::create(path.join(FILE_NAME))?;
58        file.write_all(b"[\n")?;
59        Ok(Self {
60            path,
61            file,
62            config: ron::ser::PrettyConfig::default(),
63            binary_id: 0,
64        })
65    }
66
67    pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String {
68        self.binary_id += 1;
69        let name = std::format!("data{}.{}", self.binary_id, kind);
70        let _ = std::fs::write(self.path.join(&name), data);
71        name
72    }
73
74    pub(crate) fn add(&mut self, action: Action<'_, PointerReferences>)
75    where
76        for<'a> Action<'a, PointerReferences>: serde::Serialize,
77    {
78        match ron::ser::to_string_pretty(&action, self.config.clone()) {
79            Ok(string) => {
80                let _ = writeln!(self.file, "{string},");
81            }
82            Err(e) => {
83                log::warn!("RON serialization failure: {e:?}");
84            }
85        }
86    }
87}
88
89impl Drop for Trace {
90    fn drop(&mut self) {
91        let _ = self.file.write_all(b"]");
92    }
93}
94
95pub(crate) trait IntoTrace {
96    type Output;
97    fn into_trace(self) -> Self::Output;
98
99    fn to_trace(&self) -> Self::Output
100    where
101        Self: Sized + Clone,
102    {
103        self.clone().into_trace()
104    }
105}
106
107impl<T: StorageItem> IntoTrace for Arc<T> {
108    type Output = PointerId<T::Marker>;
109    fn into_trace(self) -> Self::Output {
110        self.to_trace()
111    }
112
113    fn to_trace(&self) -> Self::Output {
114        PointerId::from(self)
115    }
116}
117
118impl IntoTrace for ArcCommand {
119    type Output = Command<PointerReferences>;
120    fn into_trace(self) -> Self::Output {
121        match self {
122            ArcCommand::CopyBufferToBuffer {
123                src,
124                src_offset,
125                dst,
126                dst_offset,
127                size,
128            } => Command::CopyBufferToBuffer {
129                src: src.to_trace(),
130                src_offset,
131                dst: dst.to_trace(),
132                dst_offset,
133                size,
134            },
135            ArcCommand::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture {
136                src: src.into_trace(),
137                dst: dst.into_trace(),
138                size,
139            },
140            ArcCommand::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer {
141                src: src.into_trace(),
142                dst: dst.into_trace(),
143                size,
144            },
145            ArcCommand::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture {
146                src: src.into_trace(),
147                dst: dst.into_trace(),
148                size,
149            },
150            ArcCommand::ClearBuffer { dst, offset, size } => Command::ClearBuffer {
151                dst: dst.to_trace(),
152                offset,
153                size,
154            },
155            ArcCommand::ClearTexture {
156                dst,
157                subresource_range,
158            } => Command::ClearTexture {
159                dst: dst.to_trace(),
160                subresource_range,
161            },
162            ArcCommand::WriteTimestamp {
163                query_set,
164                query_index,
165            } => Command::WriteTimestamp {
166                query_set: query_set.to_trace(),
167                query_index,
168            },
169            ArcCommand::ResolveQuerySet {
170                query_set,
171                start_query,
172                query_count,
173                destination,
174                destination_offset,
175            } => Command::ResolveQuerySet {
176                query_set: query_set.to_trace(),
177                start_query,
178                query_count,
179                destination: destination.to_trace(),
180                destination_offset,
181            },
182            ArcCommand::PushDebugGroup(label) => Command::PushDebugGroup(label),
183            ArcCommand::PopDebugGroup => Command::PopDebugGroup,
184            ArcCommand::InsertDebugMarker(label) => Command::InsertDebugMarker(label),
185            ArcCommand::RunComputePass {
186                pass,
187                timestamp_writes,
188            } => Command::RunComputePass {
189                pass: pass.into_trace(),
190                timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
191            },
192            ArcCommand::RunRenderPass {
193                pass,
194                color_attachments,
195                depth_stencil_attachment,
196                timestamp_writes,
197                occlusion_query_set,
198                multiview_mask,
199            } => Command::RunRenderPass {
200                pass: pass.into_trace(),
201                color_attachments: color_attachments.into_trace(),
202                depth_stencil_attachment: depth_stencil_attachment.map(|d| d.into_trace()),
203                timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
204                occlusion_query_set: occlusion_query_set.map(|q| q.to_trace()),
205                multiview_mask,
206            },
207            ArcCommand::BuildAccelerationStructures { blas, tlas } => {
208                Command::BuildAccelerationStructures {
209                    blas: blas.into_iter().map(|b| b.into_trace()).collect(),
210                    tlas: tlas.into_iter().map(|b| b.into_trace()).collect(),
211                }
212            }
213            ArcCommand::TransitionResources {
214                buffer_transitions: _,
215                texture_transitions: _,
216            } => {
217                // TransitionResources does not exist in Command, so skip or handle as needed.
218                // If you want to ignore, you could panic or return a default.
219                panic!("TransitionResources cannot be converted to Command");
220            }
221        }
222    }
223}
224
225impl<T: IntoTrace> IntoTrace for wgt::TexelCopyBufferInfo<T> {
226    type Output = wgt::TexelCopyBufferInfo<T::Output>;
227    fn into_trace(self) -> Self::Output {
228        wgt::TexelCopyBufferInfo {
229            buffer: self.buffer.into_trace(),
230            layout: self.layout,
231        }
232    }
233}
234
235impl<T: IntoTrace> IntoTrace for wgt::TexelCopyTextureInfo<T> {
236    type Output = wgt::TexelCopyTextureInfo<T::Output>;
237    fn into_trace(self) -> Self::Output {
238        wgt::TexelCopyTextureInfo {
239            texture: self.texture.into_trace(),
240            mip_level: self.mip_level,
241            origin: self.origin,
242            aspect: self.aspect,
243        }
244    }
245}
246
247impl IntoTrace for ArcPassTimestampWrites {
248    type Output = crate::command::PassTimestampWrites<PointerId<markers::QuerySet>>;
249    fn into_trace(self) -> Self::Output {
250        crate::command::PassTimestampWrites {
251            query_set: self.query_set.into_trace(),
252            beginning_of_pass_write_index: self.beginning_of_pass_write_index,
253            end_of_pass_write_index: self.end_of_pass_write_index,
254        }
255    }
256}
257
258impl IntoTrace for ColorAttachments {
259    type Output = ColorAttachments<PointerId<markers::TextureView>>;
260    fn into_trace(self) -> Self::Output {
261        self.into_iter()
262            .map(|opt| {
263                opt.map(|att| RenderPassColorAttachment {
264                    view: att.view.into_trace(),
265                    depth_slice: att.depth_slice,
266                    resolve_target: att.resolve_target.map(|r| r.into_trace()),
267                    load_op: att.load_op,
268                    store_op: att.store_op,
269                })
270            })
271            .collect()
272    }
273}
274
275impl<TV: IntoTrace> IntoTrace for ResolvedRenderPassDepthStencilAttachment<TV> {
276    type Output = ResolvedRenderPassDepthStencilAttachment<TV::Output>;
277    fn into_trace(self) -> Self::Output {
278        ResolvedRenderPassDepthStencilAttachment {
279            view: self.view.into_trace(),
280            depth: self.depth,
281            stencil: self.stencil,
282        }
283    }
284}
285
286impl IntoTrace for crate::ray_tracing::OwnedBlasBuildEntry<ArcReferences> {
287    type Output = crate::ray_tracing::OwnedBlasBuildEntry<PointerReferences>;
288    fn into_trace(self) -> Self::Output {
289        crate::ray_tracing::OwnedBlasBuildEntry {
290            blas: self.blas.into_trace(),
291            geometries: self.geometries.into_trace(),
292        }
293    }
294}
295
296impl IntoTrace for crate::ray_tracing::OwnedBlasGeometries<ArcReferences> {
297    type Output = crate::ray_tracing::OwnedBlasGeometries<PointerReferences>;
298    fn into_trace(self) -> Self::Output {
299        match self {
300            crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => {
301                crate::ray_tracing::OwnedBlasGeometries::TriangleGeometries(
302                    geos.into_iter().map(|g| g.into_trace()).collect(),
303                )
304            }
305        }
306    }
307}
308
309impl IntoTrace for crate::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> {
310    type Output = crate::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>;
311    fn into_trace(self) -> Self::Output {
312        crate::ray_tracing::OwnedBlasTriangleGeometry {
313            size: self.size,
314            vertex_buffer: self.vertex_buffer.into_trace(),
315            index_buffer: self.index_buffer.map(|b| b.into_trace()),
316            transform_buffer: self.transform_buffer.map(|b| b.into_trace()),
317            first_vertex: self.first_vertex,
318            vertex_stride: self.vertex_stride,
319            first_index: self.first_index,
320            transform_buffer_offset: self.transform_buffer_offset,
321        }
322    }
323}
324
325impl IntoTrace for crate::ray_tracing::OwnedTlasPackage<ArcReferences> {
326    type Output = crate::ray_tracing::OwnedTlasPackage<PointerReferences>;
327    fn into_trace(self) -> Self::Output {
328        crate::ray_tracing::OwnedTlasPackage {
329            tlas: self.tlas.into_trace(),
330            instances: self
331                .instances
332                .into_iter()
333                .map(|opt| opt.map(|inst| inst.into_trace()))
334                .collect(),
335            lowest_unmodified: self.lowest_unmodified,
336        }
337    }
338}
339
340impl IntoTrace for crate::ray_tracing::OwnedTlasInstance<ArcReferences> {
341    type Output = crate::ray_tracing::OwnedTlasInstance<PointerReferences>;
342    fn into_trace(self) -> Self::Output {
343        crate::ray_tracing::OwnedTlasInstance {
344            blas: self.blas.into_trace(),
345            transform: self.transform,
346            custom_data: self.custom_data,
347            mask: self.mask,
348        }
349    }
350}
351
352impl<C: IntoTrace> IntoTrace for BasePass<C, Infallible> {
353    type Output = BasePass<C::Output, Infallible>;
354
355    fn into_trace(self) -> Self::Output {
356        BasePass {
357            label: self.label,
358            error: self.error,
359            commands: self
360                .commands
361                .into_iter()
362                .map(|cmd| cmd.into_trace())
363                .collect(),
364            dynamic_offsets: self.dynamic_offsets,
365            string_data: self.string_data,
366            immediates_data: self.immediates_data,
367        }
368    }
369}
370
371impl IntoTrace for ArcComputeCommand {
372    type Output = ComputeCommand<PointerReferences>;
373    fn into_trace(self) -> Self::Output {
374        use ComputeCommand as C;
375        match self {
376            C::SetBindGroup {
377                index,
378                num_dynamic_offsets,
379                bind_group,
380            } => C::SetBindGroup {
381                index,
382                num_dynamic_offsets,
383                bind_group: bind_group.map(|bg| bg.into_trace()),
384            },
385            C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
386            C::SetImmediate {
387                offset,
388                size_bytes,
389                values_offset,
390            } => C::SetImmediate {
391                offset,
392                size_bytes,
393                values_offset,
394            },
395            C::Dispatch(groups) => C::Dispatch(groups),
396            C::DispatchIndirect { buffer, offset } => C::DispatchIndirect {
397                buffer: buffer.into_trace(),
398                offset,
399            },
400            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
401            C::PopDebugGroup => C::PopDebugGroup,
402            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
403            C::WriteTimestamp {
404                query_set,
405                query_index,
406            } => C::WriteTimestamp {
407                query_set: query_set.into_trace(),
408                query_index,
409            },
410            C::BeginPipelineStatisticsQuery {
411                query_set,
412                query_index,
413            } => C::BeginPipelineStatisticsQuery {
414                query_set: query_set.into_trace(),
415                query_index,
416            },
417            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
418        }
419    }
420}
421
422impl IntoTrace for ArcRenderCommand {
423    type Output = RenderCommand<PointerReferences>;
424    fn into_trace(self) -> Self::Output {
425        use RenderCommand as C;
426        match self {
427            C::SetBindGroup {
428                index,
429                num_dynamic_offsets,
430                bind_group,
431            } => C::SetBindGroup {
432                index,
433                num_dynamic_offsets,
434                bind_group: bind_group.map(|bg| bg.into_trace()),
435            },
436            C::SetPipeline(id) => C::SetPipeline(id.into_trace()),
437            C::SetIndexBuffer {
438                buffer,
439                index_format,
440                offset,
441                size,
442            } => C::SetIndexBuffer {
443                buffer: buffer.into_trace(),
444                index_format,
445                offset,
446                size,
447            },
448            C::SetVertexBuffer {
449                slot,
450                buffer,
451                offset,
452                size,
453            } => C::SetVertexBuffer {
454                slot,
455                buffer: buffer.into_trace(),
456                offset,
457                size,
458            },
459            C::SetBlendConstant(color) => C::SetBlendConstant(color),
460            C::SetStencilReference(val) => C::SetStencilReference(val),
461            C::SetViewport {
462                rect,
463                depth_min,
464                depth_max,
465            } => C::SetViewport {
466                rect,
467                depth_min,
468                depth_max,
469            },
470            C::SetScissor(rect) => C::SetScissor(rect),
471            C::SetImmediate {
472                offset,
473                size_bytes,
474                values_offset,
475            } => C::SetImmediate {
476                offset,
477                size_bytes,
478                values_offset,
479            },
480            C::Draw {
481                vertex_count,
482                instance_count,
483                first_vertex,
484                first_instance,
485            } => C::Draw {
486                vertex_count,
487                instance_count,
488                first_vertex,
489                first_instance,
490            },
491            C::DrawIndexed {
492                index_count,
493                instance_count,
494                first_index,
495                base_vertex,
496                first_instance,
497            } => C::DrawIndexed {
498                index_count,
499                instance_count,
500                first_index,
501                base_vertex,
502                first_instance,
503            },
504            C::DrawMeshTasks {
505                group_count_x,
506                group_count_y,
507                group_count_z,
508            } => C::DrawMeshTasks {
509                group_count_x,
510                group_count_y,
511                group_count_z,
512            },
513            C::DrawIndirect {
514                buffer,
515                offset,
516                count,
517                family,
518                vertex_or_index_limit,
519                instance_limit,
520            } => C::DrawIndirect {
521                buffer: buffer.into_trace(),
522                offset,
523                count,
524                family,
525                vertex_or_index_limit,
526                instance_limit,
527            },
528            C::MultiDrawIndirectCount {
529                buffer,
530                offset,
531                count_buffer,
532                count_buffer_offset,
533                max_count,
534                family,
535            } => C::MultiDrawIndirectCount {
536                buffer: buffer.into_trace(),
537                offset,
538                count_buffer: count_buffer.into_trace(),
539                count_buffer_offset,
540                max_count,
541                family,
542            },
543            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
544            C::PopDebugGroup => C::PopDebugGroup,
545            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
546            C::WriteTimestamp {
547                query_set,
548                query_index,
549            } => C::WriteTimestamp {
550                query_set: query_set.into_trace(),
551                query_index,
552            },
553            C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index },
554            C::EndOcclusionQuery => C::EndOcclusionQuery,
555            C::BeginPipelineStatisticsQuery {
556                query_set,
557                query_index,
558            } => C::BeginPipelineStatisticsQuery {
559                query_set: query_set.into_trace(),
560                query_index,
561            },
562            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
563            C::ExecuteBundle(bundle) => C::ExecuteBundle(bundle.into_trace()),
564        }
565    }
566}
567
568impl<'a> IntoTrace for crate::binding_model::ResolvedPipelineLayoutDescriptor<'a> {
569    type Output =
570        crate::binding_model::PipelineLayoutDescriptor<'a, PointerId<markers::BindGroupLayout>>;
571    fn into_trace(self) -> Self::Output {
572        crate::binding_model::PipelineLayoutDescriptor {
573            label: self.label.map(|l| Cow::Owned(l.into_owned())),
574            bind_group_layouts: self
575                .bind_group_layouts
576                .iter()
577                .map(|bgl| bgl.to_trace())
578                .collect(),
579            immediate_size: self.immediate_size,
580        }
581    }
582}
583
584impl<'a> IntoTrace for &'_ crate::binding_model::ResolvedBindGroupDescriptor<'a> {
585    type Output = TraceBindGroupDescriptor<'a>;
586
587    fn into_trace(self) -> Self::Output {
588        use crate::binding_model::{
589            BindGroupEntry, BindingResource, BufferBinding, ResolvedBindingResource,
590        };
591        TraceBindGroupDescriptor {
592            label: self.label.clone(),
593            layout: self.layout.to_trace(),
594            entries: Cow::Owned(
595                self.entries
596                    .iter()
597                    .map(|entry| {
598                        let resource = match &entry.resource {
599                            ResolvedBindingResource::Buffer(buffer_binding) => {
600                                BindingResource::Buffer(BufferBinding {
601                                    buffer: buffer_binding.buffer.to_trace(),
602                                    offset: buffer_binding.offset,
603                                    size: buffer_binding.size,
604                                })
605                            }
606                            ResolvedBindingResource::BufferArray(buffer_bindings) => {
607                                let resolved_buffers: Vec<_> = buffer_bindings
608                                    .iter()
609                                    .map(|bb| BufferBinding {
610                                        buffer: bb.buffer.to_trace(),
611                                        offset: bb.offset,
612                                        size: bb.size,
613                                    })
614                                    .collect();
615                                BindingResource::BufferArray(Cow::Owned(resolved_buffers))
616                            }
617                            ResolvedBindingResource::Sampler(sampler_id) => {
618                                BindingResource::Sampler(sampler_id.to_trace())
619                            }
620                            ResolvedBindingResource::SamplerArray(sampler_ids) => {
621                                let resolved: Vec<_> =
622                                    sampler_ids.iter().map(|id| id.to_trace()).collect();
623                                BindingResource::SamplerArray(Cow::Owned(resolved))
624                            }
625                            ResolvedBindingResource::TextureView(texture_view_id) => {
626                                BindingResource::TextureView(texture_view_id.to_trace())
627                            }
628                            ResolvedBindingResource::TextureViewArray(texture_view_ids) => {
629                                let resolved: Vec<_> =
630                                    texture_view_ids.iter().map(|id| id.to_trace()).collect();
631                                BindingResource::TextureViewArray(Cow::Owned(resolved))
632                            }
633                            ResolvedBindingResource::AccelerationStructure(tlas_id) => {
634                                BindingResource::AccelerationStructure(tlas_id.to_trace())
635                            }
636                            ResolvedBindingResource::ExternalTexture(external_texture_id) => {
637                                BindingResource::ExternalTexture(external_texture_id.to_trace())
638                            }
639                        };
640                        BindGroupEntry {
641                            binding: entry.binding,
642                            resource,
643                        }
644                    })
645                    .collect(),
646            ),
647        }
648    }
649}
650
651impl<'a> IntoTrace for crate::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> {
652    type Output = TraceGeneralRenderPipelineDescriptor<'a>;
653
654    fn into_trace(self) -> Self::Output {
655        TraceGeneralRenderPipelineDescriptor {
656            label: self.label,
657            layout: self.layout.into_trace(),
658            vertex: self.vertex.into_trace(),
659            primitive: self.primitive,
660            depth_stencil: self.depth_stencil,
661            multisample: self.multisample,
662            fragment: self.fragment.map(|f| f.into_trace()),
663            multiview_mask: self.multiview_mask,
664            cache: self.cache.map(|c| c.into_trace()),
665        }
666    }
667}
668
669impl<'a> IntoTrace for crate::pipeline::ResolvedComputePipelineDescriptor<'a> {
670    type Output = TraceComputePipelineDescriptor<'a>;
671
672    fn into_trace(self) -> Self::Output {
673        TraceComputePipelineDescriptor {
674            label: self.label,
675            layout: self.layout.into_trace(),
676            stage: self.stage.into_trace(),
677            cache: self.cache.map(|c| c.into_trace()),
678        }
679    }
680}
681
682impl<'a> IntoTrace for crate::pipeline::ResolvedProgrammableStageDescriptor<'a> {
683    type Output =
684        crate::pipeline::ProgrammableStageDescriptor<'a, PointerId<markers::ShaderModule>>;
685    fn into_trace(self) -> Self::Output {
686        crate::pipeline::ProgrammableStageDescriptor {
687            module: self.module.into_trace(),
688            entry_point: self.entry_point,
689            constants: self.constants,
690            zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
691        }
692    }
693}
694
695impl<'a> IntoTrace
696    for crate::pipeline::RenderPipelineVertexProcessor<'a, Arc<crate::pipeline::ShaderModule>>
697{
698    type Output =
699        crate::pipeline::RenderPipelineVertexProcessor<'a, PointerId<markers::ShaderModule>>;
700    fn into_trace(self) -> Self::Output {
701        match self {
702            crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex) => {
703                crate::pipeline::RenderPipelineVertexProcessor::Vertex(vertex.into_trace())
704            }
705            crate::pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => {
706                crate::pipeline::RenderPipelineVertexProcessor::Mesh(
707                    task.map(|t| t.into_trace()),
708                    mesh.into_trace(),
709                )
710            }
711        }
712    }
713}
714
715impl<'a> IntoTrace for crate::pipeline::ResolvedTaskState<'a> {
716    type Output = crate::pipeline::TaskState<'a, PointerId<markers::ShaderModule>>;
717    fn into_trace(self) -> Self::Output {
718        crate::pipeline::TaskState {
719            stage: self.stage.into_trace(),
720        }
721    }
722}
723
724impl<'a> IntoTrace for crate::pipeline::ResolvedMeshState<'a> {
725    type Output = crate::pipeline::MeshState<'a, PointerId<markers::ShaderModule>>;
726    fn into_trace(self) -> Self::Output {
727        crate::pipeline::MeshState {
728            stage: self.stage.into_trace(),
729        }
730    }
731}
732
733impl<'a> IntoTrace for crate::pipeline::ResolvedVertexState<'a> {
734    type Output = crate::pipeline::VertexState<'a, PointerId<markers::ShaderModule>>;
735    fn into_trace(self) -> Self::Output {
736        crate::pipeline::VertexState {
737            stage: self.stage.into_trace(),
738            buffers: self.buffers,
739        }
740    }
741}
742
743impl<'a> IntoTrace for crate::pipeline::ResolvedFragmentState<'a> {
744    type Output = crate::pipeline::FragmentState<'a, PointerId<markers::ShaderModule>>;
745    fn into_trace(self) -> Self::Output {
746        crate::pipeline::FragmentState {
747            stage: self.stage.into_trace(),
748            targets: self.targets,
749        }
750    }
751}
752
753impl<T: IntoTrace> IntoTrace for Option<T> {
754    type Output = Option<T::Output>;
755    fn into_trace(self) -> Self::Output {
756        self.map(|v| v.into_trace())
757    }
758}