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::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: crate::command::TexelCopyTextureInfo,
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#[derive(Debug)]
163#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
164pub enum Command {
165 CopyBufferToBuffer {
166 src: id::BufferId,
167 src_offset: wgt::BufferAddress,
168 dst: id::BufferId,
169 dst_offset: wgt::BufferAddress,
170 size: Option<wgt::BufferAddress>,
171 },
172 CopyBufferToTexture {
173 src: crate::command::TexelCopyBufferInfo,
174 dst: crate::command::TexelCopyTextureInfo,
175 size: wgt::Extent3d,
176 },
177 CopyTextureToBuffer {
178 src: crate::command::TexelCopyTextureInfo,
179 dst: crate::command::TexelCopyBufferInfo,
180 size: wgt::Extent3d,
181 },
182 CopyTextureToTexture {
183 src: crate::command::TexelCopyTextureInfo,
184 dst: crate::command::TexelCopyTextureInfo,
185 size: wgt::Extent3d,
186 },
187 ClearBuffer {
188 dst: id::BufferId,
189 offset: wgt::BufferAddress,
190 size: Option<wgt::BufferAddress>,
191 },
192 ClearTexture {
193 dst: id::TextureId,
194 subresource_range: wgt::ImageSubresourceRange,
195 },
196 WriteTimestamp {
197 query_set_id: id::QuerySetId,
198 query_index: u32,
199 },
200 ResolveQuerySet {
201 query_set_id: id::QuerySetId,
202 start_query: u32,
203 query_count: u32,
204 destination: id::BufferId,
205 destination_offset: wgt::BufferAddress,
206 },
207 PushDebugGroup(String),
208 PopDebugGroup,
209 InsertDebugMarker(String),
210 RunComputePass {
211 base: crate::command::BasePass<crate::command::ComputeCommand, Infallible>,
212 timestamp_writes: Option<crate::command::PassTimestampWrites>,
213 },
214 RunRenderPass {
215 base: crate::command::BasePass<crate::command::RenderCommand, Infallible>,
216 target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
217 target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
218 timestamp_writes: Option<crate::command::PassTimestampWrites>,
219 occlusion_query_set_id: Option<id::QuerySetId>,
220 },
221 BuildAccelerationStructures {
222 blas: Vec<crate::ray_tracing::TraceBlasBuildEntry>,
223 tlas: Vec<crate::ray_tracing::TraceTlasPackage>,
224 },
225}
226
227#[cfg(feature = "trace")]
228#[derive(Debug)]
229pub struct Trace {
230 path: std::path::PathBuf,
231 file: std::fs::File,
232 config: ron::ser::PrettyConfig,
233 binary_id: usize,
234}
235
236#[cfg(feature = "trace")]
237impl Trace {
238 pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> {
239 log::info!("Tracing into '{path:?}'");
240 let mut file = std::fs::File::create(path.join(FILE_NAME))?;
241 file.write_all(b"[\n")?;
242 Ok(Self {
243 path,
244 file,
245 config: ron::ser::PrettyConfig::default(),
246 binary_id: 0,
247 })
248 }
249
250 pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String {
251 self.binary_id += 1;
252 let name = std::format!("data{}.{}", self.binary_id, kind);
253 let _ = std::fs::write(self.path.join(&name), data);
254 name
255 }
256
257 pub(crate) fn add(&mut self, action: Action) {
258 match ron::ser::to_string_pretty(&action, self.config.clone()) {
259 Ok(string) => {
260 let _ = writeln!(self.file, "{string},");
261 }
262 Err(e) => {
263 log::warn!("RON serialization failure: {e:?}");
264 }
265 }
266 }
267}
268
269#[cfg(feature = "trace")]
270impl Drop for Trace {
271 fn drop(&mut self) {
272 let _ = self.file.write_all(b"]");
273 }
274}