use alloc::{string::String, vec::Vec}; use core::{convert::Infallible, ops::Range}; #[cfg(feature = "trace")] use {alloc::borrow::Cow, std::io::Write as _}; use crate::{command::Command, id}; //TODO: consider a readable Id that doesn't include the backend type FileName = String; pub const FILE_NAME: &str = "trace.ron"; #[cfg(feature = "trace")] pub(crate) fn new_render_bundle_encoder_descriptor<'a>( label: crate::Label<'a>, context: &'a super::RenderPassContext, depth_read_only: bool, stencil_read_only: bool, ) -> crate::command::RenderBundleEncoderDescriptor<'a> { crate::command::RenderBundleEncoderDescriptor { label, color_formats: Cow::Borrowed(&context.attachments.colors), depth_stencil: context.attachments.depth_stencil.map(|format| { wgt::RenderBundleDepthStencil { format, depth_read_only, stencil_read_only, } }), sample_count: context.sample_count, multiview: context.multiview, } } #[allow(clippy::large_enum_variant)] #[derive(Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Action<'a> { Init { desc: crate::device::DeviceDescriptor<'a>, backend: wgt::Backend, }, ConfigureSurface( id::SurfaceId, wgt::SurfaceConfiguration>, ), CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>), FreeBuffer(id::BufferId), DestroyBuffer(id::BufferId), CreateTexture(id::TextureId, crate::resource::TextureDescriptor<'a>), FreeTexture(id::TextureId), DestroyTexture(id::TextureId), CreateTextureView { id: id::TextureViewId, parent_id: id::TextureId, desc: crate::resource::TextureViewDescriptor<'a>, }, DestroyTextureView(id::TextureViewId), CreateExternalTexture { id: id::ExternalTextureId, desc: crate::resource::ExternalTextureDescriptor<'a>, planes: alloc::boxed::Box<[id::TextureViewId]>, }, FreeExternalTexture(id::ExternalTextureId), DestroyExternalTexture(id::ExternalTextureId), CreateSampler(id::SamplerId, crate::resource::SamplerDescriptor<'a>), DestroySampler(id::SamplerId), GetSurfaceTexture { id: id::TextureId, parent_id: id::SurfaceId, }, Present(id::SurfaceId), DiscardSurfaceTexture(id::SurfaceId), CreateBindGroupLayout( id::BindGroupLayoutId, crate::binding_model::BindGroupLayoutDescriptor<'a>, ), DestroyBindGroupLayout(id::BindGroupLayoutId), CreatePipelineLayout( id::PipelineLayoutId, crate::binding_model::PipelineLayoutDescriptor<'a>, ), DestroyPipelineLayout(id::PipelineLayoutId), CreateBindGroup( id::BindGroupId, crate::binding_model::BindGroupDescriptor<'a>, ), DestroyBindGroup(id::BindGroupId), CreateShaderModule { id: id::ShaderModuleId, desc: crate::pipeline::ShaderModuleDescriptor<'a>, data: FileName, }, CreateShaderModulePassthrough { id: id::ShaderModuleId, data: Vec, entry_point: String, label: crate::Label<'a>, num_workgroups: (u32, u32, u32), runtime_checks: wgt::ShaderRuntimeChecks, }, DestroyShaderModule(id::ShaderModuleId), CreateComputePipeline { id: id::ComputePipelineId, desc: crate::pipeline::ComputePipelineDescriptor<'a>, }, DestroyComputePipeline(id::ComputePipelineId), CreateRenderPipeline { id: id::RenderPipelineId, desc: crate::pipeline::RenderPipelineDescriptor<'a>, }, CreateMeshPipeline { id: id::RenderPipelineId, desc: crate::pipeline::MeshPipelineDescriptor<'a>, }, DestroyRenderPipeline(id::RenderPipelineId), CreatePipelineCache { id: id::PipelineCacheId, desc: crate::pipeline::PipelineCacheDescriptor<'a>, }, DestroyPipelineCache(id::PipelineCacheId), CreateRenderBundle { id: id::RenderBundleId, desc: crate::command::RenderBundleEncoderDescriptor<'a>, base: crate::command::BasePass, }, DestroyRenderBundle(id::RenderBundleId), CreateQuerySet { id: id::QuerySetId, desc: crate::resource::QuerySetDescriptor<'a>, }, DestroyQuerySet(id::QuerySetId), WriteBuffer { id: id::BufferId, data: FileName, range: Range, queued: bool, }, WriteTexture { to: wgt::TexelCopyTextureInfo, data: FileName, layout: wgt::TexelCopyBufferLayout, size: wgt::Extent3d, }, Submit(crate::SubmissionIndex, Vec), CreateBlas { id: id::BlasId, desc: crate::resource::BlasDescriptor<'a>, sizes: wgt::BlasGeometrySizeDescriptors, }, DestroyBlas(id::BlasId), CreateTlas { id: id::TlasId, desc: crate::resource::TlasDescriptor<'a>, }, DestroyTlas(id::TlasId), } #[cfg(feature = "trace")] #[derive(Debug)] pub struct Trace { path: std::path::PathBuf, file: std::fs::File, config: ron::ser::PrettyConfig, binary_id: usize, } #[cfg(feature = "trace")] impl Trace { pub fn new(path: std::path::PathBuf) -> Result { log::info!("Tracing into '{path:?}'"); let mut file = std::fs::File::create(path.join(FILE_NAME))?; file.write_all(b"[\n")?; Ok(Self { path, file, config: ron::ser::PrettyConfig::default(), binary_id: 0, }) } pub fn make_binary(&mut self, kind: &str, data: &[u8]) -> String { self.binary_id += 1; let name = std::format!("data{}.{}", self.binary_id, kind); let _ = std::fs::write(self.path.join(&name), data); name } pub(crate) fn add(&mut self, action: Action) { match ron::ser::to_string_pretty(&action, self.config.clone()) { Ok(string) => { let _ = writeln!(self.file, "{string},"); } Err(e) => { log::warn!("RON serialization failure: {e:?}"); } } } } #[cfg(feature = "trace")] impl Drop for Trace { fn drop(&mut self) { let _ = self.file.write_all(b"]"); } }