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 OomError;
use buffer::BufferAccess;
use command_buffer::CommandBufferExecError;
use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolAlloc;
use command_buffer::pool::CommandPoolBuilderAlloc;
use command_buffer::sys::Flags;
use command_buffer::sys::Kind;
use command_buffer::sys::UnsafeCommandBuffer;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilderPipelineBarrier;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPassAbstract;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessCheckError;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::GpuFuture;
use sync::PipelineStages;
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 {
#[inline]
fn description(&self) -> &str {
match *self {
SyncCommandBufferBuilderError::Conflict { .. } => {
"unsolvable conflict"
},
}
}
}
impl fmt::Display for SyncCommandBufferBuilderError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
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_id: 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_id: self.command_id,
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 => {
let c = &commands_lock.commands[self.command_id];
c.buffer(self.resource_index).conflicts_buffer(buf)
},
KeyTy::Image => {
let c = &commands_lock.commands[self.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 => {
let c = &commands_lock.commands[self.command_id];
c.buffer(self.resource_index).conflicts_image(img)
},
KeyTy::Image => {
let c = &commands_lock.commands[self.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 => {
let c = &commands_lock.commands[other.command_id];
self.conflicts_buffer(&commands_lock, c.buffer(other.resource_index))
},
KeyTy::Image => {
let c = &commands_lock.commands[other.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_id];
c.buffer(self.resource_index).conflict_key().hash(state)
},
KeyTy::Image => {
let c = &commands_lock.commands[self.command_id];
c.image(self.resource_index).conflict_key().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_id: latest_command_id,
resource_ty,
resource_index,
};
match self.resources.entry(key) {
Entry::Occupied(entry) => {
let collision_cmd_id = entry.key().command_id;
debug_assert!(collision_cmd_id <= latest_command_id);
let entry_key_resource_index = entry.key().resource_index;
let entry_key_resource_ty = entry.key().resource_ty;
let entry = entry.into_mut();
if exclusive || entry.exclusive || entry.current_layout != start_layout {
if collision_cmd_id >= first_unflushed_cmd_id || entry.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 collision_cmd_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;
}
}
}
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,
0 .. img.mipmap_levels(),
0 .. img.dimensions().array_layers(),
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 {
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,
0 .. img.mipmap_levels(),
0 .. img.dimensions().array_layers(),
PipelineStages {
bottom_of_pipe: true,
..PipelineStages::none()
},
AccessFlagBits::none(),
stages,
access,
true,
None,
from_layout,
start_layout);
img.layout_initialized();
}
}
}
entry.insert(ResourceState {
stages: stages,
access: 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_id].image(key.resource_index);
let requested_layout = img.final_layout_requirement();
if requested_layout == state.current_layout {
continue;
}
barrier.add_image_memory_barrier(img,
0 .. img.mipmap_levels(),
0 .. img.dimensions().array_layers(),
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_id: 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,
command_id,
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 => {
let c = &commands_lock[command_id];
c.buffer(resource_index).conflicts_buffer(buf)
},
KeyTy::Image => {
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,
command_id,
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 => {
let c = &commands_lock[command_id];
c.buffer(resource_index).conflicts_image(img)
},
KeyTy::Image => {
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,
command_id,
resource_ty,
resource_index,
} => {
let commands_lock = commands.lock().unwrap();
match resource_ty {
KeyTy::Buffer => {
let c = &commands_lock[command_id];
other.conflicts_buffer(Some(&commands_lock), c.buffer(resource_index))
},
KeyTy::Image => {
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,
command_id,
resource_ty,
resource_index,
} => {
let commands_lock = commands.lock().unwrap();
match resource_ty {
KeyTy::Buffer => {
let c = &commands_lock[command_id];
c.buffer(resource_index).conflict_key().hash(state)
},
KeyTy::Image => {
let c = &commands_lock[command_id];
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_id, resource_ty, resource_index) = match *key {
CbKey::Command {
command_id,
resource_ty,
resource_index,
..
} => {
(command_id, resource_ty, resource_index)
},
_ => unreachable!(),
};
match resource_ty {
KeyTy::Buffer => {
let cmd = &commands_lock[command_id];
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_id,
});
break;
},
};
locked_resources += 1;
},
KeyTy::Image => {
let cmd = &commands_lock[command_id];
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_id,
});
break;
},
};
locked_resources += 1;
},
}
}
if let Err(_) = ret_value {
for key in self.resources.keys().take(locked_resources) {
let (command_id, resource_ty, resource_index) = match *key {
CbKey::Command {
command_id,
resource_ty,
resource_index,
..
} => {
(command_id, resource_ty, resource_index)
},
_ => unreachable!(),
};
match resource_ty {
KeyTy::Buffer => {
let cmd = &commands_lock[command_id];
let buf = cmd.buffer(resource_index);
unsafe {
buf.unlock();
}
},
KeyTy::Image => {
let cmd = &commands_lock[command_id];
let img = cmd.image(resource_index);
unsafe {
img.unlock(None);
}
},
}
}
}
ret_value
}
pub unsafe fn unlock(&self) {
let commands_lock = self.commands.lock().unwrap();
for (key, val) in self.resources.iter() {
let (command_id, resource_ty, resource_index) = match *key {
CbKey::Command {
command_id,
resource_ty,
resource_index,
..
} => {
(command_id, resource_ty, resource_index)
},
_ => unreachable!(),
};
match resource_ty {
KeyTy::Buffer => {
let cmd = &commands_lock[command_id];
let buf = cmd.buffer(resource_index);
buf.unlock();
},
KeyTy::Image => {
let cmd = &commands_lock[command_id];
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()
}
}