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