zenfg 0.1.0

A FrameGraph compiler and transient-resource executor for wgpu
Documentation
use core::ops::Range;

use crate::{
    AccessId, AccessMode, AccessRole, BufferDesc, DebugGroupId, NodeKind, PassId,
    ResourceDescriptor, ResourceId, ResourceKind, ResourceOrigin, ResourceRange, RootReason,
    TextureDesc, TextureSubresourceRange, TextureViewDesc, ValueId, ViewId,
};

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum NormalizedRange {
    Buffer(Range<u64>),
    Texture(Vec<TextureSubresourceRange>),
}

impl NormalizedRange {
    pub(crate) fn report(&self) -> ResourceRange {
        match self {
            Self::Buffer(range) => ResourceRange::Buffer(crate::BufferRange::new(
                range.start,
                range.end - range.start,
            )),
            Self::Texture(regions) => ResourceRange::Texture(regions.clone()),
        }
    }

    pub(crate) fn overlaps(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Buffer(a), Self::Buffer(b)) => a.start < b.end && b.start < a.end,
            (Self::Texture(a), Self::Texture(b)) => a.iter().any(|left| {
                b.iter().any(|right| {
                    left.base_mip_level == right.base_mip_level
                        && left.aspect == right.aspect
                        && left.base_slice < right.base_slice + right.slice_count
                        && right.base_slice < left.base_slice + left.slice_count
                })
            }),
            _ => false,
        }
    }

    pub(crate) fn is_empty(&self) -> bool {
        match self {
            Self::Buffer(range) => range.is_empty(),
            Self::Texture(regions) => regions.iter().all(|region| region.slice_count == 0),
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct ResourceRecord {
    pub id: ResourceId,
    pub origin: ResourceOrigin,
    pub initial_contents: crate::InitialContents,
    pub descriptor: ResourceDescriptor,
    pub exposed_texture_usage: Option<wgpu::TextureUsages>,
    pub exposed_buffer_usage: Option<wgpu::BufferUsages>,
    pub debug_group: Option<DebugGroupId>,
}

impl ResourceRecord {
    pub(crate) fn kind(&self) -> ResourceKind {
        match self.descriptor {
            ResourceDescriptor::Texture(_) => ResourceKind::Texture,
            ResourceDescriptor::Buffer(_) => ResourceKind::Buffer,
        }
    }

    pub(crate) fn label(&self) -> &str {
        match &self.descriptor {
            ResourceDescriptor::Texture(desc) => &desc.label,
            ResourceDescriptor::Buffer(desc) => &desc.label,
        }
    }

    pub(crate) fn texture(&self) -> Option<&TextureDesc> {
        match &self.descriptor {
            ResourceDescriptor::Texture(desc) => Some(desc),
            ResourceDescriptor::Buffer(_) => None,
        }
    }

    pub(crate) fn buffer(&self) -> Option<&BufferDesc> {
        match &self.descriptor {
            ResourceDescriptor::Buffer(desc) => Some(desc),
            ResourceDescriptor::Texture(_) => None,
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct ViewRecord {
    pub id: ViewId,
    pub texture: ResourceId,
    pub descriptor: TextureViewDesc,
    pub range: NormalizedRange,
}

#[derive(Clone, Debug)]
pub(crate) struct AccessRecord {
    pub id: AccessId,
    pub pass: PassId,
    pub resource: ResourceId,
    pub role: AccessRole,
    pub mode: AccessMode,
    pub consumes_previous: bool,
    pub produces_value: bool,
    pub range: NormalizedRange,
    pub view: Option<ViewId>,
    pub value: Option<ValueId>,
}

#[derive(Clone, Debug)]
pub(crate) struct NodeRecord {
    pub id: PassId,
    pub kind: NodeKind,
    pub label: String,
    pub side_effect: bool,
    pub accesses: Vec<AccessRecord>,
    pub debug_group: Option<DebugGroupId>,
}

#[derive(Clone, Debug)]
pub(crate) struct DebugGroupRecord {
    pub id: DebugGroupId,
    pub parent: Option<DebugGroupId>,
    pub label: String,
}

#[derive(Clone, Debug)]
pub(crate) struct RootRecord {
    pub resource: ResourceId,
    pub reason: RootReason,
    pub range: NormalizedRange,
}