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 DestroyShaderModule(id::ShaderModuleId),
97 CreateComputePipeline {
98 id: id::ComputePipelineId,
99 desc: crate::pipeline::ComputePipelineDescriptor<'a>,
100 },
101 DestroyComputePipeline(id::ComputePipelineId),
102 CreateRenderPipeline {
103 id: id::RenderPipelineId,
104 desc: crate::pipeline::RenderPipelineDescriptor<'a>,
105 },
106 CreateMeshPipeline {
107 id: id::RenderPipelineId,
108 desc: crate::pipeline::MeshPipelineDescriptor<'a>,
109 },
110 DestroyRenderPipeline(id::RenderPipelineId),
111 CreatePipelineCache {
112 id: id::PipelineCacheId,
113 desc: crate::pipeline::PipelineCacheDescriptor<'a>,
114 },
115 DestroyPipelineCache(id::PipelineCacheId),
116 CreateRenderBundle {
117 id: id::RenderBundleId,
118 desc: crate::command::RenderBundleEncoderDescriptor<'a>,
119 base: crate::command::BasePass<crate::command::RenderCommand, Infallible>,
120 },
121 DestroyRenderBundle(id::RenderBundleId),
122 CreateQuerySet {
123 id: id::QuerySetId,
124 desc: crate::resource::QuerySetDescriptor<'a>,
125 },
126 DestroyQuerySet(id::QuerySetId),
127 WriteBuffer {
128 id: id::BufferId,
129 data: FileName,
130 range: Range<wgt::BufferAddress>,
131 queued: bool,
132 },
133 WriteTexture {
134 to: crate::command::TexelCopyTextureInfo,
135 data: FileName,
136 layout: wgt::TexelCopyBufferLayout,
137 size: wgt::Extent3d,
138 },
139 Submit(crate::SubmissionIndex, Vec<Command>),
140 CreateBlas {
141 id: id::BlasId,
142 desc: crate::resource::BlasDescriptor<'a>,
143 sizes: wgt::BlasGeometrySizeDescriptors,
144 },
145 DestroyBlas(id::BlasId),
146 CreateTlas {
147 id: id::TlasId,
148 desc: crate::resource::TlasDescriptor<'a>,
149 },
150 DestroyTlas(id::TlasId),
151}
152
153#[derive(Debug)]
154#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
155pub enum Command {
156 CopyBufferToBuffer {
157 src: id::BufferId,
158 src_offset: wgt::BufferAddress,
159 dst: id::BufferId,
160 dst_offset: wgt::BufferAddress,
161 size: Option<wgt::BufferAddress>,
162 },
163 CopyBufferToTexture {
164 src: crate::command::TexelCopyBufferInfo,
165 dst: crate::command::TexelCopyTextureInfo,
166 size: wgt::Extent3d,
167 },
168 CopyTextureToBuffer {
169 src: crate::command::TexelCopyTextureInfo,
170 dst: crate::command::TexelCopyBufferInfo,
171 size: wgt::Extent3d,
172 },
173 CopyTextureToTexture {
174 src: crate::command::TexelCopyTextureInfo,
175 dst: crate::command::TexelCopyTextureInfo,
176 size: wgt::Extent3d,
177 },
178 ClearBuffer {
179 dst: id::BufferId,
180 offset: wgt::BufferAddress,
181 size: Option<wgt::BufferAddress>,
182 },
183 ClearTexture {
184 dst: id::TextureId,
185 subresource_range: wgt::ImageSubresourceRange,
186 },
187 WriteTimestamp {
188 query_set_id: id::QuerySetId,
189 query_index: u32,
190 },
191 ResolveQuerySet {
192 query_set_id: id::QuerySetId,
193 start_query: u32,
194 query_count: u32,
195 destination: id::BufferId,
196 destination_offset: wgt::BufferAddress,
197 },
198 PushDebugGroup(String),
199 PopDebugGroup,
200 InsertDebugMarker(String),
201 RunComputePass {
202 base: crate::command::BasePass<crate::command::ComputeCommand, Infallible>,
203 timestamp_writes: Option<crate::command::PassTimestampWrites>,
204 },
205 RunRenderPass {
206 base: crate::command::BasePass<crate::command::RenderCommand, Infallible>,
207 target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
208 target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
209 timestamp_writes: Option<crate::command::PassTimestampWrites>,
210 occlusion_query_set_id: Option<id::QuerySetId>,
211 },
212 BuildAccelerationStructures {
213 blas: Vec<crate::ray_tracing::TraceBlasBuildEntry>,
214 tlas: Vec<crate::ray_tracing::TraceTlasPackage>,
215 },
216}
217
218#[cfg(feature = "trace")]
219#[derive(Debug)]
220pub struct Trace {
221 path: std::path::PathBuf,
222 file: std::fs::File,
223 config: ron::ser::PrettyConfig,
224 binary_id: usize,
225}
226
227#[cfg(feature = "trace")]
228impl Trace {
229 pub fn new(path: std::path::PathBuf) -> Result<Self, std::io::Error> {
230 log::info!("Tracing into '{path:?}'");
231 let mut file = std::fs::File::create(path.join(FILE_NAME))?;
232 file.write_all(b"[\n")?;
233 Ok(Self {
234 path,
235 file,
236 config: ron::ser::PrettyConfig::default(),
237 binary_id: 0,
238 })
239 }
240
241 pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String {
242 self.binary_id += 1;
243 let name = std::format!("data{}.{}", self.binary_id, kind);
244 let _ = std::fs::write(self.path.join(&name), data);
245 name
246 }
247
248 pub(crate) fn add(&mut self, action: Action) {
249 match ron::ser::to_string_pretty(&action, self.config.clone()) {
250 Ok(string) => {
251 let _ = writeln!(self.file, "{string},");
252 }
253 Err(e) => {
254 log::warn!("RON serialization failure: {e:?}");
255 }
256 }
257 }
258}
259
260#[cfg(feature = "trace")]
261impl Drop for Trace {
262 fn drop(&mut self) {
263 let _ = self.file.write_all(b"]");
264 }
265}