pub mod present;
pub mod render;
use {
crate::{
command::{Capability, Families, Family, FamilyId, Fence, Queue, Submission, Submittable},
factory::{Factory, UploadError},
frame::Frames,
graph::GraphContext,
wsi::SwapchainError,
BufferId, ImageId, NodeId,
},
rendy_core::hal::{queue::QueueFamilyId, Backend},
};
#[derive(Clone, Copy, Debug)]
pub struct BufferAccess {
pub access: rendy_core::hal::buffer::Access,
pub usage: rendy_core::hal::buffer::Usage,
pub stages: rendy_core::hal::pso::PipelineStage,
}
#[derive(Clone, Debug)]
pub struct BufferBarrier {
pub states: std::ops::Range<rendy_core::hal::buffer::State>,
pub stages: std::ops::Range<rendy_core::hal::pso::PipelineStage>,
pub families: Option<std::ops::Range<QueueFamilyId>>,
}
#[derive(Clone, Debug)]
pub struct NodeBuffer {
pub id: BufferId,
pub range: std::ops::Range<u64>,
pub acquire: Option<BufferBarrier>,
pub release: Option<BufferBarrier>,
}
#[derive(Clone, Copy, Debug)]
pub struct ImageAccess {
pub access: rendy_core::hal::image::Access,
pub usage: rendy_core::hal::image::Usage,
pub layout: rendy_core::hal::image::Layout,
pub stages: rendy_core::hal::pso::PipelineStage,
}
#[derive(Clone, Debug)]
pub struct ImageBarrier {
pub states: std::ops::Range<rendy_core::hal::image::State>,
pub stages: std::ops::Range<rendy_core::hal::pso::PipelineStage>,
pub families: Option<std::ops::Range<QueueFamilyId>>,
}
#[derive(Clone, Debug)]
pub struct NodeImage {
pub id: ImageId,
pub range: rendy_core::hal::image::SubresourceRange,
pub layout: rendy_core::hal::image::Layout,
pub clear: Option<rendy_core::hal::command::ClearValue>,
pub acquire: Option<ImageBarrier>,
pub release: Option<ImageBarrier>,
}
pub trait NodeSubmittable<'a, B: Backend> {
type Submittable: Submittable<B> + 'a;
type Submittables: IntoIterator<Item = Self::Submittable>;
}
pub trait Node<B: Backend, T: ?Sized>:
for<'a> NodeSubmittable<'a, B> + std::fmt::Debug + Sized + Sync + Send + 'static
{
type Capability: Capability;
fn run<'a>(
&'a mut self,
ctx: &GraphContext<B>,
factory: &Factory<B>,
aux: &T,
frames: &'a Frames<B>,
) -> <Self as NodeSubmittable<'a, B>>::Submittables;
unsafe fn dispose(self, factory: &mut Factory<B>, aux: &T);
}
pub trait NodeDesc<B: Backend, T: ?Sized>: std::fmt::Debug + Sized + 'static {
type Node: Node<B, T>;
fn builder(self) -> DescBuilder<B, T, Self> {
DescBuilder::new(self)
}
fn buffers(&self) -> Vec<BufferAccess> {
Vec::new()
}
fn images(&self) -> Vec<ImageAccess> {
Vec::new()
}
fn build<'a>(
self,
ctx: &GraphContext<B>,
factory: &mut Factory<B>,
family: &mut Family<B>,
queue: usize,
aux: &T,
buffers: Vec<NodeBuffer>,
images: Vec<NodeImage>,
) -> Result<Self::Node, NodeBuildError>;
}
pub trait DynNode<B: Backend, T: ?Sized>: std::fmt::Debug + Sync + Send {
unsafe fn run<'a>(
&mut self,
ctx: &GraphContext<B>,
factory: &Factory<B>,
queue: &mut Queue<B>,
aux: &T,
frames: &Frames<B>,
waits: &[(&'a B::Semaphore, rendy_core::hal::pso::PipelineStage)],
signals: &[&'a B::Semaphore],
fence: Option<&mut Fence<B>>,
);
unsafe fn dispose(self: Box<Self>, factory: &mut Factory<B>, aux: &T);
}
impl<B, T, N> DynNode<B, T> for (N,)
where
B: Backend,
T: ?Sized,
N: Node<B, T>,
{
unsafe fn run<'a>(
&mut self,
ctx: &GraphContext<B>,
factory: &Factory<B>,
queue: &mut Queue<B>,
aux: &T,
frames: &Frames<B>,
waits: &[(&'a B::Semaphore, rendy_core::hal::pso::PipelineStage)],
signals: &[&'a B::Semaphore],
fence: Option<&mut Fence<B>>,
) {
let submittables = Node::run(&mut self.0, ctx, factory, aux, frames);
queue.submit(
Some(
Submission::new()
.submits(submittables)
.wait(waits.iter().cloned())
.signal(signals.iter().cloned()),
),
fence,
)
}
unsafe fn dispose(self: Box<Self>, factory: &mut Factory<B>, aux: &T) {
N::dispose(self.0, factory, aux);
}
}
#[derive(Debug)]
pub enum NodeBuildError {
Upload(UploadError),
QueueFamily(FamilyId),
View(rendy_core::hal::image::ViewError),
Pipeline(rendy_core::hal::pso::CreationError),
Swapchain(SwapchainError),
OutOfMemory(rendy_core::hal::device::OutOfMemory),
}
pub trait NodeBuilder<B: Backend, T: ?Sized>: std::fmt::Debug {
fn family(&self, factory: &mut Factory<B>, families: &Families<B>) -> Option<FamilyId>;
fn buffers(&self) -> Vec<(BufferId, BufferAccess)>;
fn images(&self) -> Vec<(ImageId, ImageAccess)>;
fn dependencies(&self) -> Vec<NodeId>;
fn build<'a>(
self: Box<Self>,
ctx: &GraphContext<B>,
factory: &mut Factory<B>,
family: &mut Family<B>,
queue: usize,
aux: &T,
buffers: Vec<NodeBuffer>,
images: Vec<NodeImage>,
) -> Result<Box<dyn DynNode<B, T>>, NodeBuildError>;
}
pub struct DescBuilder<B: Backend, T: ?Sized, N> {
desc: N,
buffers: Vec<BufferId>,
images: Vec<ImageId>,
dependencies: Vec<NodeId>,
marker: std::marker::PhantomData<fn(B, &T)>,
}
impl<B, T, N> std::fmt::Debug for DescBuilder<B, T, N>
where
B: Backend,
T: ?Sized,
N: std::fmt::Debug,
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("DescBuilder")
.field("desc", &self.desc)
.field("buffers", &self.buffers)
.field("images", &self.images)
.field("dependencies", &self.dependencies)
.finish()
}
}
impl<B, T, N> DescBuilder<B, T, N>
where
B: Backend,
T: ?Sized,
{
pub fn new(desc: N) -> Self {
DescBuilder {
desc,
buffers: Vec::new(),
images: Vec::new(),
dependencies: Vec::new(),
marker: std::marker::PhantomData,
}
}
pub fn add_buffer(&mut self, buffer: BufferId) -> &mut Self {
self.buffers.push(buffer);
self
}
pub fn with_buffer(mut self, buffer: BufferId) -> Self {
self.add_buffer(buffer);
self
}
pub fn add_image(&mut self, image: ImageId) -> &mut Self {
self.images.push(image);
self
}
pub fn with_image(mut self, image: ImageId) -> Self {
self.add_image(image);
self
}
pub fn add_dependency(&mut self, dependency: NodeId) -> &mut Self {
self.dependencies.push(dependency);
self
}
pub fn with_dependency(mut self, dependency: NodeId) -> Self {
self.add_dependency(dependency);
self
}
}
impl<B, T, N> NodeBuilder<B, T> for DescBuilder<B, T, N>
where
B: Backend,
T: ?Sized,
N: NodeDesc<B, T>,
{
fn family(&self, _factory: &mut Factory<B>, families: &Families<B>) -> Option<FamilyId> {
families.with_capability::<<N::Node as Node<B, T>>::Capability>()
}
fn buffers(&self) -> Vec<(BufferId, BufferAccess)> {
let desc_buffers = self.desc.buffers();
assert_eq!(self.buffers.len(), desc_buffers.len());
self.buffers.iter().cloned().zip(desc_buffers).collect()
}
fn images(&self) -> Vec<(ImageId, ImageAccess)> {
let desc_images = self.desc.images();
assert_eq!(self.images.len(), desc_images.len());
self.images.iter().cloned().zip(desc_images).collect()
}
fn dependencies(&self) -> Vec<NodeId> {
self.dependencies.clone()
}
fn build<'a>(
self: Box<Self>,
ctx: &GraphContext<B>,
factory: &mut Factory<B>,
family: &mut Family<B>,
queue: usize,
aux: &T,
buffers: Vec<NodeBuffer>,
images: Vec<NodeImage>,
) -> Result<Box<dyn DynNode<B, T>>, NodeBuildError> {
Ok(Box::new((self.desc.build(
ctx, factory, family, queue, aux, buffers, images,
)?,)))
}
}
pub fn gfx_acquire_barriers<'a, 'b, B: Backend>(
ctx: &'a GraphContext<B>,
buffers: impl IntoIterator<Item = &'b NodeBuffer>,
images: impl IntoIterator<Item = &'b NodeImage>,
) -> (
std::ops::Range<rendy_core::hal::pso::PipelineStage>,
Vec<rendy_core::hal::memory::Barrier<'a, B>>,
) {
let mut bstart = rendy_core::hal::pso::PipelineStage::empty();
let mut bend = rendy_core::hal::pso::PipelineStage::empty();
let mut istart = rendy_core::hal::pso::PipelineStage::empty();
let mut iend = rendy_core::hal::pso::PipelineStage::empty();
let barriers: Vec<rendy_core::hal::memory::Barrier<'_, B>> = buffers
.into_iter()
.filter_map(|buffer| {
buffer.acquire.as_ref().map(|acquire| {
bstart |= acquire.stages.start;
bend |= acquire.stages.end;
rendy_core::hal::memory::Barrier::Buffer {
states: acquire.states.clone(),
families: acquire.families.clone(),
target: ctx
.get_buffer(buffer.id)
.expect("Buffer does not exist")
.raw(),
range: Some(buffer.range.start)..Some(buffer.range.end),
}
})
})
.chain(images.into_iter().filter_map(|image| {
image.acquire.as_ref().map(|acquire| {
istart |= acquire.stages.start;
iend |= acquire.stages.end;
rendy_core::hal::memory::Barrier::Image {
states: acquire.states.clone(),
families: acquire.families.clone(),
target: ctx.get_image(image.id).expect("Image does not exist").raw(),
range: image.range.clone(),
}
})
}))
.collect();
(bstart | istart..bend | iend, barriers)
}
pub fn gfx_release_barriers<'a, B: Backend>(
ctx: &'a GraphContext<B>,
buffers: impl IntoIterator<Item = &'a NodeBuffer>,
images: impl IntoIterator<Item = &'a NodeImage>,
) -> (
std::ops::Range<rendy_core::hal::pso::PipelineStage>,
Vec<rendy_core::hal::memory::Barrier<'a, B>>,
) {
let mut bstart = rendy_core::hal::pso::PipelineStage::empty();
let mut bend = rendy_core::hal::pso::PipelineStage::empty();
let mut istart = rendy_core::hal::pso::PipelineStage::empty();
let mut iend = rendy_core::hal::pso::PipelineStage::empty();
let barriers: Vec<rendy_core::hal::memory::Barrier<'_, B>> = buffers
.into_iter()
.filter_map(|buffer| {
buffer.release.as_ref().map(|release| {
bstart |= release.stages.start;
bend |= release.stages.end;
rendy_core::hal::memory::Barrier::Buffer {
states: release.states.clone(),
families: release.families.clone(),
target: ctx
.get_buffer(buffer.id)
.expect("Buffer does not exist")
.raw(),
range: Some(buffer.range.start)..Some(buffer.range.end),
}
})
})
.chain(images.into_iter().filter_map(|image| {
image.release.as_ref().map(|release| {
istart |= release.stages.start;
iend |= release.stages.end;
rendy_core::hal::memory::Barrier::Image {
states: release.states.clone(),
families: release.families.clone(),
target: ctx.get_image(image.id).expect("Image does not exist").raw(),
range: image.range.clone(),
}
})
}))
.collect();
(bstart | istart..bend | iend, barriers)
}