use smallvec::SmallVec;
use std::cell::RefCell;
use std::ops::Range;
use context::CommandContext;
use sync::{self, LinearSyncFence};
pub struct Fences {
fences: RefCell<SmallVec<[(Range<usize>, LinearSyncFence); 16]>>,
}
impl Fences {
pub fn new() -> Fences {
Fences {
fences: RefCell::new(SmallVec::new()),
}
}
#[inline]
pub fn inserter(&self, range: Range<usize>) -> Inserter {
Inserter {
fences: self,
range: range,
}
}
pub fn wait(&self, ctxt: &mut CommandContext, range: Range<usize>) {
let mut existing_fences = self.fences.borrow_mut();
let mut new_fences = SmallVec::new();
for existing in existing_fences.drain() {
if (existing.0.start >= range.start && existing.0.start < range.end) ||
(existing.0.end > range.start && existing.0.end < range.end)
{
unsafe { sync::wait_linear_sync_fence_and_drop(existing.1, ctxt) };
} else {
new_fences.push(existing);
}
}
*existing_fences = new_fences;
}
pub fn clean(&mut self, ctxt: &mut CommandContext) {
let mut fences = self.fences.borrow_mut();
for (_, sync) in fences.drain() {
unsafe { sync::destroy_linear_sync_fence(ctxt, sync) };
}
}
}
pub struct Inserter<'a> {
fences: &'a Fences,
range: Range<usize>,
}
impl<'a> Inserter<'a> {
pub fn insert(self, ctxt: &mut CommandContext) {
let mut new_fences = SmallVec::new();
let mut written = false;
let mut existing_fences = self.fences.fences.borrow_mut();
for existing in existing_fences.drain() {
if existing.0.start < self.range.start && existing.0.end <= self.range.start {
new_fences.push(existing);
} else if existing.0.start < self.range.start && existing.0.end >= self.range.end {
let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
new_fences.push((existing.0.start .. self.range.start, existing.1));
new_fences.push((self.range.start .. existing.0.end, new_fence));
written = true;
} else if existing.0.start < self.range.start && existing.0.end >= self.range.start {
new_fences.push((existing.0.start .. self.range.start, existing.1));
if !written {
let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
new_fences.push((self.range.clone(), new_fence));
written = true;
}
} else if existing.0.start >= self.range.start && existing.0.end <= self.range.end {
unsafe { sync::destroy_linear_sync_fence(ctxt, existing.1) };
if !written {
let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
new_fences.push((self.range.clone(), new_fence));
written = true;
}
} else if existing.0.start >= self.range.end {
if !written {
let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
new_fences.push((self.range.clone(), new_fence));
written = true;
}
new_fences.push(existing);
} else {
if !written {
let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
new_fences.push((self.range.clone(), new_fence));
written = true;
}
new_fences.push((self.range.end .. existing.0.end, existing.1));
}
}
if !written {
let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
new_fences.push((self.range, new_fence));
}
*existing_fences = new_fences;
}
}