use crate::id;
#[cfg(feature = "trace")]
use std::io::Write as _;
use std::ops::Range;
type FileName = String;
pub const FILE_NAME: &str = "trace.ron";
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum BindingResource {
    Buffer {
        id: id::BufferId,
        offset: wgt::BufferAddress,
        size: wgt::BufferSize,
    },
    Sampler(id::SamplerId),
    TextureView(id::TextureViewId),
    TextureViewArray(Vec<id::TextureViewId>),
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ProgrammableStageDescriptor {
    pub module: id::ShaderModuleId,
    pub entry_point: String,
}
#[cfg(feature = "trace")]
impl ProgrammableStageDescriptor {
    pub fn new(desc: &crate::pipeline::ProgrammableStageDescriptor) -> Self {
        ProgrammableStageDescriptor {
            module: desc.module,
            entry_point: unsafe { std::ffi::CStr::from_ptr(desc.entry_point) }
                .to_string_lossy()
                .to_string(),
        }
    }
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ComputePipelineDescriptor {
    pub layout: id::PipelineLayoutId,
    pub compute_stage: ProgrammableStageDescriptor,
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexBufferLayoutDescriptor {
    pub array_stride: wgt::BufferAddress,
    pub step_mode: wgt::InputStepMode,
    pub attributes: Vec<wgt::VertexAttributeDescriptor>,
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexStateDescriptor {
    pub index_format: wgt::IndexFormat,
    pub vertex_buffers: Vec<VertexBufferLayoutDescriptor>,
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderPipelineDescriptor {
    pub layout: id::PipelineLayoutId,
    pub vertex_stage: ProgrammableStageDescriptor,
    pub fragment_stage: Option<ProgrammableStageDescriptor>,
    pub primitive_topology: wgt::PrimitiveTopology,
    pub rasterization_state: Option<wgt::RasterizationStateDescriptor>,
    pub color_states: Vec<wgt::ColorStateDescriptor>,
    pub depth_stencil_state: Option<wgt::DepthStencilStateDescriptor>,
    pub vertex_state: VertexStateDescriptor,
    pub sample_count: u32,
    pub sample_mask: u32,
    pub alpha_to_coverage_enabled: bool,
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderBundleDescriptor {
    pub label: String,
    pub color_formats: Vec<wgt::TextureFormat>,
    pub depth_stencil_format: Option<wgt::TextureFormat>,
    pub sample_count: u32,
}
#[cfg(feature = "trace")]
impl RenderBundleDescriptor {
    pub(crate) fn new(label: super::Label, context: &super::RenderPassContext) -> Self {
        RenderBundleDescriptor {
            label: super::own_label(&label),
            color_formats: context.attachments.colors.to_vec(),
            depth_stencil_format: context.attachments.depth_stencil,
            sample_count: context.sample_count as u32,
        }
    }
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum Action {
    Init {
        desc: wgt::DeviceDescriptor,
        backend: wgt::Backend,
    },
    CreateBuffer {
        id: id::BufferId,
        desc: wgt::BufferDescriptor<String>,
    },
    DestroyBuffer(id::BufferId),
    CreateTexture {
        id: id::TextureId,
        desc: wgt::TextureDescriptor<String>,
    },
    DestroyTexture(id::TextureId),
    CreateTextureView {
        id: id::TextureViewId,
        parent_id: id::TextureId,
        desc: Option<wgt::TextureViewDescriptor<String>>,
    },
    DestroyTextureView(id::TextureViewId),
    CreateSampler {
        id: id::SamplerId,
        desc: wgt::SamplerDescriptor<String>,
    },
    DestroySampler(id::SamplerId),
    CreateSwapChain {
        id: id::SwapChainId,
        desc: wgt::SwapChainDescriptor,
    },
    GetSwapChainTexture {
        id: Option<id::TextureViewId>,
        parent_id: id::SwapChainId,
    },
    PresentSwapChain(id::SwapChainId),
    CreateBindGroupLayout {
        id: id::BindGroupLayoutId,
        label: String,
        entries: Vec<wgt::BindGroupLayoutEntry>,
    },
    DestroyBindGroupLayout(id::BindGroupLayoutId),
    CreatePipelineLayout {
        id: id::PipelineLayoutId,
        bind_group_layouts: Vec<id::BindGroupLayoutId>,
    },
    DestroyPipelineLayout(id::PipelineLayoutId),
    CreateBindGroup {
        id: id::BindGroupId,
        label: String,
        layout_id: id::BindGroupLayoutId,
        entries: std::collections::BTreeMap<u32, BindingResource>,
    },
    DestroyBindGroup(id::BindGroupId),
    CreateShaderModule {
        id: id::ShaderModuleId,
        data: FileName,
    },
    DestroyShaderModule(id::ShaderModuleId),
    CreateComputePipeline {
        id: id::ComputePipelineId,
        desc: ComputePipelineDescriptor,
    },
    DestroyComputePipeline(id::ComputePipelineId),
    CreateRenderPipeline {
        id: id::RenderPipelineId,
        desc: RenderPipelineDescriptor,
    },
    DestroyRenderPipeline(id::RenderPipelineId),
    CreateRenderBundle {
        id: id::RenderBundleId,
        desc: RenderBundleDescriptor,
        commands: Vec<crate::command::RenderCommand>,
        dynamic_offsets: Vec<wgt::DynamicOffset>,
    },
    DestroyRenderBundle(id::RenderBundleId),
    WriteBuffer {
        id: id::BufferId,
        data: FileName,
        range: Range<wgt::BufferAddress>,
        queued: bool,
    },
    WriteTexture {
        to: crate::command::TextureCopyView,
        data: FileName,
        layout: wgt::TextureDataLayout,
        size: wgt::Extent3d,
    },
    Submit(crate::SubmissionIndex, Vec<Command>),
}
#[derive(Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum Command {
    CopyBufferToBuffer {
        src: id::BufferId,
        src_offset: wgt::BufferAddress,
        dst: id::BufferId,
        dst_offset: wgt::BufferAddress,
        size: wgt::BufferAddress,
    },
    CopyBufferToTexture {
        src: crate::command::BufferCopyView,
        dst: crate::command::TextureCopyView,
        size: wgt::Extent3d,
    },
    CopyTextureToBuffer {
        src: crate::command::TextureCopyView,
        dst: crate::command::BufferCopyView,
        size: wgt::Extent3d,
    },
    CopyTextureToTexture {
        src: crate::command::TextureCopyView,
        dst: crate::command::TextureCopyView,
        size: wgt::Extent3d,
    },
    RunComputePass {
        commands: Vec<crate::command::ComputeCommand>,
        dynamic_offsets: Vec<wgt::DynamicOffset>,
    },
    RunRenderPass {
        target_colors: Vec<crate::command::RenderPassColorAttachmentDescriptor>,
        target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachmentDescriptor>,
        commands: Vec<crate::command::RenderCommand>,
        dynamic_offsets: Vec<wgt::DynamicOffset>,
    },
}
#[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::Path) -> Result<Self, std::io::Error> {
        log::info!("Tracing into '{:?}'", path);
        let mut file = std::fs::File::create(path.join(FILE_NAME))?;
        file.write(b"[\n")?;
        Ok(Trace {
            path: path.to_path_buf(),
            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 = 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(b"]");
    }
}