1#[cfg(feature = "trace")]
2mod record;
3#[cfg(feature = "replay")]
4mod replay;
5
6use core::convert::Infallible;
7
8use alloc::{borrow::Cow, string::String, vec::Vec};
9use macro_rules_attribute::apply;
10
11use crate::{
12 binding_model::BindGroupLayoutEntry,
13 command::{serde_object_reference_struct, BasePass, Command, ReferenceType, RenderCommand},
14 id::{markers, PointerId},
15 pipeline::GeneralRenderPipelineDescriptor,
16};
17
18#[cfg(feature = "trace")]
19pub use record::*;
20#[cfg(feature = "replay")]
21pub use replay::*;
22
23type FileName = String;
24
25pub const FILE_NAME: &str = "trace.ron";
26
27#[derive(Debug)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub enum Data {
30 File(FileName),
31 String(DataKind, String),
32 Binary(DataKind, Vec<u8>),
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36#[cfg_attr(
37 feature = "serde",
38 derive(serde::Serialize, serde::Deserialize),
39 serde(rename_all = "lowercase")
40)]
41pub enum DataKind {
42 Bin,
43 Wgsl,
44
45 Ron,
47 Spv,
48 Dxil,
49 Hlsl,
50 MetalLib,
51 Msl,
52 Glsl,
53}
54
55impl core::fmt::Display for DataKind {
56 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57 let s = match self {
58 DataKind::Bin => "bin",
59 DataKind::Wgsl => "wgsl",
60 DataKind::Ron => "ron",
61 DataKind::Spv => "spv",
62 DataKind::Dxil => "dxil",
63 DataKind::Hlsl => "hlsl",
64 DataKind::MetalLib => "metallib",
65 DataKind::Msl => "metal",
66 DataKind::Glsl => "glsl",
67 };
68 write!(f, "{s}")
69 }
70}
71
72impl DataKind {
73 #[cfg(feature = "replay")]
74 fn is_string(&self) -> bool {
75 match *self {
76 DataKind::Wgsl | DataKind::Ron | DataKind::Hlsl | DataKind::Msl | DataKind::Glsl => {
77 true
78 }
79 DataKind::Bin | DataKind::Spv | DataKind::Dxil | DataKind::MetalLib => false,
80 }
81 }
82}
83
84impl Data {
85 pub fn kind(&self) -> DataKind {
86 match self {
87 Data::File(file) => {
88 if file.ends_with(".bin") {
89 DataKind::Bin
90 } else if file.ends_with(".wgsl") {
91 DataKind::Wgsl
92 } else if file.ends_with(".ron") {
93 DataKind::Ron
94 } else if file.ends_with(".spv") {
95 DataKind::Spv
96 } else if file.ends_with(".dxil") {
97 DataKind::Dxil
98 } else if file.ends_with(".hlsl") {
99 DataKind::Hlsl
100 } else if file.ends_with(".metallib") {
101 DataKind::MetalLib
102 } else if file.ends_with(".metal") {
103 DataKind::Msl
104 } else if file.ends_with(".glsl") {
105 DataKind::Glsl
106 } else {
107 panic!("unknown data file extension: {file}");
108 }
109 }
110 Data::String(kind, _) => *kind,
111 Data::Binary(kind, _) => *kind,
112 }
113 }
114}
115
116#[allow(clippy::large_enum_variant)]
117#[derive(Debug)]
118#[apply(serde_object_reference_struct)]
119pub enum Action<'a, R: ReferenceType> {
120 Init {
121 desc: crate::device::DeviceDescriptor<'a>,
122 backend: wgt::Backend,
123 },
124 ConfigureSurface(
125 R::Surface,
126 wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
127 ),
128 CreateBuffer(R::Buffer, crate::resource::BufferDescriptor<'a>),
129 DestroyBuffer(R::Buffer),
130 DropBuffer(R::Buffer),
131 CreateTexture(R::Texture, crate::resource::TextureDescriptor<'a>),
132 CreateTextureError(R::Texture, crate::resource::TextureDescriptor<'a>),
133 DestroyTexture(R::Texture),
134 DropTexture(R::Texture),
135 CreateTextureView {
136 id: R::TextureView,
137 parent: R::Texture,
138 desc: crate::resource::TextureViewDescriptor<'a>,
139 },
140 DropTextureView(R::TextureView),
141 CreateExternalTexture {
142 id: R::ExternalTexture,
143 desc: crate::resource::ExternalTextureDescriptor<'a>,
144 planes: alloc::boxed::Box<[R::TextureView]>,
145 },
146 DestroyExternalTexture(R::ExternalTexture),
147 DropExternalTexture(R::ExternalTexture),
148 CreateSampler(
149 PointerId<markers::Sampler>,
150 crate::resource::SamplerDescriptor<'a>,
151 ),
152 DropSampler(PointerId<markers::Sampler>),
153 GetSurfaceTexture {
154 id: R::Texture,
155 parent: R::Surface,
156 },
157 Present(R::Surface),
158 DiscardSurfaceTexture(R::Surface),
159 ReleaseSurfaceTexture(R::Surface),
160 CreateBindGroupLayout(
161 PointerId<markers::BindGroupLayout>,
162 crate::binding_model::BindGroupLayoutDescriptor<'a, BindGroupLayoutEntry>,
163 ),
164 GetRenderPipelineBindGroupLayout {
165 id: PointerId<markers::BindGroupLayout>,
166 pipeline: PointerId<markers::RenderPipeline>,
167 index: u32,
168 },
169 GetComputePipelineBindGroupLayout {
170 id: PointerId<markers::BindGroupLayout>,
171 pipeline: PointerId<markers::ComputePipeline>,
172 index: u32,
173 },
174 DropBindGroupLayout(PointerId<markers::BindGroupLayout>),
175 CreatePipelineLayout(
176 PointerId<markers::PipelineLayout>,
177 crate::binding_model::PipelineLayoutDescriptor<'a, PointerId<markers::BindGroupLayout>>,
178 ),
179 DropPipelineLayout(PointerId<markers::PipelineLayout>),
180 CreateBindGroup(PointerId<markers::BindGroup>, TraceBindGroupDescriptor<'a>),
181 DropBindGroup(PointerId<markers::BindGroup>),
182 CreateShaderModule {
183 id: PointerId<markers::ShaderModule>,
184 desc: crate::pipeline::ShaderModuleDescriptor<'a>,
185 data: Data,
186 },
187 CreateShaderModulePassthrough {
188 id: PointerId<markers::ShaderModule>,
189 data: Vec<Data>,
190
191 label: crate::Label<'a>,
192 entry_points: Cow<'a, [wgt::PassthroughShaderEntryPoint<'a>]>,
193 },
194 DropShaderModule(PointerId<markers::ShaderModule>),
195 CreateComputePipeline {
196 id: PointerId<markers::ComputePipeline>,
197 desc: TraceComputePipelineDescriptor<'a>,
198 },
199 DropComputePipeline(PointerId<markers::ComputePipeline>),
200 CreateGeneralRenderPipeline {
201 id: PointerId<markers::RenderPipeline>,
202 desc: TraceGeneralRenderPipelineDescriptor<'a>,
203 },
204 DropRenderPipeline(PointerId<markers::RenderPipeline>),
205 CreatePipelineCache {
206 id: PointerId<markers::PipelineCache>,
207 desc: crate::pipeline::PipelineCacheDescriptor<'a>,
208 },
209 DropPipelineCache(PointerId<markers::PipelineCache>),
210 CreateRenderBundle {
211 id: R::RenderBundle,
212 desc: crate::command::RenderBundleEncoderDescriptor<'a>,
213 base: BasePass<RenderCommand<R>, Infallible>,
214 },
215 DropRenderBundle(PointerId<markers::RenderBundle>),
216 CreateQuerySet {
217 id: PointerId<markers::QuerySet>,
218 desc: crate::resource::QuerySetDescriptor<'a>,
219 },
220 DropQuerySet(PointerId<markers::QuerySet>),
221 DestroyQuerySet(PointerId<markers::QuerySet>),
222 WriteBuffer {
223 id: R::Buffer,
224 data: Data,
225 offset: wgt::BufferAddress,
226 size: wgt::BufferAddress,
227 queued: bool,
228 },
229 WriteTexture {
230 to: wgt::TexelCopyTextureInfo<R::Texture>,
231 data: Data,
232 layout: wgt::TexelCopyBufferLayout,
233 size: wgt::Extent3d,
234 },
235 Submit(crate::SubmissionIndex, Vec<Command<R>>),
236 FailedCommands {
237 commands: Option<Vec<Command<R>>>,
238 failed_at_submit: Option<crate::SubmissionIndex>,
242 error: String,
243 },
244 CreateBlas {
245 id: R::Blas,
246 desc: crate::resource::BlasDescriptor<'a>,
247 sizes: wgt::BlasGeometrySizeDescriptors,
248 },
249 DropBlas(R::Blas),
250 CreateTlas {
251 id: R::Tlas,
252 desc: crate::resource::TlasDescriptor<'a>,
253 },
254 DropTlas(R::Tlas),
255}
256
257pub type TraceBindGroupDescriptor<'a> = crate::binding_model::BindGroupDescriptor<
259 'a,
260 PointerId<markers::BindGroupLayout>,
261 PointerId<markers::Buffer>,
262 PointerId<markers::Sampler>,
263 PointerId<markers::TextureView>,
264 PointerId<markers::Tlas>,
265 PointerId<markers::ExternalTexture>,
266>;
267
268#[doc(hidden)]
272pub type TraceGeneralRenderPipelineDescriptor<'a> = GeneralRenderPipelineDescriptor<
273 'a,
274 PointerId<markers::PipelineLayout>,
275 PointerId<markers::ShaderModule>,
276 PointerId<markers::PipelineCache>,
277>;
278
279#[doc(hidden)]
283pub type TraceComputePipelineDescriptor<'a> = crate::pipeline::ComputePipelineDescriptor<
284 'a,
285 PointerId<markers::PipelineLayout>,
286 PointerId<markers::ShaderModule>,
287 PointerId<markers::PipelineCache>,
288>;