li_wgpu_core/device/
trace.rs

1use crate::id;
2use std::ops::Range;
3#[cfg(feature = "trace")]
4use std::{borrow::Cow, io::Write as _};
5
6//TODO: consider a readable Id that doesn't include the backend
7
8type FileName = String;
9
10pub const FILE_NAME: &str = "trace.ron";
11
12#[cfg(feature = "trace")]
13pub(crate) fn new_render_bundle_encoder_descriptor<'a>(
14    label: crate::Label<'a>,
15    context: &'a super::RenderPassContext,
16    depth_read_only: bool,
17    stencil_read_only: bool,
18) -> crate::command::RenderBundleEncoderDescriptor<'a> {
19    crate::command::RenderBundleEncoderDescriptor {
20        label,
21        color_formats: Cow::Borrowed(&context.attachments.colors),
22        depth_stencil: context.attachments.depth_stencil.map(|format| {
23            wgt::RenderBundleDepthStencil {
24                format,
25                depth_read_only,
26                stencil_read_only,
27            }
28        }),
29        sample_count: context.sample_count,
30        multiview: context.multiview,
31    }
32}
33
34#[allow(clippy::large_enum_variant)]
35#[derive(Debug)]
36#[cfg_attr(feature = "trace", derive(serde::Serialize))]
37#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
38pub enum Action<'a> {
39    Init {
40        desc: crate::device::DeviceDescriptor<'a>,
41        backend: wgt::Backend,
42    },
43    ConfigureSurface(
44        id::SurfaceId,
45        wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
46    ),
47    CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>),
48    FreeBuffer(id::BufferId),
49    DestroyBuffer(id::BufferId),
50    CreateTexture(id::TextureId, crate::resource::TextureDescriptor<'a>),
51    FreeTexture(id::TextureId),
52    DestroyTexture(id::TextureId),
53    CreateTextureView {
54        id: id::TextureViewId,
55        parent_id: id::TextureId,
56        desc: crate::resource::TextureViewDescriptor<'a>,
57    },
58    DestroyTextureView(id::TextureViewId),
59    CreateSampler(id::SamplerId, crate::resource::SamplerDescriptor<'a>),
60    DestroySampler(id::SamplerId),
61    GetSurfaceTexture {
62        id: id::TextureId,
63        parent_id: id::SurfaceId,
64    },
65    Present(id::SurfaceId),
66    DiscardSurfaceTexture(id::SurfaceId),
67    CreateBindGroupLayout(
68        id::BindGroupLayoutId,
69        crate::binding_model::BindGroupLayoutDescriptor<'a>,
70    ),
71    DestroyBindGroupLayout(id::BindGroupLayoutId),
72    CreatePipelineLayout(
73        id::PipelineLayoutId,
74        crate::binding_model::PipelineLayoutDescriptor<'a>,
75    ),
76    DestroyPipelineLayout(id::PipelineLayoutId),
77    CreateBindGroup(
78        id::BindGroupId,
79        crate::binding_model::BindGroupDescriptor<'a>,
80    ),
81    DestroyBindGroup(id::BindGroupId),
82    CreateShaderModule {
83        id: id::ShaderModuleId,
84        desc: crate::pipeline::ShaderModuleDescriptor<'a>,
85        data: FileName,
86    },
87    DestroyShaderModule(id::ShaderModuleId),
88    CreateComputePipeline {
89        id: id::ComputePipelineId,
90        desc: crate::pipeline::ComputePipelineDescriptor<'a>,
91        #[cfg_attr(feature = "replay", serde(default))]
92        implicit_context: Option<super::ImplicitPipelineContext>,
93    },
94    DestroyComputePipeline(id::ComputePipelineId),
95    CreateRenderPipeline {
96        id: id::RenderPipelineId,
97        desc: crate::pipeline::RenderPipelineDescriptor<'a>,
98        #[cfg_attr(feature = "replay", serde(default))]
99        implicit_context: Option<super::ImplicitPipelineContext>,
100    },
101    DestroyRenderPipeline(id::RenderPipelineId),
102    CreateRenderBundle {
103        id: id::RenderBundleId,
104        desc: crate::command::RenderBundleEncoderDescriptor<'a>,
105        base: crate::command::BasePass<crate::command::RenderCommand>,
106    },
107    DestroyRenderBundle(id::RenderBundleId),
108    CreateQuerySet {
109        id: id::QuerySetId,
110        desc: crate::resource::QuerySetDescriptor<'a>,
111    },
112    DestroyQuerySet(id::QuerySetId),
113    WriteBuffer {
114        id: id::BufferId,
115        data: FileName,
116        range: Range<wgt::BufferAddress>,
117        queued: bool,
118    },
119    WriteTexture {
120        to: crate::command::ImageCopyTexture,
121        data: FileName,
122        layout: wgt::ImageDataLayout,
123        size: wgt::Extent3d,
124    },
125    Submit(crate::SubmissionIndex, Vec<Command>),
126}
127
128#[derive(Debug)]
129#[cfg_attr(feature = "trace", derive(serde::Serialize))]
130#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
131pub enum Command {
132    CopyBufferToBuffer {
133        src: id::BufferId,
134        src_offset: wgt::BufferAddress,
135        dst: id::BufferId,
136        dst_offset: wgt::BufferAddress,
137        size: wgt::BufferAddress,
138    },
139    CopyBufferToTexture {
140        src: crate::command::ImageCopyBuffer,
141        dst: crate::command::ImageCopyTexture,
142        size: wgt::Extent3d,
143    },
144    CopyTextureToBuffer {
145        src: crate::command::ImageCopyTexture,
146        dst: crate::command::ImageCopyBuffer,
147        size: wgt::Extent3d,
148    },
149    CopyTextureToTexture {
150        src: crate::command::ImageCopyTexture,
151        dst: crate::command::ImageCopyTexture,
152        size: wgt::Extent3d,
153    },
154    ClearBuffer {
155        dst: id::BufferId,
156        offset: wgt::BufferAddress,
157        size: Option<wgt::BufferSize>,
158    },
159    ClearTexture {
160        dst: id::TextureId,
161        subresource_range: wgt::ImageSubresourceRange,
162    },
163    WriteTimestamp {
164        query_set_id: id::QuerySetId,
165        query_index: u32,
166    },
167    ResolveQuerySet {
168        query_set_id: id::QuerySetId,
169        start_query: u32,
170        query_count: u32,
171        destination: id::BufferId,
172        destination_offset: wgt::BufferAddress,
173    },
174    PushDebugGroup(String),
175    PopDebugGroup,
176    InsertDebugMarker(String),
177    RunComputePass {
178        base: crate::command::BasePass<crate::command::ComputeCommand>,
179        timestamp_writes: Option<crate::command::ComputePassTimestampWrites>,
180    },
181    RunRenderPass {
182        base: crate::command::BasePass<crate::command::RenderCommand>,
183        target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
184        target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
185        timestamp_writes: Option<crate::command::RenderPassTimestampWrites>,
186        occlusion_query_set_id: Option<id::QuerySetId>,
187    },
188}
189
190#[cfg(feature = "trace")]
191#[derive(Debug)]
192pub struct Trace {
193    path: std::path::PathBuf,
194    file: std::fs::File,
195    config: ron::ser::PrettyConfig,
196    binary_id: usize,
197}
198
199#[cfg(feature = "trace")]
200impl Trace {
201    pub fn new(path: &std::path::Path) -> Result<Self, std::io::Error> {
202        log::info!("Tracing into '{:?}'", path);
203        let mut file = std::fs::File::create(path.join(FILE_NAME))?;
204        file.write_all(b"[\n")?;
205        Ok(Self {
206            path: path.to_path_buf(),
207            file,
208            config: ron::ser::PrettyConfig::default(),
209            binary_id: 0,
210        })
211    }
212
213    pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String {
214        self.binary_id += 1;
215        let name = format!("data{}.{}", self.binary_id, kind);
216        let _ = std::fs::write(self.path.join(&name), data);
217        name
218    }
219
220    pub(crate) fn add(&mut self, action: Action) {
221        match ron::ser::to_string_pretty(&action, self.config.clone()) {
222            Ok(string) => {
223                let _ = writeln!(self.file, "{},", string);
224            }
225            Err(e) => {
226                log::warn!("RON serialization failure: {:?}", e);
227            }
228        }
229    }
230}
231
232#[cfg(feature = "trace")]
233impl Drop for Trace {
234    fn drop(&mut self) {
235        let _ = self.file.write_all(b"]");
236    }
237}