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 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}