use {
crate::{
command::Encoder,
resource::{Handle, Image},
},
gfx_hal::{self, buffer, image, memory::Barrier, pso, Backend},
std::ops::Range,
};
#[derive(Debug)]
struct ImageBarrier<B: Backend> {
pub states: Range<image::State>,
pub target: Handle<Image<B>>,
pub range: image::SubresourceRange,
}
impl<B: Backend> ImageBarrier<B> {
fn raw(&self) -> Barrier<'_, B> {
Barrier::Image {
states: self.states.clone(),
target: self.target.raw(),
families: None,
range: self.range.clone(),
}
}
}
#[derive(Debug)]
pub struct Barriers<B: Backend> {
before_stages: pso::PipelineStage,
before_buffer_access: buffer::Access,
before_image_access: image::Access,
before_image_transitions: Vec<ImageBarrier<B>>,
target_stages: pso::PipelineStage,
target_buffer_access: buffer::Access,
target_image_access: image::Access,
after_stages: pso::PipelineStage,
after_buffer_access: buffer::Access,
after_image_access: image::Access,
after_image_transitions: Vec<ImageBarrier<B>>,
}
impl<B: Backend> Barriers<B> {
pub fn new(
target_stages: pso::PipelineStage,
target_buffer_access: buffer::Access,
target_image_access: image::Access,
) -> Self {
Self {
before_stages: pso::PipelineStage::empty(),
before_buffer_access: buffer::Access::empty(),
before_image_access: image::Access::empty(),
before_image_transitions: Vec::new(),
target_stages,
target_buffer_access,
target_image_access,
after_stages: pso::PipelineStage::empty(),
after_buffer_access: buffer::Access::empty(),
after_image_access: image::Access::empty(),
after_image_transitions: Vec::new(),
}
}
pub fn add_image(
&mut self,
image: Handle<Image<B>>,
image_range: gfx_hal::image::SubresourceRange,
last_stage: pso::PipelineStage,
last_access: gfx_hal::image::Access,
last_layout: gfx_hal::image::Layout,
target_layout: image::Layout,
next_stage: pso::PipelineStage,
next_access: gfx_hal::image::Access,
next_layout: gfx_hal::image::Layout,
) {
self.before_stages |= last_stage;
self.before_image_access |= last_access;
self.after_stages |= next_stage;
self.after_image_access |= next_access;
if last_layout != target_layout {
log::trace!(
"Transition last: {:?}",
(last_access, last_layout)..(self.target_image_access, target_layout)
);
self.before_image_transitions.push(ImageBarrier {
states: (last_access, last_layout)..(self.target_image_access, target_layout),
target: image.clone(),
range: image_range.clone(),
});
}
if next_layout != target_layout {
log::trace!(
"Transition next: {:?}",
(self.target_image_access, target_layout)..(next_access, next_layout)
);
self.after_image_transitions.push(ImageBarrier {
states: (self.target_image_access, target_layout)..(next_access, next_layout),
target: image,
range: image_range,
})
}
}
pub fn add_buffer(
&mut self,
last_stage: pso::PipelineStage,
last_access: gfx_hal::buffer::Access,
next_stage: pso::PipelineStage,
next_access: gfx_hal::buffer::Access,
) {
self.before_stages |= last_stage;
self.before_buffer_access |= last_access;
self.after_stages |= next_stage;
self.after_buffer_access |= next_access;
}
pub fn encode_before<C, L>(&mut self, encoder: &mut Encoder<'_, B, C, L>) {
if !self.before_stages.is_empty() {
let transitions = self.before_image_transitions.iter().map(|b| b.raw());
let all_images = Some(Barrier::AllImages(
self.before_image_access..self.target_image_access,
))
.filter(|_| !self.before_image_access.is_empty());
let all_buffers = Some(Barrier::AllBuffers(
self.before_buffer_access..self.target_buffer_access,
))
.filter(|_| !self.before_buffer_access.is_empty());
unsafe {
encoder.pipeline_barrier(
self.before_stages..self.target_stages,
gfx_hal::memory::Dependencies::empty(),
transitions.chain(all_images).chain(all_buffers),
);
}
} else {
assert_eq!(self.before_image_transitions.len(), 0);
}
self.before_stages = pso::PipelineStage::empty();
self.before_image_access = image::Access::empty();
self.before_buffer_access = buffer::Access::empty();
self.before_image_transitions.clear();
}
pub fn encode_after<C, L>(&mut self, encoder: &mut Encoder<'_, B, C, L>) {
if !self.target_stages.is_empty() {
let transitions = self.after_image_transitions.iter().map(|b| b.raw());
let all_images = Some(Barrier::AllImages(
self.target_image_access..self.after_image_access,
))
.filter(|_| !self.after_image_access.is_empty());
let all_buffers = Some(Barrier::AllBuffers(
self.target_buffer_access..self.after_buffer_access,
))
.filter(|_| !self.after_buffer_access.is_empty());
unsafe {
encoder.pipeline_barrier(
self.target_stages..self.after_stages,
gfx_hal::memory::Dependencies::empty(),
transitions.chain(all_images).chain(all_buffers),
);
}
} else {
assert_eq!(self.after_image_transitions.len(), 0);
}
self.after_stages = pso::PipelineStage::empty();
self.after_image_access = image::Access::empty();
self.after_buffer_access = buffer::Access::empty();
self.after_image_transitions.clear();
}
}