use std::sync::Arc;
use command_buffer::cb::AddCommand;
use command_buffer::cb::CommandBufferBuild;
use command_buffer::CommandAddError;
use command_buffer::CommandBufferBuilder;
use command_buffer::commands_raw;
use device::Device;
use device::DeviceOwned;
use instance::QueueFamily;
pub struct ContextCheckLayer<I> {
inner: I,
inside_render_pass: bool,
allow_render_pass_ops: bool,
}
impl<I> ContextCheckLayer<I> {
#[inline]
pub fn new(inner: I, inside_render_pass: bool, allow_render_pass_ops: bool)
-> ContextCheckLayer<I>
{
ContextCheckLayer {
inner: inner,
inside_render_pass: inside_render_pass,
allow_render_pass_ops: allow_render_pass_ops,
}
}
#[inline]
pub fn into_inner(self) -> I {
self.inner
}
}
unsafe impl<I, O, E> CommandBufferBuild for ContextCheckLayer<I>
where I: CommandBufferBuild<Out = O, Err = E>
{
type Out = O;
type Err = E;
#[inline]
fn build(self) -> Result<O, E> {
self.inner.build()
}
}
unsafe impl<I> DeviceOwned for ContextCheckLayer<I>
where I: DeviceOwned
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
unsafe impl<I> CommandBufferBuilder for ContextCheckLayer<I>
where I: CommandBufferBuilder
{
#[inline]
fn queue_family(&self) -> QueueFamily {
self.inner.queue_family()
}
}
macro_rules! impl_always {
(($($param:ident),*), $cmd:ty) => {
unsafe impl<'a, I, O $(, $param)*> AddCommand<$cmd> for ContextCheckLayer<I>
where I: AddCommand<$cmd, Out = O>
{
type Out = ContextCheckLayer<O>;
#[inline]
fn add(self, command: $cmd) -> Result<Self::Out, CommandAddError> {
Ok(ContextCheckLayer {
inner: self.inner.add(command)?,
inside_render_pass: self.inside_render_pass,
allow_render_pass_ops: self.allow_render_pass_ops,
})
}
}
}
}
impl_always!((S, Pl), commands_raw::CmdBindDescriptorSets<S, Pl>);
impl_always!((B), commands_raw::CmdBindIndexBuffer<B>);
impl_always!((Pl), commands_raw::CmdBindPipeline<Pl>);
impl_always!((V), commands_raw::CmdBindVertexBuffers<V>);
impl_always!((Pc, Pl), commands_raw::CmdPushConstants<Pc, Pl>);
impl_always!((), commands_raw::CmdSetState);
macro_rules! impl_inside_only {
(($($param:ident),*), $cmd:ty) => {
unsafe impl<'a, I, O $(, $param)*> AddCommand<$cmd> for ContextCheckLayer<I>
where I: AddCommand<$cmd, Out = O>
{
type Out = ContextCheckLayer<O>;
#[inline]
fn add(self, command: $cmd) -> Result<Self::Out, CommandAddError> {
if !self.inside_render_pass {
return Err(CommandAddError::ForbiddenOutsideRenderPass);
}
Ok(ContextCheckLayer {
inner: self.inner.add(command)?,
inside_render_pass: self.inside_render_pass,
allow_render_pass_ops: self.allow_render_pass_ops,
})
}
}
}
}
impl_inside_only!((), commands_raw::CmdClearAttachments);
impl_inside_only!((), commands_raw::CmdDrawIndexedRaw);
impl_inside_only!((B), commands_raw::CmdDrawIndirectRaw<B>);
impl_inside_only!((), commands_raw::CmdDrawRaw);
macro_rules! impl_outside_only {
(($($param:ident),*), $cmd:ty) => {
unsafe impl<'a, I, O $(, $param)*> AddCommand<$cmd> for ContextCheckLayer<I>
where I: AddCommand<$cmd, Out = O>
{
type Out = ContextCheckLayer<O>;
#[inline]
fn add(self, command: $cmd) -> Result<Self::Out, CommandAddError> {
if self.inside_render_pass {
return Err(CommandAddError::ForbiddenInsideRenderPass);
}
Ok(ContextCheckLayer {
inner: self.inner.add(command)?,
inside_render_pass: self.inside_render_pass,
allow_render_pass_ops: self.allow_render_pass_ops,
})
}
}
}
}
impl_outside_only!((S, D), commands_raw::CmdBlitImage<S, D>);
impl_outside_only!((S, D), commands_raw::CmdCopyBuffer<S, D>);
impl_outside_only!((S, D), commands_raw::CmdCopyBufferToImage<S, D>);
impl_outside_only!((S, D), commands_raw::CmdCopyImage<S, D>);
impl_outside_only!((), commands_raw::CmdDispatchRaw);
impl_outside_only!((B), commands_raw::CmdFillBuffer<B>);
impl_outside_only!((S, D), commands_raw::CmdResolveImage<S, D>);
impl_outside_only!((), commands_raw::CmdSetEvent);
impl_outside_only!((B, D), commands_raw::CmdUpdateBuffer<B, D>);
unsafe impl<'a, I, O, Rp, F> AddCommand<commands_raw::CmdBeginRenderPass<Rp, F>> for ContextCheckLayer<I>
where I: AddCommand<commands_raw::CmdBeginRenderPass<Rp, F>, Out = O>
{
type Out = ContextCheckLayer<O>;
#[inline]
fn add(self, command: commands_raw::CmdBeginRenderPass<Rp, F>) -> Result<Self::Out, CommandAddError> {
if self.inside_render_pass {
return Err(CommandAddError::ForbiddenInsideRenderPass);
}
if !self.allow_render_pass_ops {
return Err(CommandAddError::ForbiddenInSecondaryCommandBuffer);
}
Ok(ContextCheckLayer {
inner: self.inner.add(command)?,
inside_render_pass: true,
allow_render_pass_ops: true,
})
}
}
unsafe impl<'a, I, O> AddCommand<commands_raw::CmdNextSubpass> for ContextCheckLayer<I>
where I: AddCommand<commands_raw::CmdNextSubpass, Out = O>
{
type Out = ContextCheckLayer<O>;
#[inline]
fn add(self, command: commands_raw::CmdNextSubpass) -> Result<Self::Out, CommandAddError> {
if !self.inside_render_pass {
return Err(CommandAddError::ForbiddenOutsideRenderPass);
}
if !self.allow_render_pass_ops {
return Err(CommandAddError::ForbiddenInSecondaryCommandBuffer);
}
Ok(ContextCheckLayer {
inner: self.inner.add(command)?,
inside_render_pass: true,
allow_render_pass_ops: true,
})
}
}
unsafe impl<'a, I, O> AddCommand<commands_raw::CmdEndRenderPass> for ContextCheckLayer<I>
where I: AddCommand<commands_raw::CmdEndRenderPass, Out = O>
{
type Out = ContextCheckLayer<O>;
#[inline]
fn add(self, command: commands_raw::CmdEndRenderPass) -> Result<Self::Out, CommandAddError> {
if !self.inside_render_pass {
return Err(CommandAddError::ForbiddenOutsideRenderPass);
}
if !self.allow_render_pass_ops {
return Err(CommandAddError::ForbiddenInSecondaryCommandBuffer);
}
Ok(ContextCheckLayer {
inner: self.inner.add(command)?,
inside_render_pass: false,
allow_render_pass_ops: true,
})
}
}