use std::ptr;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use buffer::BufferAccess;
use command_buffer::CommandBuffer;
use command_buffer::CommandBufferBuilder;
use command_buffer::CommandBufferExecError;
use command_buffer::cb::CommandBufferBuild;
use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolBuilderAlloc;
use command_buffer::pool::CommandPoolAlloc;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::Framebuffer;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPass;
use framebuffer::RenderPassAbstract;
use framebuffer::Subpass;
use image::ImageLayout;
use image::ImageAccess;
use instance::QueueFamily;
use sync::AccessCheckError;
use sync::AccessFlagBits;
use sync::PipelineStages;
use sync::GpuFuture;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;
#[derive(Debug, Clone)]
pub enum Kind<R, F> {
Primary,
Secondary,
SecondaryRenderPass {
subpass: Subpass<R>,
framebuffer: Option<F>,
},
}
impl Kind<RenderPass<EmptySinglePassRenderPassDesc>, Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>> {
#[inline]
pub fn primary() -> Kind<RenderPass<EmptySinglePassRenderPassDesc>, Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>> {
Kind::Primary
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Flags {
None,
SimultaneousUse,
OneTimeSubmit,
}
pub struct UnsafeCommandBufferBuilder<P> where P: CommandPool {
cmd: Option<P::Builder>,
device: Arc<Device>,
flags: Flags,
secondary_cb: bool,
}
impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
pub unsafe fn new<R, F>(pool: &P, kind: Kind<R, F>, flags: Flags)
-> Result<UnsafeCommandBufferBuilder<P>, OomError>
where R: RenderPassAbstract, F: FramebufferAbstract
{
let secondary = match kind {
Kind::Primary => false,
Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
};
let cmd = try!(pool.alloc(secondary, 1)).next().expect("Requested one command buffer from \
the command pool, but got zero.");
UnsafeCommandBufferBuilder::already_allocated(cmd, kind, flags)
}
pub unsafe fn already_allocated<R, F>(alloc: P::Builder, kind: Kind<R, F>, flags: Flags)
-> Result<UnsafeCommandBufferBuilder<P>, OomError>
where R: RenderPassAbstract, F: FramebufferAbstract
{
let device = alloc.device().clone();
let vk = device.pointers();
let cmd = alloc.inner().internal_object();
let vk_flags = {
let a = match flags {
Flags::None => 0,
Flags::SimultaneousUse => vk::COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
Flags::OneTimeSubmit => vk::COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
let b = match kind {
Kind::Primary | Kind::Secondary => 0,
Kind::SecondaryRenderPass { .. } => {
vk::COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
},
};
a | b
};
let (rp, sp) = if let Kind::SecondaryRenderPass { ref subpass, .. } = kind {
(subpass.render_pass().inner().internal_object(), subpass.index())
} else {
(0, 0)
};
let framebuffer = if let Kind::SecondaryRenderPass { ref subpass, framebuffer: Some(ref framebuffer) } = kind {
FramebufferAbstract::inner(&framebuffer).internal_object()
} else {
0
};
let inheritance = vk::CommandBufferInheritanceInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
pNext: ptr::null(),
renderPass: rp,
subpass: sp,
framebuffer: framebuffer,
occlusionQueryEnable: 0, queryFlags: 0, pipelineStatistics: 0, };
let infos = vk::CommandBufferBeginInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
pNext: ptr::null(),
flags: vk_flags,
pInheritanceInfo: &inheritance,
};
try!(check_errors(vk.BeginCommandBuffer(cmd, &infos)));
Ok(UnsafeCommandBufferBuilder {
cmd: Some(alloc),
device: device.clone(),
flags: flags,
secondary_cb: match kind {
Kind::Primary => false,
Kind::Secondary | Kind::SecondaryRenderPass { .. } => true,
},
})
}
}
unsafe impl<P> DeviceOwned for UnsafeCommandBufferBuilder<P> where P: CommandPool {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl<P> CommandBufferBuilder for UnsafeCommandBufferBuilder<P> where P: CommandPool {
#[inline]
fn queue_family(&self) -> QueueFamily {
self.cmd.as_ref().unwrap().queue_family()
}
}
unsafe impl<P> VulkanObject for UnsafeCommandBufferBuilder<P> where P: CommandPool {
type Object = vk::CommandBuffer;
#[inline]
fn internal_object(&self) -> vk::CommandBuffer {
self.cmd.as_ref().unwrap().inner().internal_object()
}
}
unsafe impl<P> CommandBufferBuild for UnsafeCommandBufferBuilder<P>
where P: CommandPool
{
type Out = UnsafeCommandBuffer<P>;
type Err = OomError;
#[inline]
fn build(mut self) -> Result<Self::Out, OomError> {
unsafe {
let cmd = self.cmd.take().unwrap();
let vk = self.device.pointers();
try!(check_errors(vk.EndCommandBuffer(cmd.inner().internal_object())));
Ok(UnsafeCommandBuffer {
cmd: cmd.into_alloc(),
device: self.device.clone(),
flags: self.flags,
already_submitted: AtomicBool::new(false),
secondary_cb: self.secondary_cb
})
}
}
}
pub struct UnsafeCommandBuffer<P> where P: CommandPool {
cmd: P::Alloc,
device: Arc<Device>,
flags: Flags,
already_submitted: AtomicBool,
secondary_cb: bool
}
unsafe impl<P> CommandBuffer for UnsafeCommandBuffer<P> where P: CommandPool {
type Pool = P;
#[inline]
fn inner(&self) -> &UnsafeCommandBuffer<P> {
self
}
#[inline]
fn prepare_submit(&self, _: &GpuFuture, _: &Queue) -> Result<(), CommandBufferExecError> {
Ok(())
}
#[inline]
fn check_buffer_access(&self, buffer: &BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
Err(AccessCheckError::Unknown)
}
#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError>
{
Err(AccessCheckError::Unknown)
}
}
unsafe impl<P> DeviceOwned for UnsafeCommandBuffer<P> where P: CommandPool {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl<P> VulkanObject for UnsafeCommandBuffer<P> where P: CommandPool {
type Object = vk::CommandBuffer;
#[inline]
fn internal_object(&self) -> vk::CommandBuffer {
self.cmd.inner().internal_object()
}
}