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