use super::ResourceId;
use crate::backend::{BufferHandle, ComputePipelineHandle, RenderTargetHandle, TextureHandle};
use std::sync::Arc;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct UsageKindFlags: u8 {
const COMPUTE = 0b001;
const TRANSFER = 0b010;
const RENDER = 0b100;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct SlotUsageSet {
pub access: NodeAccessUnion,
pub kinds: UsageKindFlags,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum NodeAccessUnion {
#[default]
ReadOnly,
Write,
}
impl NodeAccessUnion {
pub fn widen(self, access: NodeAccess) -> Self {
if access.writes() {
Self::Write
} else {
self
}
}
pub fn writes(self) -> bool {
matches!(self, Self::Write)
}
}
impl SlotUsageSet {
pub fn merge(&mut self, access: NodeAccess, kind: UsageKindFlags) {
self.access = self.access.widen(access);
self.kinds |= kind;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NodeAccess {
Read,
Write,
ReadWrite,
Overwrite,
}
impl NodeAccess {
pub fn writes(self) -> bool {
matches!(self, NodeAccess::Write | NodeAccess::ReadWrite | NodeAccess::Overwrite)
}
pub fn reads(self) -> bool {
matches!(self, NodeAccess::Read | NodeAccess::ReadWrite)
}
pub fn overwrites(self) -> bool {
matches!(self, NodeAccess::Overwrite)
}
}
impl From<crate::types::ResourceAccess> for NodeAccess {
fn from(access: crate::types::ResourceAccess) -> Self {
match access {
crate::types::ResourceAccess::Read => NodeAccess::Read,
crate::types::ResourceAccess::Write => NodeAccess::Write,
crate::types::ResourceAccess::ReadWrite => NodeAccess::ReadWrite,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ResourceBinding {
pub(crate) resource: ResourceId,
pub access: NodeAccess,
}
#[derive(Debug, Clone)]
pub enum DispatchDim {
Direct { x: u32, y: u32, z: u32 },
Indirect { buffer: BufferHandle, offset: u64 },
}
#[derive(Debug, Clone)]
#[allow(private_interfaces)]
pub enum NodeKind {
Dispatch {
pipeline: ComputePipelineHandle,
resource_slots: Vec<u32>,
user_slots: Vec<u32>,
dispatch: DispatchDim,
},
ClearBuffer {
buffer: BufferHandle,
offset: u64,
size: u64,
},
WriteBuffer {
buffer: BufferHandle,
offset: u64,
data: Arc<[u8]>,
},
CopyBuffer {
src: ResourceId,
src_offset: u64,
dst: ResourceId,
dst_offset: u64,
size: u64,
},
CopyBufferToTexture {
src: ResourceId,
src_offset: u64,
src_row_pitch: u32,
dst: TextureHandle,
x: u32,
y: u32,
width: u32,
height: u32,
},
WriteTexture {
texture: TextureHandle,
data: Arc<[u8]>,
width: u32,
height: u32,
},
WriteTextureRegion {
texture: TextureHandle,
x: u32,
y: u32,
width: u32,
height: u32,
data: Arc<[u8]>,
},
CopyTexture {
src: TextureHandle,
dst: ResourceId,
dst_buffer_layout: Option<crate::backend::TextureCopyFootprint>,
},
CopyRenderTarget { src: RenderTargetHandle, dst: ResourceId },
RenderPass {
target: RenderTargetHandle,
color_load: crate::types::TargetLoad,
commands: Vec<crate::backend::RenderCommand>,
},
WithdrawRead { withdraw_id: u32 },
}
#[derive(Debug, Clone)]
pub struct TaskNode {
pub label: &'static str,
pub bindings: Vec<ResourceBinding>,
pub kind: NodeKind,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct GraphIR {
pub(crate) nodes: Vec<TaskNode>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct BarrierUsage {
pub src: SlotUsageSet,
pub dst: SlotUsageSet,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct BarrierSet {
pub buffers: Vec<(BufferHandle, BarrierUsage)>,
pub textures: Vec<(TextureHandle, BarrierUsage)>,
pub transient_ids: Vec<(u32, BarrierUsage)>,
pub upload_ids: Vec<(u32, BarrierUsage)>,
}
impl BarrierSet {
pub fn is_empty(&self) -> bool {
self.buffers.is_empty()
&& self.textures.is_empty()
&& self.transient_ids.is_empty()
&& self.upload_ids.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct Wave {
pub node_indices: Vec<usize>,
pub barriers_before: BarrierSet,
}
#[derive(Debug, Clone)]
pub struct CompiledSchedule {
pub waves: Vec<Wave>,
}