1use alloc::{string::String, vec::Vec};
2use core::{convert::Infallible, ops::Range};
3
4#[cfg(feature = "trace")]
5use {alloc::borrow::Cow, std::io::Write as _};
6
7use crate::{command::Command, id};
8
9type FileName = String;
12
13pub const FILE_NAME: &str = "trace.ron";
14
15#[cfg(feature = "trace")]
16pub(crate) fn new_render_bundle_encoder_descriptor<'a>(
17 label: crate::Label<'a>,
18 context: &'a super::RenderPassContext,
19 depth_read_only: bool,
20 stencil_read_only: bool,
21) -> crate::command::RenderBundleEncoderDescriptor<'a> {
22 crate::command::RenderBundleEncoderDescriptor {
23 label,
24 color_formats: Cow::Borrowed(&context.attachments.colors),
25 depth_stencil: context.attachments.depth_stencil.map(|format| {
26 wgt::RenderBundleDepthStencil {
27 format,
28 depth_read_only,
29 stencil_read_only,
30 }
31 }),
32 sample_count: context.sample_count,
33 multiview: context.multiview,
34 }
35}
36
37#[allow(clippy::large_enum_variant)]
38#[derive(Debug)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40pub enum Action<'a> {
41 Init {
42 desc: crate::device::DeviceDescriptor<'a>,
43 backend: wgt::Backend,
44 },
45 ConfigureSurface(
46 id::SurfaceId,
47 wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
48 ),
49 CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>),
50 FreeBuffer(id::BufferId),
51 DestroyBuffer(id::BufferId),
52 CreateTexture(id::TextureId, crate::resource::TextureDescriptor<'a>),
53 FreeTexture(id::TextureId),
54 DestroyTexture(id::TextureId),
55 CreateTextureView {
56 id: id::TextureViewId,
57 parent_id: id::TextureId,
58 desc: crate::resource::TextureViewDescriptor<'a>,
59 },
60 DestroyTextureView(id::TextureViewId),
61 CreateExternalTexture {
62 id: id::ExternalTextureId,
63 desc: crate::resource::ExternalTextureDescriptor<'a>,
64 planes: alloc::boxed::Box<[id::TextureViewId]>,
65 },
66 FreeExternalTexture(id::ExternalTextureId),
67 DestroyExternalTexture(id::ExternalTextureId),
68 CreateSampler(id::SamplerId, crate::resource::SamplerDescriptor<'a>),
69 DestroySampler(id::SamplerId),
70 GetSurfaceTexture {
71 id: id::TextureId,
72 parent_id: id::SurfaceId,
73 },
74 Present(id::SurfaceId),
75 DiscardSurfaceTexture(id::SurfaceId),
76 CreateBindGroupLayout(
77 id::BindGroupLayoutId,
78 crate::binding_model::BindGroupLayoutDescriptor<'a>,
79 ),
80 DestroyBindGroupLayout(id::BindGroupLayoutId),
81 CreatePipelineLayout(
82 id::PipelineLayoutId,
83 crate::binding_model::PipelineLayoutDescriptor<'a>,
84 ),
85 DestroyPipelineLayout(id::PipelineLayoutId),
86 CreateBindGroup(
87 id::BindGroupId,
88 crate::binding_model::BindGroupDescriptor<'a>,
89 ),
90 DestroyBindGroup(id::BindGroupId),
91 CreateShaderModule {
92 id: id::ShaderModuleId,
93 desc: crate::pipeline::ShaderModuleDescriptor<'a>,
94 data: FileName,
95 },
96 CreateShaderModulePassthrough {
97 id: id::ShaderModuleId,
98 data: Vec<FileName>,
99
100 entry_point: String,
101 label: crate::Label<'a>,
102 num_workgroups: (u32, u32, u32),
103 runtime_checks: wgt::ShaderRuntimeChecks,
104 },
105 DestroyShaderModule(id::ShaderModuleId),
106 CreateComputePipeline {
107 id: id::ComputePipelineId,
108 desc: crate::pipeline::ComputePipelineDescriptor<'a>,
109 },
110 DestroyComputePipeline(id::ComputePipelineId),
111 CreateRenderPipeline {
112 id: id::RenderPipelineId,
113 desc: crate::pipeline::RenderPipelineDescriptor<'a>,
114 },
115 CreateMeshPipeline {
116 id: id::RenderPipelineId,
117 desc: crate::pipeline::MeshPipelineDescriptor<'a>,
118 },
119 DestroyRenderPipeline(id::RenderPipelineId),
120 CreatePipelineCache {
121 id: id::PipelineCacheId,
122 desc: crate::pipeline::PipelineCacheDescriptor<'a>,
123 },
124 DestroyPipelineCache(id::PipelineCacheId),
125 CreateRenderBundle {
126 id: id::RenderBundleId,
127 desc: crate::command::RenderBundleEncoderDescriptor<'a>,
128 base: crate::command::BasePass<crate::command::RenderCommand, Infallible>,
129 },
130 DestroyRenderBundle(id::RenderBundleId),
131 CreateQuerySet {
132 id: id::QuerySetId,
133 desc: crate::resource::QuerySetDescriptor<'a>,
134 },
135 DestroyQuerySet(id::QuerySetId),
136 WriteBuffer {
137 id: id::BufferId,
138 data: FileName,
139 range: Range<wgt::BufferAddress>,
140 queued: bool,
141 },
142 WriteTexture {
143 to: wgt::TexelCopyTextureInfo<id::TextureId>,
144 data: FileName,
145 layout: wgt::TexelCopyBufferLayout,
146 size: wgt::Extent3d,
147 },
148 Submit(crate::SubmissionIndex, Vec<Command>),
149 CreateBlas {
150 id: id::BlasId,
151 desc: crate::resource::BlasDescriptor<'a>,
152 sizes: wgt::BlasGeometrySizeDescriptors,
153 },
154 DestroyBlas(id::BlasId),
155 CreateTlas {
156 id: id::TlasId,
157 desc: crate::resource::TlasDescriptor<'a>,
158 },
159 DestroyTlas(id::TlasId),
160}
161
162#[cfg(feature = "trace")]
163#[derive(Debug)]
164pub struct Trace {
165 path: std::path::PathBuf,
166 file: std::fs::File,
167 config: ron::ser::PrettyConfig,
168 binary_id: usize,
169}
170
171#[cfg(feature = "trace")]
172impl Trace {
173 pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> {
174 log::info!("Tracing into '{path:?}'");
175 let mut file = std::fs::File::create(path.join(FILE_NAME))?;
176 file.write_all(b"[\n")?;
177 Ok(Self {
178 path,
179 file,
180 config: ron::ser::PrettyConfig::default(),
181 binary_id: 0,
182 })
183 }
184
185 pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String {
186 self.binary_id += 1;
187 let name = std::format!("data{}.{}", self.binary_id, kind);
188 let _ = std::fs::write(self.path.join(&name), data);
189 name
190 }
191
192 pub(crate) fn add(&mut self, action: Action) {
193 match ron::ser::to_string_pretty(&action, self.config.clone()) {
194 Ok(string) => {
195 let _ = writeln!(self.file, "{string},");
196 }
197 Err(e) => {
198 log::warn!("RON serialization failure: {e:?}");
199 }
200 }
201 }
202}
203
204#[cfg(feature = "trace")]
205impl Drop for Trace {
206 fn drop(&mut self) {
207 let _ = self.file.write_all(b"]");
208 }
209}