use fnv::FnvHashMap;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
use std::error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::sync::Mutex;
use buffer::BufferAccess;
use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolAlloc;
use command_buffer::pool::CommandPoolBuilderAlloc;
use command_buffer::sys::Flags;
use command_buffer::sys::UnsafeCommandBuffer;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilderPipelineBarrier;
use command_buffer::CommandBufferExecError;
use command_buffer::Kind;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPassAbstract;
use image::ImageAccess;
use image::ImageLayout;
use std::cell::RefCell;
use sync::AccessCheckError;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::GpuFuture;
use sync::PipelineStages;
use OomError;
pub struct SyncCommandBufferBuilder<P> {
inner: UnsafeCommandBufferBuilder<P>,
resources: FnvHashMap<BuilderKey<P>, ResourceState>,
pending_barrier: UnsafeCommandBufferBuilderPipelineBarrier,
commands: Arc<Mutex<Commands<P>>>,
is_secondary: bool,
}
impl<P> fmt::Debug for SyncCommandBufferBuilder<P> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.inner, f)
}
}
#[derive(Debug, Clone)]
pub enum SyncCommandBufferBuilderError {
Conflict {
command1_name: &'static str,
command1_param: Cow<'static, str>,
command1_offset: usize,
command2_name: &'static str,
command2_param: Cow<'static, str>,
command2_offset: usize,
},
}
impl error::Error for SyncCommandBufferBuilderError {}
impl fmt::Display for SyncCommandBufferBuilderError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
SyncCommandBufferBuilderError::Conflict { .. } => "unsolvable conflict",
}
)
}
}
struct Commands<P> {
first_unflushed: usize,
latest_render_pass_enter: Option<usize>,
commands: Vec<Box<dyn Command<P> + Send + Sync>>,
}
pub trait Command<P> {
fn name(&self) -> &'static str;
unsafe fn send(&mut self, out: &mut UnsafeCommandBufferBuilder<P>);
fn into_final_command(self: Box<Self>) -> Box<dyn FinalCommand + Send + Sync>;
fn buffer(&self, _num: usize) -> &dyn BufferAccess {
panic!()
}
fn image(&self, _num: usize) -> &dyn ImageAccess {
panic!()
}
fn buffer_name(&self, _num: usize) -> Cow<'static, str> {
panic!()
}
fn image_name(&self, _num: usize) -> Cow<'static, str> {
panic!()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum KeyTy {
Buffer,
Image,
}
struct BuilderKey<P> {
commands: Arc<Mutex<Commands<P>>>,
command_ids: RefCell<Vec<usize>>,
resource_ty: KeyTy,
resource_index: usize,
}
impl<P> BuilderKey<P> {
fn into_cb_key(
self,
final_commands: Arc<Mutex<Vec<Box<dyn FinalCommand + Send + Sync>>>>,
) -> CbKey<'static> {
CbKey::Command {
commands: final_commands,
command_ids: self.command_ids.borrow().clone(),
resource_ty: self.resource_ty,
resource_index: self.resource_index,
}
}
#[inline]
fn conflicts_buffer(&self, commands_lock: &Commands<P>, buf: &dyn BufferAccess) -> bool {
match self.resource_ty {
KeyTy::Buffer => self.command_ids.borrow().iter().any(|command_id| {
let c = &commands_lock.commands[*command_id];
c.buffer(self.resource_index).conflicts_buffer(buf)
}),
KeyTy::Image => self.command_ids.borrow().iter().any(|command_id| {
let c = &commands_lock.commands[*command_id];
c.image(self.resource_index).conflicts_buffer(buf)
}),
}
}
#[inline]
fn conflicts_image(&self, commands_lock: &Commands<P>, img: &dyn ImageAccess) -> bool {
match self.resource_ty {
KeyTy::Buffer => self.command_ids.borrow().iter().any(|command_id| {
let c = &commands_lock.commands[*command_id];
c.buffer(self.resource_index).conflicts_image(img)
}),
KeyTy::Image => self.command_ids.borrow().iter().any(|command_id| {
let c = &commands_lock.commands[*command_id];
c.image(self.resource_index).conflicts_image(img)
}),
}
}
}
impl<P> PartialEq for BuilderKey<P> {
#[inline]
fn eq(&self, other: &BuilderKey<P>) -> bool {
debug_assert!(Arc::ptr_eq(&self.commands, &other.commands));
let commands_lock = self.commands.lock().unwrap();
match other.resource_ty {
KeyTy::Buffer => other.command_ids.borrow().iter().any(|command_id| {
let c = &commands_lock.commands[*command_id];
self.conflicts_buffer(&commands_lock, c.buffer(other.resource_index))
}),
KeyTy::Image => other.command_ids.borrow().iter().any(|command_id| {
let c = &commands_lock.commands[*command_id];
self.conflicts_image(&commands_lock, c.image(other.resource_index))
}),
}
}
}
impl<P> Eq for BuilderKey<P> {}
impl<P> Hash for BuilderKey<P> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
let commands_lock = self.commands.lock().unwrap();
match self.resource_ty {
KeyTy::Buffer => {
let c = &commands_lock.commands[self.command_ids.borrow()[0]];
c.buffer(self.resource_index).conflict_key().hash(state)
}
KeyTy::Image => {
let c = &commands_lock.commands[self.command_ids.borrow()[0]];
c.image(self.resource_index).conflict_key().hash(state);
c.image(self.resource_index)
.current_miplevels_access()
.hash(state);
c.image(self.resource_index)
.current_layer_levels_access()
.hash(state);
}
}
}
}
#[derive(Debug, Clone)]
struct ResourceState {
stages: PipelineStages,
access: AccessFlagBits,
exclusive_any: bool,
exclusive: bool,
initial_layout: ImageLayout,
current_layout: ImageLayout,
}
impl ResourceState {
#[inline]
fn finalize(self) -> ResourceFinalState {
ResourceFinalState {
final_stages: self.stages,
final_access: self.access,
exclusive: self.exclusive_any,
initial_layout: self.initial_layout,
final_layout: self.current_layout,
}
}
}
impl<P> SyncCommandBufferBuilder<P> {
pub unsafe fn new<Pool, R, F, A>(
pool: &Pool,
kind: Kind<R, F>,
flags: Flags,
) -> Result<SyncCommandBufferBuilder<P>, OomError>
where
Pool: CommandPool<Builder = P, Alloc = A>,
P: CommandPoolBuilderAlloc<Alloc = A>,
A: CommandPoolAlloc,
R: RenderPassAbstract,
F: FramebufferAbstract,
{
let (is_secondary, inside_render_pass) = match kind {
Kind::Primary => (false, false),
Kind::Secondary {
ref render_pass, ..
} => (true, render_pass.is_some()),
};
let cmd = UnsafeCommandBufferBuilder::new(pool, kind, flags)?;
Ok(SyncCommandBufferBuilder::from_unsafe_cmd(
cmd,
is_secondary,
inside_render_pass,
))
}
#[inline]
pub unsafe fn from_unsafe_cmd(
cmd: UnsafeCommandBufferBuilder<P>,
is_secondary: bool,
inside_render_pass: bool,
) -> SyncCommandBufferBuilder<P> {
let latest_render_pass_enter = if inside_render_pass { Some(0) } else { None };
SyncCommandBufferBuilder {
inner: cmd,
resources: FnvHashMap::default(),
pending_barrier: UnsafeCommandBufferBuilderPipelineBarrier::new(),
commands: Arc::new(Mutex::new(Commands {
first_unflushed: 0,
latest_render_pass_enter,
commands: Vec::new(),
})),
is_secondary,
}
}
#[inline]
pub(super) fn append_command<C>(&mut self, command: C)
where
C: Command<P> + Send + Sync + 'static,
{
self.commands
.lock()
.unwrap()
.commands
.push(Box::new(command));
}
#[inline]
pub(super) fn prev_cmd_entered_render_pass(&mut self) {
let mut cmd_lock = self.commands.lock().unwrap();
cmd_lock.latest_render_pass_enter = Some(cmd_lock.commands.len() - 1);
}
#[inline]
pub(super) fn prev_cmd_left_render_pass(&mut self) {
let mut cmd_lock = self.commands.lock().unwrap();
debug_assert!(cmd_lock.latest_render_pass_enter.is_some());
cmd_lock.latest_render_pass_enter = None;
}
pub(super) fn prev_cmd_resource(
&mut self,
resource_ty: KeyTy,
resource_index: usize,
exclusive: bool,
stages: PipelineStages,
access: AccessFlagBits,
start_layout: ImageLayout,
end_layout: ImageLayout,
) -> Result<(), SyncCommandBufferBuilderError> {
debug_assert!(exclusive || start_layout == end_layout);
debug_assert!(access.is_compatible_with(&stages));
debug_assert!(resource_ty != KeyTy::Image || end_layout != ImageLayout::Undefined);
debug_assert!(resource_ty != KeyTy::Buffer || start_layout == ImageLayout::Undefined);
debug_assert!(resource_ty != KeyTy::Buffer || end_layout == ImageLayout::Undefined);
debug_assert_ne!(end_layout, ImageLayout::Preinitialized);
let (first_unflushed_cmd_id, latest_command_id) = {
let commands_lock = self.commands.lock().unwrap();
debug_assert!(commands_lock.commands.len() >= 1);
(
commands_lock.first_unflushed,
commands_lock.commands.len() - 1,
)
};
let key = BuilderKey {
commands: self.commands.clone(),
command_ids: RefCell::new(vec![latest_command_id]),
resource_ty,
resource_index,
};
match self.resources.entry(key) {
Entry::Occupied(entry) => {
let collision_cmd_ids = entry.key().command_ids.borrow().clone();
debug_assert!(collision_cmd_ids.iter().all(|id| *id <= latest_command_id));
let entry_key_resource_index = entry.key().resource_index;
let entry_key_resource_ty = entry.key().resource_ty;
if exclusive || entry.get().exclusive || entry.get().current_layout != start_layout
{
if collision_cmd_ids
.iter()
.any(|command_id| *command_id >= first_unflushed_cmd_id)
|| entry.get().current_layout != start_layout
{
unsafe {
self.inner.pipeline_barrier(&self.pending_barrier);
self.pending_barrier = UnsafeCommandBufferBuilderPipelineBarrier::new();
{
let mut commands_lock = self.commands.lock().unwrap();
let start = commands_lock.first_unflushed;
let end = if let Some(rp_enter) =
commands_lock.latest_render_pass_enter
{
rp_enter
} else {
latest_command_id
};
if let Some(collision_cmd_id) = collision_cmd_ids
.iter()
.find(|command_id| **command_id >= end)
{
let cmd1 = &commands_lock.commands[*collision_cmd_id];
let cmd2 = &commands_lock.commands[latest_command_id];
return Err(SyncCommandBufferBuilderError::Conflict {
command1_name: cmd1.name(),
command1_param: match entry_key_resource_ty {
KeyTy::Buffer => {
cmd1.buffer_name(entry_key_resource_index)
}
KeyTy::Image => {
cmd1.image_name(entry_key_resource_index)
}
},
command1_offset: *collision_cmd_id,
command2_name: cmd2.name(),
command2_param: match resource_ty {
KeyTy::Buffer => cmd2.buffer_name(resource_index),
KeyTy::Image => cmd2.image_name(resource_index),
},
command2_offset: latest_command_id,
});
}
for command in &mut commands_lock.commands[start..end] {
command.send(&mut self.inner);
}
commands_lock.first_unflushed = end;
}
}
}
entry.key().command_ids.borrow_mut().push(latest_command_id);
let entry = entry.into_mut();
unsafe {
let commands_lock = self.commands.lock().unwrap();
match resource_ty {
KeyTy::Buffer => {
let buf = commands_lock.commands[latest_command_id]
.buffer(resource_index);
let b = &mut self.pending_barrier;
b.add_buffer_memory_barrier(
buf,
entry.stages,
entry.access,
stages,
access,
true,
None,
0,
buf.size(),
);
}
KeyTy::Image => {
let img =
commands_lock.commands[latest_command_id].image(resource_index);
let b = &mut self.pending_barrier;
b.add_image_memory_barrier(
img,
img.current_miplevels_access(),
img.current_layer_levels_access(),
entry.stages,
entry.access,
stages,
access,
true,
None,
entry.current_layout,
start_layout,
);
}
};
}
entry.stages = stages;
entry.access = access;
entry.exclusive_any = true;
entry.exclusive = exclusive;
if exclusive || end_layout != ImageLayout::Undefined {
entry.current_layout = end_layout;
}
} else {
let entry = entry.into_mut();
entry.stages = entry.stages | stages;
entry.access = entry.access | access;
}
}
Entry::Vacant(entry) => {
let mut actually_exclusive = exclusive;
let mut actual_start_layout = start_layout;
if !self.is_secondary
&& resource_ty == KeyTy::Image
&& start_layout != ImageLayout::Undefined
&& start_layout != ImageLayout::Preinitialized
{
let commands_lock = self.commands.lock().unwrap();
let img = commands_lock.commands[latest_command_id].image(resource_index);
let initial_layout_requirement = img.initial_layout_requirement();
let is_layout_initialized = img.is_layout_initialized();
if initial_layout_requirement != start_layout || !is_layout_initialized {
unsafe {
let from_layout = if is_layout_initialized {
actually_exclusive = true;
initial_layout_requirement
} else {
if img.preinitialized_layout() {
ImageLayout::Preinitialized
} else {
ImageLayout::Undefined
}
};
if initial_layout_requirement != start_layout {
actual_start_layout = initial_layout_requirement;
}
let b = &mut self.pending_barrier;
b.add_image_memory_barrier(
img,
img.current_miplevels_access(),
img.current_layer_levels_access(),
PipelineStages {
bottom_of_pipe: true,
..PipelineStages::none()
},
AccessFlagBits::none(),
stages,
access,
true,
None,
from_layout,
start_layout,
);
img.layout_initialized();
}
}
}
entry.insert(ResourceState {
stages,
access,
exclusive_any: actually_exclusive,
exclusive: actually_exclusive,
initial_layout: actual_start_layout,
current_layout: end_layout,
});
}
}
Ok(())
}
#[inline]
pub fn build(mut self) -> Result<SyncCommandBuffer<P::Alloc>, OomError>
where
P: CommandPoolBuilderAlloc,
{
let mut commands_lock = self.commands.lock().unwrap();
debug_assert!(
commands_lock.latest_render_pass_enter.is_none() || self.pending_barrier.is_empty()
);
unsafe {
self.inner.pipeline_barrier(&self.pending_barrier);
let f = commands_lock.first_unflushed;
for command in &mut commands_lock.commands[f..] {
command.send(&mut self.inner);
}
}
if !self.is_secondary {
unsafe {
let mut barrier = UnsafeCommandBufferBuilderPipelineBarrier::new();
for (key, state) in &mut self.resources {
if key.resource_ty != KeyTy::Image {
continue;
}
let img = commands_lock.commands[key.command_ids.borrow()[0]]
.image(key.resource_index);
let requested_layout = img.final_layout_requirement();
if requested_layout == state.current_layout {
continue;
}
barrier.add_image_memory_barrier(
img,
img.current_miplevels_access(),
img.current_layer_levels_access(),
state.stages,
state.access,
PipelineStages {
top_of_pipe: true,
..PipelineStages::none()
},
AccessFlagBits::none(),
true,
None,
state.current_layout,
requested_layout,
);
state.exclusive_any = true;
state.current_layout = requested_layout;
}
self.inner.pipeline_barrier(&barrier);
}
}
let final_commands = {
let mut final_commands = Vec::with_capacity(commands_lock.commands.len());
for command in commands_lock.commands.drain(..) {
final_commands.push(command.into_final_command());
}
Arc::new(Mutex::new(final_commands))
};
let final_resources_states: FnvHashMap<_, _> = {
self.resources
.into_iter()
.map(|(resource, state)| {
(
resource.into_cb_key(final_commands.clone()),
state.finalize(),
)
})
.collect()
};
Ok(SyncCommandBuffer {
inner: self.inner.build()?,
resources: final_resources_states,
commands: final_commands,
})
}
}
unsafe impl<P> DeviceOwned for SyncCommandBufferBuilder<P> {
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
pub struct SyncCommandBuffer<P> {
inner: UnsafeCommandBuffer<P>,
resources: FnvHashMap<CbKey<'static>, ResourceFinalState>,
commands: Arc<Mutex<Vec<Box<dyn FinalCommand + Send + Sync>>>>,
}
#[derive(Debug, Clone)]
struct ResourceFinalState {
final_stages: PipelineStages,
final_access: AccessFlagBits,
exclusive: bool,
initial_layout: ImageLayout,
final_layout: ImageLayout,
}
pub trait FinalCommand {
fn name(&self) -> &'static str;
fn buffer(&self, _num: usize) -> &dyn BufferAccess {
panic!()
}
fn image(&self, _num: usize) -> &dyn ImageAccess {
panic!()
}
fn buffer_name(&self, _num: usize) -> Cow<'static, str> {
panic!()
}
fn image_name(&self, _num: usize) -> Cow<'static, str> {
panic!()
}
}
impl FinalCommand for &'static str {
fn name(&self) -> &'static str {
*self
}
}
enum CbKey<'a> {
Command {
commands: Arc<Mutex<Vec<Box<dyn FinalCommand + Send + Sync>>>>,
command_ids: Vec<usize>,
resource_ty: KeyTy,
resource_index: usize,
},
BufferRef(&'a dyn BufferAccess),
ImageRef(&'a dyn ImageAccess),
}
unsafe impl<'a> Send for CbKey<'a> {}
unsafe impl<'a> Sync for CbKey<'a> {}
impl<'a> CbKey<'a> {
#[inline]
fn conflicts_buffer(
&self,
commands_lock: Option<&Vec<Box<dyn FinalCommand + Send + Sync>>>,
buf: &dyn BufferAccess,
) -> bool {
match *self {
CbKey::Command {
ref commands,
ref command_ids,
resource_ty,
resource_index,
} => {
let lock = if commands_lock.is_none() {
Some(commands.lock().unwrap())
} else {
None
};
let commands_lock = commands_lock.unwrap_or_else(|| lock.as_ref().unwrap());
match resource_ty {
KeyTy::Buffer => command_ids.iter().any(|command_id| {
let c = &commands_lock[*command_id];
c.buffer(resource_index).conflicts_buffer(buf)
}),
KeyTy::Image => command_ids.iter().any(|command_id| {
let c = &commands_lock[*command_id];
c.image(resource_index).conflicts_buffer(buf)
}),
}
}
CbKey::BufferRef(b) => b.conflicts_buffer(buf),
CbKey::ImageRef(i) => i.conflicts_buffer(buf),
}
}
#[inline]
fn conflicts_image(
&self,
commands_lock: Option<&Vec<Box<dyn FinalCommand + Send + Sync>>>,
img: &dyn ImageAccess,
) -> bool {
match *self {
CbKey::Command {
ref commands,
ref command_ids,
resource_ty,
resource_index,
} => {
let lock = if commands_lock.is_none() {
Some(commands.lock().unwrap())
} else {
None
};
let commands_lock = commands_lock.unwrap_or_else(|| lock.as_ref().unwrap());
match resource_ty {
KeyTy::Buffer => command_ids.iter().any(|command_id| {
let c = &commands_lock[*command_id];
c.buffer(resource_index).conflicts_image(img)
}),
KeyTy::Image => command_ids.iter().any(|command_id| {
let c = &commands_lock[*command_id];
c.image(resource_index).conflicts_image(img)
}),
}
}
CbKey::BufferRef(b) => b.conflicts_image(img),
CbKey::ImageRef(i) => i.conflicts_image(img),
}
}
}
impl<'a> PartialEq for CbKey<'a> {
#[inline]
fn eq(&self, other: &CbKey) -> bool {
match *self {
CbKey::BufferRef(a) => other.conflicts_buffer(None, a),
CbKey::ImageRef(a) => other.conflicts_image(None, a),
CbKey::Command {
ref commands,
ref command_ids,
resource_ty,
resource_index,
} => {
let commands_lock = commands.lock().unwrap();
match resource_ty {
KeyTy::Buffer => command_ids.iter().any(|command_id| {
let c = &commands_lock[*command_id];
other.conflicts_buffer(Some(&commands_lock), c.buffer(resource_index))
}),
KeyTy::Image => command_ids.iter().any(|command_id| {
let c = &commands_lock[*command_id];
other.conflicts_image(Some(&commands_lock), c.image(resource_index))
}),
}
}
}
}
}
impl<'a> Eq for CbKey<'a> {}
impl<'a> Hash for CbKey<'a> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
match *self {
CbKey::Command {
ref commands,
ref command_ids,
resource_ty,
resource_index,
} => {
let commands_lock = commands.lock().unwrap();
match resource_ty {
KeyTy::Buffer => {
let c = &commands_lock[command_ids[0]];
c.buffer(resource_index).conflict_key().hash(state)
}
KeyTy::Image => {
let c = &commands_lock[command_ids[0]];
c.image(resource_index).conflict_key().hash(state)
}
}
}
CbKey::BufferRef(buf) => buf.conflict_key().hash(state),
CbKey::ImageRef(img) => img.conflict_key().hash(state),
}
}
}
impl<P> AsRef<UnsafeCommandBuffer<P>> for SyncCommandBuffer<P> {
#[inline]
fn as_ref(&self) -> &UnsafeCommandBuffer<P> {
&self.inner
}
}
impl<P> SyncCommandBuffer<P> {
pub fn lock_submit(
&self,
future: &dyn GpuFuture,
queue: &Queue,
) -> Result<(), CommandBufferExecError> {
let commands_lock = self.commands.lock().unwrap();
let mut locked_resources = 0;
let mut ret_value = Ok(());
for (key, entry) in self.resources.iter() {
let (command_ids, resource_ty, resource_index) = match *key {
CbKey::Command {
ref command_ids,
resource_ty,
resource_index,
..
} => (command_ids, resource_ty, resource_index),
_ => unreachable!(),
};
match resource_ty {
KeyTy::Buffer => {
let cmd = &commands_lock[command_ids[0]];
let buf = cmd.buffer(resource_index);
let prev_err = match future.check_buffer_access(&buf, entry.exclusive, queue) {
Ok(_) => {
unsafe {
buf.increase_gpu_lock();
}
locked_resources += 1;
continue;
}
Err(err) => err,
};
match (buf.try_gpu_lock(entry.exclusive, queue), prev_err) {
(Ok(_), _) => (),
(Err(err), AccessCheckError::Unknown)
| (_, AccessCheckError::Denied(err)) => {
ret_value = Err(CommandBufferExecError::AccessError {
error: err,
command_name: cmd.name().into(),
command_param: cmd.buffer_name(resource_index),
command_offset: command_ids[0],
});
break;
}
};
locked_resources += 1;
}
KeyTy::Image => {
let cmd = &commands_lock[command_ids[0]];
let img = cmd.image(resource_index);
let prev_err = match future.check_image_access(
img,
entry.initial_layout,
entry.exclusive,
queue,
) {
Ok(_) => {
unsafe {
img.increase_gpu_lock();
}
locked_resources += 1;
continue;
}
Err(err) => err,
};
match (
img.try_gpu_lock(entry.exclusive, entry.initial_layout),
prev_err,
) {
(Ok(_), _) => (),
(Err(err), AccessCheckError::Unknown)
| (_, AccessCheckError::Denied(err)) => {
ret_value = Err(CommandBufferExecError::AccessError {
error: err,
command_name: cmd.name().into(),
command_param: cmd.image_name(resource_index),
command_offset: command_ids[0],
});
break;
}
};
locked_resources += 1;
}
}
}
if let Err(_) = ret_value {
for (key, val) in self.resources.iter().take(locked_resources) {
let (command_ids, resource_ty, resource_index) = match *key {
CbKey::Command {
ref command_ids,
resource_ty,
resource_index,
..
} => (command_ids, resource_ty, resource_index),
_ => unreachable!(),
};
match resource_ty {
KeyTy::Buffer => {
let cmd = &commands_lock[command_ids[0]];
let buf = cmd.buffer(resource_index);
unsafe {
buf.unlock();
}
}
KeyTy::Image => {
let cmd = &commands_lock[command_ids[0]];
let img = cmd.image(resource_index);
let trans = if val.final_layout != val.initial_layout {
Some(val.final_layout)
} else {
None
};
unsafe {
img.unlock(trans);
}
}
}
}
}
ret_value
}
pub unsafe fn unlock(&self) {
let commands_lock = self.commands.lock().unwrap();
for (key, val) in self.resources.iter() {
let (command_ids, resource_ty, resource_index) = match *key {
CbKey::Command {
ref command_ids,
resource_ty,
resource_index,
..
} => (command_ids, resource_ty, resource_index),
_ => unreachable!(),
};
match resource_ty {
KeyTy::Buffer => {
let cmd = &commands_lock[command_ids[0]];
let buf = cmd.buffer(resource_index);
buf.unlock();
}
KeyTy::Image => {
let cmd = &commands_lock[command_ids[0]];
let img = cmd.image(resource_index);
let trans = if val.final_layout != val.initial_layout {
Some(val.final_layout)
} else {
None
};
img.unlock(trans);
}
}
}
}
#[inline]
pub fn check_buffer_access(
&self,
buffer: &dyn BufferAccess,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
if let Some(value) = self.resources.get(&CbKey::BufferRef(buffer)) {
if !value.exclusive && exclusive {
return Err(AccessCheckError::Unknown);
}
return Ok(Some((value.final_stages, value.final_access)));
}
Err(AccessCheckError::Unknown)
}
#[inline]
pub fn check_image_access(
&self,
image: &dyn ImageAccess,
layout: ImageLayout,
exclusive: bool,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
if let Some(value) = self.resources.get(&CbKey::ImageRef(image)) {
if layout != ImageLayout::Undefined && value.final_layout != layout {
return Err(AccessCheckError::Denied(
AccessError::UnexpectedImageLayout {
allowed: value.final_layout,
requested: layout,
},
));
}
if !value.exclusive && exclusive {
return Err(AccessCheckError::Unknown);
}
return Ok(Some((value.final_stages, value.final_access)));
}
Err(AccessCheckError::Unknown)
}
}
unsafe impl<P> DeviceOwned for SyncCommandBuffer<P> {
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}