Merge pull request #125 from tomaka/cb-pool-rework

[breaking-change] Rework command pools
This commit is contained in:
tomaka 2016-06-04 16:42:07 +02:00
commit 164389d6c4
11 changed files with 780 additions and 324 deletions

View File

@ -63,10 +63,6 @@ fn main() {
};
let cb_pool = vulkano::command_buffer::CommandBufferPool::new(&device, &queue.family());
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[Vertex]>
@ -202,7 +198,7 @@ fn main() {
let command_buffers = framebuffers.iter().map(|framebuffer| {
vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&cb_pool)
vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&device, queue.family())
.copy_buffer_to_color_image(&pixel_buffer, &texture, 0, 0 .. 1, [0, 0, 0],
[texture.dimensions().width(), texture.dimensions().height(), 1])
//.clear_color_image(&texture, [0.0, 1.0, 0.0, 1.0])

View File

@ -68,8 +68,6 @@ fn main() {
};
let cb_pool = vulkano::command_buffer::CommandBufferPool::new(&device, &queue.family());
let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(&device, images[0].dimensions(), vulkano::format::D16Unorm).unwrap();
@ -204,7 +202,7 @@ fn main() {
let command_buffers = framebuffers.iter().map(|framebuffer| {
vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&cb_pool)
vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&device, queue.family())
.draw_inline(&renderpass, &framebuffer, renderpass::ClearValues {
color: [0.0, 0.0, 1.0, 1.0],
depth: 1.0,

View File

@ -34,7 +34,6 @@ use vulkano_win::VkSurfaceBuild;
use vulkano::buffer::BufferUsage;
use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::command_buffer;
use vulkano::command_buffer::CommandBufferPool;
use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::PrimaryCommandBufferBuilder;
use vulkano::command_buffer::Submission;
@ -235,10 +234,6 @@ fn main() {
// implicitely does a lot of computation whenever you draw. In Vulkan, you have to do all this
// manually.
// We are going to create a command buffer below. Command buffers need to be allocated
// from a *command buffer pool*, so we create the pool.
let cb_pool = CommandBufferPool::new(&device, &queue.family());
// The next step is to create a *render pass*, which is an object that describes where the
// output of the graphics pipeline will go. It describes the layout of the images
// where the colors, depth and/or stencil information will be written.
@ -397,7 +392,10 @@ fn main() {
// Building a command buffer is an expensive operation (usually a few hundred
// microseconds), but it is known to be a hot path in the driver and is expected to be
// optimized.
let command_buffer = PrimaryCommandBufferBuilder::new(&cb_pool)
//
// Note that we have to pass a queue family when we create the command buffer. The command
// buffer will only be executable on that given queue family.
let command_buffer = PrimaryCommandBufferBuilder::new(&device, queue.family())
// Before we can draw, we have to *enter a render pass*. There are two methods to do
// this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
// not covered here.

View File

@ -26,9 +26,11 @@ use buffer::Buffer;
use buffer::BufferSlice;
use buffer::TypedBuffer;
use buffer::traits::AccessRange as BufferAccessRange;
use command_buffer::CommandBufferPool;
use command_buffer::DrawIndirectCommand;
use command_buffer::DynamicState;
use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolFinished;
use command_buffer::pool::StandardCommandPool;
use descriptor::descriptor_set::DescriptorSetsCollection;
use descriptor::PipelineLayout;
use device::Queue;
@ -76,9 +78,9 @@ lazy_static! {
// for this design is that we want to minimize the number of pipeline barriers. In order to know
// what must be in a pipeline barrier, we have to be ahead of the actual commands.
//
pub struct InnerCommandBufferBuilder {
pub struct InnerCommandBufferBuilder<P> where P: CommandPool {
device: Arc<Device>,
pool: Arc<CommandBufferPool>,
pool: Option<P>,
cmd: Option<vk::CommandBuffer>,
// If true, we're inside a secondary command buffer (compute or graphics).
@ -129,38 +131,17 @@ pub struct InnerCommandBufferBuilder {
current_dynamic_state: DynamicState,
}
impl InnerCommandBufferBuilder {
impl<P> InnerCommandBufferBuilder<P> where P: CommandPool {
/// Creates a new builder.
pub fn new<R>(pool: &Arc<CommandBufferPool>, secondary: bool, secondary_cont: Option<Subpass<R>>,
pub fn new<R>(pool: P, secondary: bool, secondary_cont: Option<Subpass<R>>,
secondary_cont_fb: Option<&Arc<Framebuffer<R>>>)
-> Result<InnerCommandBufferBuilder, OomError>
-> Result<InnerCommandBufferBuilder<P>, OomError>
where R: RenderPass + 'static + Send + Sync
{
let device = pool.device();
let device = pool.device().clone();
let vk = device.pointers();
let pool_obj = pool.internal_object_guard();
let cmd = unsafe {
let infos = vk::CommandBufferAllocateInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
pNext: ptr::null(),
commandPool: *pool_obj,
level: if secondary {
assert!(secondary_cont.is_some());
vk::COMMAND_BUFFER_LEVEL_SECONDARY
} else {
vk::COMMAND_BUFFER_LEVEL_PRIMARY
},
// vulkan can allocate multiple command buffers at once, hence the 1
commandBufferCount: 1,
};
let mut output = mem::uninitialized();
try!(check_errors(vk.AllocateCommandBuffers(device.internal_object(), &infos,
&mut output)));
output
};
let cmd = try!(pool.alloc(secondary, 1)).next().unwrap().internal_object();
let mut keep_alive = Vec::new();
@ -206,7 +187,7 @@ impl InnerCommandBufferBuilder {
Ok(InnerCommandBufferBuilder {
device: device.clone(),
pool: pool.clone(),
pool: Some(pool),
cmd: Some(cmd),
is_secondary: secondary,
is_secondary_graphics: secondary_cont.is_some(),
@ -230,9 +211,12 @@ impl InnerCommandBufferBuilder {
/// # Safety
///
/// Care must be taken to respect the rules about secondary command buffers.
pub unsafe fn execute_commands<'a>(mut self, cb_arc: Arc<KeepAlive>,
cb: &InnerCommandBuffer) -> InnerCommandBufferBuilder
pub unsafe fn execute_commands<'a, S>(mut self, cb_arc: Arc<KeepAlive>,
cb: &InnerCommandBuffer<S>)
-> InnerCommandBufferBuilder<P>
where S: CommandPool
{
debug_assert!(cb.is_secondary);
debug_assert!(!self.is_secondary);
debug_assert!(!self.is_secondary_graphics);
@ -351,7 +335,7 @@ impl InnerCommandBufferBuilder {
/// - Care must be taken to respect the rules about secondary command buffers.
///
pub unsafe fn update_buffer<'a, B, T, Bt>(mut self, buffer: B, data: &T)
-> InnerCommandBufferBuilder
-> InnerCommandBufferBuilder<P>
where B: Into<BufferSlice<'a, T, Bt>>, Bt: Buffer + 'static, T: Clone + Send + Sync + 'static
{
debug_assert!(self.render_pass_staging_commands.is_empty());
@ -402,12 +386,12 @@ impl InnerCommandBufferBuilder {
/// - Care must be taken to respect the rules about secondary command buffers.
///
pub unsafe fn fill_buffer<B>(mut self, buffer: &Arc<B>, offset: usize,
size: usize, data: u32) -> InnerCommandBufferBuilder
size: usize, data: u32) -> InnerCommandBufferBuilder<P>
where B: Buffer + 'static
{
debug_assert!(self.render_pass_staging_commands.is_empty());
assert!(self.pool.queue_family().supports_transfers());
assert!(self.pool.as_ref().unwrap().queue_family().supports_transfers());
assert!(offset + size <= buffer.size());
assert!(offset % 4 == 0);
assert!(size % 4 == 0);
@ -448,7 +432,7 @@ impl InnerCommandBufferBuilder {
// TODO: doesn't support slices
pub unsafe fn copy_buffer<T: ?Sized + 'static, Bs, Bd>(mut self, source: &Arc<Bs>,
destination: &Arc<Bd>)
-> InnerCommandBufferBuilder
-> InnerCommandBufferBuilder<P>
where Bs: TypedBuffer<Content = T> + 'static, Bd: TypedBuffer<Content = T> + 'static
{
debug_assert!(self.render_pass_staging_commands.is_empty());
@ -492,7 +476,7 @@ impl InnerCommandBufferBuilder {
/// - Care must be taken to respect the rules about secondary command buffers.
///
pub unsafe fn clear_color_image<'a, I, V>(mut self, image: &Arc<I>, color: V)
-> InnerCommandBufferBuilder
-> InnerCommandBufferBuilder<P>
where I: ImageClearValue<V> + 'static // FIXME: should accept uint and int images too
{
debug_assert!(self.render_pass_staging_commands.is_empty());
@ -536,11 +520,11 @@ impl InnerCommandBufferBuilder {
///
/// - Care must be taken to respect the rules about secondary command buffers.
///
pub unsafe fn copy_buffer_to_color_image<'a, P, S, Sb, Img>(mut self, source: S, image: &Arc<Img>,
pub unsafe fn copy_buffer_to_color_image<'a, Pi, S, Sb, Img>(mut self, source: S, image: &Arc<Img>,
mip_level: u32, array_layers_range: Range<u32>,
offset: [u32; 3], extent: [u32; 3])
-> InnerCommandBufferBuilder
where S: Into<BufferSlice<'a, [P], Sb>>, Img: ImageContent<P> + Image + 'static,
-> InnerCommandBufferBuilder<P>
where S: Into<BufferSlice<'a, [Pi], Sb>>, Img: ImageContent<Pi> + Image + 'static,
Sb: Buffer + 'static
{
// FIXME: check the parameters
@ -605,11 +589,11 @@ impl InnerCommandBufferBuilder {
///
/// - Care must be taken to respect the rules about secondary command buffers.
///
pub unsafe fn copy_color_image_to_buffer<'a, P, S, Sb, Img>(mut self, dest: S, image: &Arc<Img>,
pub unsafe fn copy_color_image_to_buffer<'a, Pi, S, Sb, Img>(mut self, dest: S, image: &Arc<Img>,
mip_level: u32, array_layers_range: Range<u32>,
offset: [u32; 3], extent: [u32; 3])
-> InnerCommandBufferBuilder
where S: Into<BufferSlice<'a, [P], Sb>>, Img: ImageContent<P> + Image + 'static,
-> InnerCommandBufferBuilder<P>
where S: Into<BufferSlice<'a, [Pi], Sb>>, Img: ImageContent<Pi> + Image + 'static,
Sb: Buffer + 'static
{
// FIXME: check the parameters
@ -670,7 +654,7 @@ impl InnerCommandBufferBuilder {
source_array_layers: Range<u32>, src_coords: [Range<i32>; 3],
destination: &Arc<Di>, dest_mip_level: u32,
dest_array_layers: Range<u32>, dest_coords: [Range<i32>; 3])
-> InnerCommandBufferBuilder
-> InnerCommandBufferBuilder<P>
where Si: Image + 'static, Di: Image + 'static
{
// FIXME: check the parameters
@ -745,7 +729,7 @@ impl InnerCommandBufferBuilder {
}
pub unsafe fn dispatch<Pl, L, Pc>(mut self, pipeline: &Arc<ComputePipeline<Pl>>, sets: L,
dimensions: [u32; 3], push_constants: &Pc) -> InnerCommandBufferBuilder
dimensions: [u32; 3], push_constants: &Pc) -> InnerCommandBufferBuilder<P>
where L: 'static + DescriptorSetsCollection + Send + Sync,
Pl: 'static + PipelineLayout + Send + Sync,
Pc: 'static + Clone + Send + Sync
@ -765,7 +749,7 @@ impl InnerCommandBufferBuilder {
// FIXME: push constants
pub unsafe fn draw<V, Pv, Pl, L, Rp, Pc>(mut self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, dynamic: &DynamicState,
sets: L, push_constants: &Pc) -> InnerCommandBufferBuilder
sets: L, push_constants: &Pc) -> InnerCommandBufferBuilder<P>
where Pv: 'static + VertexSource<V>, L: DescriptorSetsCollection + Send + Sync,
Pl: 'static + PipelineLayout + Send + Sync, Rp: 'static + Send + Sync,
Pc: 'static + Clone + Send + Sync
@ -807,7 +791,7 @@ impl InnerCommandBufferBuilder {
// FIXME: push constants
pub unsafe fn draw_indexed<'a, V, Pv, Pl, Rp, L, I, Ib, Ibb, Pc>(mut self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, indices: Ib, dynamic: &DynamicState,
sets: L, push_constants: &Pc) -> InnerCommandBufferBuilder
sets: L, push_constants: &Pc) -> InnerCommandBufferBuilder<P>
where L: DescriptorSetsCollection + Send + Sync,
Pv: 'static + VertexSource<V>,
Pl: 'static + PipelineLayout + Send + Sync, Rp: 'static + Send + Sync,
@ -865,7 +849,7 @@ impl InnerCommandBufferBuilder {
// FIXME: push constants
pub unsafe fn draw_indirect<I, V, Pv, Pl, L, Rp, Pc>(mut self, buffer: &Arc<I>, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, dynamic: &DynamicState,
sets: L, push_constants: &Pc) -> InnerCommandBufferBuilder
sets: L, push_constants: &Pc) -> InnerCommandBufferBuilder<P>
where Pv: 'static + VertexSource<V>, L: DescriptorSetsCollection + Send + Sync,
Pl: 'static + PipelineLayout + Send + Sync, Rp: 'static + Send + Sync, Pc: 'static + Clone + Send + Sync,
I: 'static + TypedBuffer<Content = [DrawIndirectCommand]>
@ -1088,7 +1072,7 @@ impl InnerCommandBufferBuilder {
pub unsafe fn begin_renderpass<R, F>(mut self, render_pass: &Arc<R>,
framebuffer: &Arc<Framebuffer<F>>,
secondary_cmd_buffers: bool,
clear_values: &[ClearValue]) -> InnerCommandBufferBuilder
clear_values: &[ClearValue]) -> InnerCommandBufferBuilder<P>
where R: RenderPass + 'static, F: RenderPass + 'static
{
debug_assert!(self.render_pass_staging_commands.is_empty());
@ -1178,7 +1162,7 @@ impl InnerCommandBufferBuilder {
}
#[inline]
pub unsafe fn next_subpass(mut self, secondary_cmd_buffers: bool) -> InnerCommandBufferBuilder {
pub unsafe fn next_subpass(mut self, secondary_cmd_buffers: bool) -> InnerCommandBufferBuilder<P> {
debug_assert!(!self.render_pass_staging_commands.is_empty());
let content = if secondary_cmd_buffers {
@ -1201,7 +1185,7 @@ impl InnerCommandBufferBuilder {
/// Assumes that you're inside a render pass and that all subpasses have been processed.
///
#[inline]
pub unsafe fn end_renderpass(mut self) -> InnerCommandBufferBuilder {
pub unsafe fn end_renderpass(mut self) -> InnerCommandBufferBuilder<P> {
debug_assert!(!self.render_pass_staging_commands.is_empty());
self.flush_render_pass();
self.staging_commands.push(Box::new(move |vk, cmd| {
@ -1624,7 +1608,7 @@ impl InnerCommandBufferBuilder {
}
/// Finishes building the command buffer.
pub fn build(mut self) -> Result<InnerCommandBuffer, OomError> {
pub fn build(mut self) -> Result<InnerCommandBuffer<P>, OomError> {
unsafe {
self.flush_render_pass();
self.flush(true);
@ -1673,7 +1657,7 @@ impl InnerCommandBufferBuilder {
debug_assert!(self.staging_required_image_accesses.is_empty());
let vk = self.device.pointers();
let _ = self.pool.internal_object_guard(); // the pool needs to be synchronized
let _pool_lock = self.pool.as_ref().unwrap().lock(); // the pool needs to be synchronized
let cmd = self.cmd.take().unwrap();
// Ending the commands recording.
@ -1681,8 +1665,9 @@ impl InnerCommandBufferBuilder {
Ok(InnerCommandBuffer {
device: self.device.clone(),
pool: self.pool.clone(),
pool: self.pool.take().unwrap().finish(),
cmd: cmd,
is_secondary: self.is_secondary,
buffers_state: self.buffers_state.clone(), // TODO: meh
images_state: self.images_state.clone(), // TODO: meh
extern_buffers_sync: {
@ -1737,7 +1722,7 @@ impl InnerCommandBufferBuilder {
}
}
impl Drop for InnerCommandBufferBuilder {
impl<P> Drop for InnerCommandBufferBuilder<P> where P: CommandPool {
#[inline]
fn drop(&mut self) {
if let Some(cmd) = self.cmd {
@ -1745,18 +1730,18 @@ impl Drop for InnerCommandBufferBuilder {
let vk = self.device.pointers();
vk.EndCommandBuffer(cmd); // TODO: really needed?
let pool = self.pool.internal_object_guard();
vk.FreeCommandBuffers(self.device.internal_object(), *pool, 1, &cmd);
self.pool.as_ref().unwrap().free(self.is_secondary, Some(cmd.into()).into_iter());
}
}
}
}
/// Actual implementation of all command buffers.
pub struct InnerCommandBuffer {
pub struct InnerCommandBuffer<P = Arc<StandardCommandPool>> where P: CommandPool {
device: Arc<Device>,
pool: Arc<CommandBufferPool>,
pool: P::Finished,
cmd: vk::CommandBuffer,
is_secondary: bool,
buffers_state: HashMap<(BufferKey, usize), InternalBufferBlockAccess, BuildHasherDefault<FnvHasher>>,
images_state: HashMap<(ImageKey, (u32, u32)), InternalImageBlockAccess, BuildHasherDefault<FnvHasher>>,
extern_buffers_sync: SmallVec<[(Arc<Buffer>, SmallVec<[BufferAccessRange; 4]>); 32]>,
@ -1773,9 +1758,12 @@ pub struct InnerCommandBuffer {
/// - Panicks if the queue doesn't belong to the device this command buffer was created with.
/// - Panicks if the queue doesn't belong to the family the pool was created with.
///
pub fn submit(me: &InnerCommandBuffer, me_arc: Arc<KeepAlive>,
queue: &Arc<Queue>) -> Result<Arc<Submission>, OomError> // TODO: wrong error type
pub fn submit<P>(me: &InnerCommandBuffer<P>, me_arc: Arc<KeepAlive>,
queue: &Arc<Queue>) -> Result<Arc<Submission>, OomError> // TODO: wrong error type
where P: CommandPool
{
debug_assert!(!me.is_secondary);
// TODO: see comment of GLOBAL_MUTEX
let _global_lock = GLOBAL_MUTEX.lock().unwrap();
@ -1891,13 +1879,13 @@ pub fn submit(me: &InnerCommandBuffer, me_arc: Arc<KeepAlive>,
}
for transition in result.before_transitions {
let cb = transition_cb(&me.pool, resource.clone(), transition.block, transition.from, transition.to).unwrap();
let cb = transition_cb(Device::standard_command_pool(&me.device, me.pool.queue_family()), resource.clone(), transition.block, transition.from, transition.to).unwrap();
before_command_buffers.push(cb.cmd);
submission.keep_alive_cb.lock().unwrap().push(Arc::new(cb));
}
for transition in result.after_transitions {
let cb = transition_cb(&me.pool, resource.clone(), transition.block, transition.from, transition.to).unwrap();
let cb = transition_cb(Device::standard_command_pool(&me.device, me.pool.queue_family()), resource.clone(), transition.block, transition.from, transition.to).unwrap();
after_command_buffers.push(cb.cmd);
submission.keep_alive_cb.lock().unwrap().push(Arc::new(cb));
}
@ -2036,13 +2024,11 @@ pub fn submit(me: &InnerCommandBuffer, me_arc: Arc<KeepAlive>,
Ok(submission)
}
impl Drop for InnerCommandBuffer {
impl<P> Drop for InnerCommandBuffer<P> where P: CommandPool {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
let pool = self.pool.internal_object_guard();
vk.FreeCommandBuffers(self.device.internal_object(), *pool, 1, &self.cmd);
self.pool.free(self.is_secondary, Some(self.cmd.into()).into_iter());
}
}
}
@ -2213,28 +2199,15 @@ struct InternalImageBlockAccess {
/// Builds an `InnerCommandBuffer` whose only purpose is to transition an image between two
/// layouts.
fn transition_cb(pool: &Arc<CommandBufferPool>, image: Arc<Image>, block: (u32, u32),
old_layout: ImageLayout, new_layout: ImageLayout)
-> Result<InnerCommandBuffer, OomError>
fn transition_cb<P>(pool: P, image: Arc<Image>, block: (u32, u32),
old_layout: ImageLayout, new_layout: ImageLayout)
-> Result<InnerCommandBuffer<P>, OomError>
where P: CommandPool
{
let device = pool.device();
let device = pool.device().clone();
let vk = device.pointers();
let pool_obj = pool.internal_object_guard();
let cmd = unsafe {
let infos = vk::CommandBufferAllocateInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
pNext: ptr::null(),
commandPool: *pool_obj,
level: vk::COMMAND_BUFFER_LEVEL_PRIMARY,
commandBufferCount: 1,
};
let mut output = mem::uninitialized();
try!(check_errors(vk.AllocateCommandBuffers(device.internal_object(), &infos,
&mut output)));
output
};
let cmd = try!(pool.alloc(false, 1)).next().unwrap().internal_object();
unsafe {
let infos = vk::CommandBufferBeginInfo {
@ -2287,8 +2260,9 @@ fn transition_cb(pool: &Arc<CommandBufferPool>, image: Arc<Image>, block: (u32,
Ok(InnerCommandBuffer {
device: device.clone(),
pool: pool.clone(),
pool: pool.finish(),
cmd: cmd,
is_secondary: false,
buffers_state: HashMap::with_hasher(BuildHasherDefault::<FnvHasher>::default()),
images_state: HashMap::with_hasher(BuildHasherDefault::<FnvHasher>::default()),
extern_buffers_sync: SmallVec::new(),

View File

@ -52,7 +52,6 @@ pub use self::outer::SecondaryGraphicsCommandBufferBuilder;
pub use self::outer::SecondaryGraphicsCommandBuffer;
pub use self::outer::SecondaryComputeCommandBufferBuilder;
pub use self::outer::SecondaryComputeCommandBuffer;
pub use self::pool::CommandBufferPool;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -75,4 +74,4 @@ pub struct DrawIndexedIndirectCommand {
mod inner;
mod outer;
mod pool;
pub mod pool;

View File

@ -14,14 +14,16 @@ use smallvec::SmallVec;
use buffer::Buffer;
use buffer::BufferSlice;
use buffer::TypedBuffer;
use command_buffer::CommandBufferPool;
use command_buffer::DrawIndirectCommand;
use command_buffer::inner::InnerCommandBufferBuilder;
use command_buffer::inner::InnerCommandBuffer;
use command_buffer::inner::Submission;
use command_buffer::inner::submit as inner_submit;
use command_buffer::pool::CommandPool;
use command_buffer::pool::StandardCommandPool;
use descriptor::descriptor_set::DescriptorSetsCollection;
use descriptor::PipelineLayout;
use device::Device;
use device::Queue;
use framebuffer::Framebuffer;
use framebuffer::UnsafeRenderPass;
@ -33,6 +35,7 @@ use framebuffer::Subpass;
use image::traits::Image;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use instance::QueueFamily;
use pipeline::ComputePipeline;
use pipeline::GraphicsPipeline;
use pipeline::input_assembly::Index;
@ -55,31 +58,32 @@ use OomError;
///
/// ```
///
pub struct PrimaryCommandBufferBuilder {
inner: InnerCommandBufferBuilder,
pub struct PrimaryCommandBufferBuilder<P = Arc<StandardCommandPool>> where P: CommandPool {
inner: InnerCommandBufferBuilder<P>,
}
impl PrimaryCommandBufferBuilder {
/// See the docs of new().
#[inline]
pub fn raw(pool: &Arc<CommandBufferPool>)
-> Result<PrimaryCommandBufferBuilder, OomError>
{
let inner = try!(InnerCommandBufferBuilder::new::<UnsafeRenderPass>(pool, false, None, None));
Ok(PrimaryCommandBufferBuilder { inner: inner })
}
impl PrimaryCommandBufferBuilder<Arc<StandardCommandPool>> {
/// Builds a new primary command buffer and start recording commands in it.
///
/// # Panic
///
/// - Panicks if the device or host ran out of memory.
/// - Panicks if the device and queue family do not belong to the same physical device.
///
#[inline]
pub fn new(pool: &Arc<CommandBufferPool>)
-> PrimaryCommandBufferBuilder
pub fn new(device: &Arc<Device>, queue_family: QueueFamily)
-> PrimaryCommandBufferBuilder<Arc<StandardCommandPool>>
{
PrimaryCommandBufferBuilder::raw(pool).unwrap()
PrimaryCommandBufferBuilder::raw(Device::standard_command_pool(device, queue_family)).unwrap()
}
}
impl<P> PrimaryCommandBufferBuilder<P> where P: CommandPool {
/// See the docs of new().
#[inline]
pub fn raw(pool: P) -> Result<PrimaryCommandBufferBuilder<P>, OomError> {
let inner = try!(InnerCommandBufferBuilder::new::<UnsafeRenderPass>(pool, false, None, None));
Ok(PrimaryCommandBufferBuilder { inner: inner })
}
/// Writes data to a buffer.
@ -97,7 +101,7 @@ impl PrimaryCommandBufferBuilder {
/// - Panicks if the queue family doesn't support transfer operations.
///
#[inline]
pub fn update_buffer<'a, B, T, Bb>(self, buffer: B, data: &T) -> PrimaryCommandBufferBuilder
pub fn update_buffer<'a, B, T, Bb>(self, buffer: B, data: &T) -> PrimaryCommandBufferBuilder<P>
where B: Into<BufferSlice<'a, T, Bb>>, Bb: Buffer + 'static, T: Clone + 'static + Send + Sync
{
unsafe {
@ -124,7 +128,7 @@ impl PrimaryCommandBufferBuilder {
/// - Type safety is not enforced by the API.
///
pub unsafe fn fill_buffer<B>(self, buffer: &Arc<B>, offset: usize,
size: usize, data: u32) -> PrimaryCommandBufferBuilder
size: usize, data: u32) -> PrimaryCommandBufferBuilder<P>
where B: Buffer + 'static
{
PrimaryCommandBufferBuilder {
@ -133,7 +137,7 @@ impl PrimaryCommandBufferBuilder {
}
pub fn copy_buffer<T: ?Sized + 'static, Bs, Bd>(self, source: &Arc<Bs>, destination: &Arc<Bd>)
-> PrimaryCommandBufferBuilder
-> PrimaryCommandBufferBuilder<P>
where Bs: TypedBuffer<Content = T> + 'static, Bd: TypedBuffer<Content = T> + 'static
{
unsafe {
@ -143,11 +147,11 @@ impl PrimaryCommandBufferBuilder {
}
}
pub fn copy_buffer_to_color_image<'a, P, S, Img, Sb>(self, source: S, destination: &Arc<Img>, mip_level: u32, array_layers_range: Range<u32>,
pub fn copy_buffer_to_color_image<'a, Pi, S, Img, Sb>(self, source: S, destination: &Arc<Img>, mip_level: u32, array_layers_range: Range<u32>,
offset: [u32; 3], extent: [u32; 3])
-> PrimaryCommandBufferBuilder
where S: Into<BufferSlice<'a, [P], Sb>>, Sb: Buffer + 'static,
Img: ImageContent<P> + 'static
-> PrimaryCommandBufferBuilder<P>
where S: Into<BufferSlice<'a, [Pi], Sb>>, Sb: Buffer + 'static,
Img: ImageContent<Pi> + 'static
{
unsafe {
PrimaryCommandBufferBuilder {
@ -157,11 +161,11 @@ impl PrimaryCommandBufferBuilder {
}
}
pub fn copy_color_image_to_buffer<'a, P, S, Img, Sb>(self, dest: S, destination: &Arc<Img>, mip_level: u32, array_layers_range: Range<u32>,
pub fn copy_color_image_to_buffer<'a, Pi, S, Img, Sb>(self, dest: S, destination: &Arc<Img>, mip_level: u32, array_layers_range: Range<u32>,
offset: [u32; 3], extent: [u32; 3])
-> PrimaryCommandBufferBuilder
where S: Into<BufferSlice<'a, [P], Sb>>, Sb: Buffer + 'static,
Img: ImageContent<P> + 'static
-> PrimaryCommandBufferBuilder<P>
where S: Into<BufferSlice<'a, [Pi], Sb>>, Sb: Buffer + 'static,
Img: ImageContent<Pi> + 'static
{
unsafe {
PrimaryCommandBufferBuilder {
@ -175,7 +179,7 @@ impl PrimaryCommandBufferBuilder {
source_array_layers: Range<u32>, src_coords: [Range<i32>; 3],
destination: &Arc<Di>, dest_mip_level: u32,
dest_array_layers: Range<u32>, dest_coords: [Range<i32>; 3])
-> PrimaryCommandBufferBuilder
-> PrimaryCommandBufferBuilder<P>
where Si: Image + 'static, Di: Image + 'static
{
unsafe {
@ -189,7 +193,7 @@ impl PrimaryCommandBufferBuilder {
///
/// Note that compressed formats are not supported.
pub fn clear_color_image<'a, I, V>(self, image: &Arc<I>, color: V)
-> PrimaryCommandBufferBuilder
-> PrimaryCommandBufferBuilder<P>
where I: ImageClearValue<V> + 'static
{
unsafe {
@ -201,8 +205,10 @@ impl PrimaryCommandBufferBuilder {
/// Executes secondary compute command buffers within this primary command buffer.
#[inline]
pub fn execute_commands(self, cb: &Arc<SecondaryComputeCommandBuffer>)
-> PrimaryCommandBufferBuilder
pub fn execute_commands<S>(self, cb: &Arc<SecondaryComputeCommandBuffer<S>>)
-> PrimaryCommandBufferBuilder<P>
where S: CommandPool + 'static,
S::Finished: Send + Sync + 'static,
{
unsafe {
PrimaryCommandBufferBuilder {
@ -214,7 +220,7 @@ impl PrimaryCommandBufferBuilder {
/// Executes a compute pipeline.
#[inline]
pub fn dispatch<Pl, L, Pc>(self, pipeline: &Arc<ComputePipeline<Pl>>, sets: L,
dimensions: [u32; 3], push_constants: &Pc) -> PrimaryCommandBufferBuilder
dimensions: [u32; 3], push_constants: &Pc) -> PrimaryCommandBufferBuilder<P>
where L: 'static + DescriptorSetsCollection + Send + Sync,
Pl: 'static + PipelineLayout + Send + Sync,
Pc: 'static + Clone + Send + Sync
@ -239,7 +245,7 @@ impl PrimaryCommandBufferBuilder {
#[inline]
pub fn draw_inline<R, F, C>(self, renderpass: &Arc<R>,
framebuffer: &Arc<Framebuffer<F>>, clear_values: C)
-> PrimaryCommandBufferBuilderInlineDraw
-> PrimaryCommandBufferBuilderInlineDraw<P>
where F: RenderPass + RenderPassDesc + RenderPassClearValues<C> + 'static,
R: RenderPass + RenderPassDesc + 'static
{
@ -273,7 +279,7 @@ impl PrimaryCommandBufferBuilder {
#[inline]
pub fn draw_secondary<R, F, C>(self, renderpass: &Arc<R>,
framebuffer: &Arc<Framebuffer<F>>, clear_values: C)
-> PrimaryCommandBufferBuilderSecondaryDraw
-> PrimaryCommandBufferBuilderSecondaryDraw<P>
where F: RenderPass + RenderPassDesc + RenderPassClearValues<C> + 'static,
R: RenderPass + RenderPassDesc + 'static
{
@ -295,7 +301,7 @@ impl PrimaryCommandBufferBuilder {
/// See the docs of build().
#[inline]
pub fn build_raw(self) -> Result<PrimaryCommandBuffer, OomError> {
pub fn build_raw(self) -> Result<PrimaryCommandBuffer<P>, OomError> {
let inner = try!(self.inner.build());
Ok(PrimaryCommandBuffer { inner: inner })
}
@ -307,24 +313,26 @@ impl PrimaryCommandBufferBuilder {
/// - Panicks if the device or host ran out of memory.
///
#[inline]
pub fn build(self) -> Arc<PrimaryCommandBuffer> {
pub fn build(self) -> Arc<PrimaryCommandBuffer<P>> {
Arc::new(self.build_raw().unwrap())
}
}
/// Object that you obtain when calling `draw_inline` or `next_subpass_inline`.
pub struct PrimaryCommandBufferBuilderInlineDraw {
inner: InnerCommandBufferBuilder,
pub struct PrimaryCommandBufferBuilderInlineDraw<P = Arc<StandardCommandPool>>
where P: CommandPool
{
inner: InnerCommandBufferBuilder<P>,
current_subpass: u32,
num_subpasses: u32,
}
impl PrimaryCommandBufferBuilderInlineDraw {
impl<P> PrimaryCommandBufferBuilderInlineDraw<P> where P: CommandPool {
/// Calls `vkCmdDraw`.
// FIXME: push constants
pub fn draw<V, L, Pv, Pl, Rp, Pc>(self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, dynamic: &DynamicState, sets: L, push_constants: &Pc)
-> PrimaryCommandBufferBuilderInlineDraw
-> PrimaryCommandBufferBuilderInlineDraw<P>
where Pv: VertexSource<V> + 'static, Pl: PipelineLayout + 'static + Send + Sync, Rp: 'static + Send + Sync,
L: DescriptorSetsCollection + Send + Sync, Pc: 'static + Clone + Send + Sync
{
@ -342,7 +350,7 @@ impl PrimaryCommandBufferBuilderInlineDraw {
/// Calls `vkCmdDrawIndexed`.
pub fn draw_indexed<'a, V, L, Pv, Pl, Rp, I, Ib, Ibb, Pc>(self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, indices: Ib, dynamic: &DynamicState,
sets: L, push_constants: &Pc) -> PrimaryCommandBufferBuilderInlineDraw
sets: L, push_constants: &Pc) -> PrimaryCommandBufferBuilderInlineDraw<P>
where Pv: 'static + VertexSource<V> + Send + Sync, Pl: 'static + PipelineLayout + Send + Sync, Rp: 'static + Send + Sync,
Ib: Into<BufferSlice<'a, [I], Ibb>>, I: 'static + Index, Ibb: Buffer + 'static + Send + Sync,
L: DescriptorSetsCollection + Send + Sync, Pc: 'static + Clone + Send + Sync
@ -367,7 +375,7 @@ impl PrimaryCommandBufferBuilderInlineDraw {
/// - Panicks if no more subpasses remain.
///
#[inline]
pub fn next_subpass_inline(self) -> PrimaryCommandBufferBuilderInlineDraw {
pub fn next_subpass_inline(self) -> PrimaryCommandBufferBuilderInlineDraw<P> {
assert!(self.current_subpass + 1 < self.num_subpasses);
unsafe {
@ -390,7 +398,7 @@ impl PrimaryCommandBufferBuilderInlineDraw {
/// - Panicks if no more subpasses remain.
///
#[inline]
pub fn next_subpass_secondary(self) -> PrimaryCommandBufferBuilderSecondaryDraw {
pub fn next_subpass_secondary(self) -> PrimaryCommandBufferBuilderSecondaryDraw<P> {
assert!(self.current_subpass + 1 < self.num_subpasses);
unsafe {
@ -411,7 +419,7 @@ impl PrimaryCommandBufferBuilderInlineDraw {
/// - Panicks if not at the last subpass.
///
#[inline]
pub fn draw_end(self) -> PrimaryCommandBufferBuilder {
pub fn draw_end(self) -> PrimaryCommandBufferBuilder<P> {
assert!(self.current_subpass + 1 == self.num_subpasses);
unsafe {
@ -424,13 +432,15 @@ impl PrimaryCommandBufferBuilderInlineDraw {
}
/// Object that you obtain when calling `draw_secondary` or `next_subpass_secondary`.
pub struct PrimaryCommandBufferBuilderSecondaryDraw {
inner: InnerCommandBufferBuilder,
pub struct PrimaryCommandBufferBuilderSecondaryDraw<P = Arc<StandardCommandPool>>
where P: CommandPool
{
inner: InnerCommandBufferBuilder<P>,
current_subpass: u32,
num_subpasses: u32,
}
impl PrimaryCommandBufferBuilderSecondaryDraw {
impl<P> PrimaryCommandBufferBuilderSecondaryDraw<P> where P: CommandPool {
/// Switches to the next subpass of the current renderpass.
///
/// This function is similar to `draw_inline` on the builder.
@ -440,7 +450,7 @@ impl PrimaryCommandBufferBuilderSecondaryDraw {
/// - Panicks if no more subpasses remain.
///
#[inline]
pub fn next_subpass_inline(self) -> PrimaryCommandBufferBuilderInlineDraw {
pub fn next_subpass_inline(self) -> PrimaryCommandBufferBuilderInlineDraw<P> {
assert!(self.current_subpass + 1 < self.num_subpasses);
unsafe {
@ -463,7 +473,7 @@ impl PrimaryCommandBufferBuilderSecondaryDraw {
/// - Panicks if no more subpasses remain.
///
#[inline]
pub fn next_subpass_secondary(self) -> PrimaryCommandBufferBuilderSecondaryDraw {
pub fn next_subpass_secondary(self) -> PrimaryCommandBufferBuilderSecondaryDraw<P> {
assert!(self.current_subpass + 1 < self.num_subpasses);
unsafe {
@ -484,9 +494,11 @@ impl PrimaryCommandBufferBuilderSecondaryDraw {
/// - Panicks if the secondary command buffers wasn't created with a compatible
/// renderpass or is using the wrong subpass.
#[inline]
pub fn execute_commands<R>(mut self, cb: &Arc<SecondaryGraphicsCommandBuffer<R>>)
-> PrimaryCommandBufferBuilderSecondaryDraw
where R: 'static + Send + Sync
pub fn execute_commands<R, Ps>(mut self, cb: &Arc<SecondaryGraphicsCommandBuffer<R, Ps>>)
-> PrimaryCommandBufferBuilderSecondaryDraw<P>
where R: 'static + Send + Sync,
Ps: CommandPool + 'static,
Ps::Finished: Send + Sync + 'static,
{
// FIXME: check renderpass, subpass and framebuffer
@ -503,7 +515,7 @@ impl PrimaryCommandBufferBuilderSecondaryDraw {
/// - Panicks if not at the last subpass.
///
#[inline]
pub fn draw_end(self) -> PrimaryCommandBufferBuilder {
pub fn draw_end(self) -> PrimaryCommandBufferBuilder<P> {
assert!(self.current_subpass + 1 == self.num_subpasses);
unsafe {
@ -518,8 +530,8 @@ impl PrimaryCommandBufferBuilderSecondaryDraw {
/// Represents a collection of commands to be executed by the GPU.
///
/// A primary command buffer can contain any command.
pub struct PrimaryCommandBuffer {
inner: InnerCommandBuffer,
pub struct PrimaryCommandBuffer<P = Arc<StandardCommandPool>> where P: CommandPool {
inner: InnerCommandBuffer<P>,
}
/// Submits the command buffer to a queue so that it is executed.
@ -532,28 +544,55 @@ pub struct PrimaryCommandBuffer {
/// - Panicks if the queue doesn't belong to the family the pool was created with.
///
#[inline]
pub fn submit(cmd: &Arc<PrimaryCommandBuffer>, queue: &Arc<Queue>)
-> Result<Arc<Submission>, OomError>
pub fn submit<P>(cmd: &Arc<PrimaryCommandBuffer<P>>, queue: &Arc<Queue>)
-> Result<Arc<Submission>, OomError>
where P: CommandPool + 'static,
P::Finished: Send + Sync + 'static
{ // TODO: wrong error type
inner_submit(&cmd.inner, cmd.clone() as Arc<_>, queue)
}
/// A prototype of a secondary compute command buffer.
pub struct SecondaryGraphicsCommandBufferBuilder<R> {
inner: InnerCommandBufferBuilder,
pub struct SecondaryGraphicsCommandBufferBuilder<R, P = Arc<StandardCommandPool>>
where P: CommandPool
{
inner: InnerCommandBufferBuilder<P>,
render_pass: Arc<R>,
render_pass_subpass: u32,
framebuffer: Option<Arc<Framebuffer<R>>>,
}
impl<R> SecondaryGraphicsCommandBufferBuilder<R>
impl<R> SecondaryGraphicsCommandBufferBuilder<R, Arc<StandardCommandPool>>
where R: RenderPass + RenderPassDesc + 'static
{
/// Builds a new secondary command buffer and start recording commands in it.
///
/// The `framebuffer` parameter is optional and can be used as an optimisation.
///
/// # Panic
///
/// - Panicks if the device or host ran out of memory.
/// - Panicks if the device and queue family do not belong to the same physical device.
///
#[inline]
pub fn new(device: &Arc<Device>, queue_family: QueueFamily, subpass: Subpass<R>,
framebuffer: Option<&Arc<Framebuffer<R>>>)
-> SecondaryGraphicsCommandBufferBuilder<R, Arc<StandardCommandPool>>
where R: 'static + Send + Sync
{
SecondaryGraphicsCommandBufferBuilder::raw(Device::standard_command_pool(device,
queue_family), subpass, framebuffer).unwrap()
}
}
impl<R, P> SecondaryGraphicsCommandBufferBuilder<R, P>
where R: RenderPass + RenderPassDesc + 'static,
P: CommandPool
{
/// See the docs of new().
#[inline]
pub fn raw(pool: &Arc<CommandBufferPool>, subpass: Subpass<R>,
framebuffer: Option<&Arc<Framebuffer<R>>>)
-> Result<SecondaryGraphicsCommandBufferBuilder<R>, OomError>
pub fn raw(pool: P, subpass: Subpass<R>, framebuffer: Option<&Arc<Framebuffer<R>>>)
-> Result<SecondaryGraphicsCommandBufferBuilder<R, P>, OomError>
where R: 'static + Send + Sync
{
let inner = try!(InnerCommandBufferBuilder::new(pool, true, Some(subpass), framebuffer.clone()));
@ -565,28 +604,11 @@ impl<R> SecondaryGraphicsCommandBufferBuilder<R>
})
}
/// Builds a new secondary command buffer and start recording commands in it.
///
/// The `framebuffer` parameter is optional and can be used as an optimisation.
///
/// # Panic
///
/// - Panicks if the device or host ran out of memory.
///
#[inline]
pub fn new(pool: &Arc<CommandBufferPool>, subpass: Subpass<R>,
framebuffer: Option<&Arc<Framebuffer<R>>>)
-> SecondaryGraphicsCommandBufferBuilder<R>
where R: 'static + Send + Sync
{
SecondaryGraphicsCommandBufferBuilder::raw(pool, subpass, framebuffer).unwrap()
}
/// Calls `vkCmdDraw`.
// FIXME: push constants
pub fn draw<V, L, Pv, Pl, Rp, Pc>(self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, dynamic: &DynamicState, sets: L, push_constants: &Pc)
-> SecondaryGraphicsCommandBufferBuilder<R>
-> SecondaryGraphicsCommandBufferBuilder<R, P>
where Pv: VertexSource<V> + 'static, Pl: PipelineLayout + 'static + Send + Sync,
Rp: RenderPass + RenderPassDesc + 'static + Send + Sync, L: DescriptorSetsCollection + Send + Sync,
R: RenderPassCompatible<Rp>, Pc: 'static + Clone + Send + Sync
@ -607,7 +629,7 @@ impl<R> SecondaryGraphicsCommandBufferBuilder<R>
/// Calls `vkCmdDrawIndexed`.
pub fn draw_indexed<'a, V, L, Pv, Pl, Rp, I, Ib, Ibb, Pc>(self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, indices: Ib, dynamic: &DynamicState,
sets: L, push_constants: &Pc) -> SecondaryGraphicsCommandBufferBuilder<R>
sets: L, push_constants: &Pc) -> SecondaryGraphicsCommandBufferBuilder<R, P>
where Pv: 'static + VertexSource<V>, Pl: 'static + PipelineLayout + Send + Sync,
Rp: RenderPass + RenderPassDesc + 'static + Send + Sync,
Ib: Into<BufferSlice<'a, [I], Ibb>>, I: 'static + Index, Ibb: Buffer + 'static,
@ -629,7 +651,7 @@ impl<R> SecondaryGraphicsCommandBufferBuilder<R>
/// Calls `vkCmdDrawIndirect`.
pub fn draw_indirect<I, V, Pv, Pl, L, Rp, Pc>(self, buffer: &Arc<I>, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Rp>>,
vertices: V, dynamic: &DynamicState,
sets: L, push_constants: &Pc) -> SecondaryGraphicsCommandBufferBuilder<R>
sets: L, push_constants: &Pc) -> SecondaryGraphicsCommandBufferBuilder<R, P>
where Pv: 'static + VertexSource<V>, L: DescriptorSetsCollection + Send + Sync,
Pl: 'static + PipelineLayout + Send + Sync, Rp: RenderPass + RenderPassDesc + 'static + Send + Sync,
Pc: 'static + Clone + Send + Sync,
@ -650,7 +672,7 @@ impl<R> SecondaryGraphicsCommandBufferBuilder<R>
/// See the docs of build().
#[inline]
pub fn build_raw(self) -> Result<SecondaryGraphicsCommandBuffer<R>, OomError> {
pub fn build_raw(self) -> Result<SecondaryGraphicsCommandBuffer<R, P>, OomError> {
let inner = try!(self.inner.build());
Ok(SecondaryGraphicsCommandBuffer {
@ -667,7 +689,7 @@ impl<R> SecondaryGraphicsCommandBufferBuilder<R>
/// - Panicks if the device or host ran out of memory.
///
#[inline]
pub fn build(self) -> Arc<SecondaryGraphicsCommandBuffer<R>> {
pub fn build(self) -> Arc<SecondaryGraphicsCommandBuffer<R, P>> {
Arc::new(self.build_raw().unwrap())
}
}
@ -679,38 +701,40 @@ impl<R> SecondaryGraphicsCommandBufferBuilder<R>
/// a primary command buffer, specify a framebuffer, and then call the secondary command buffer.
///
/// A secondary graphics command buffer can't be called outside of a renderpass.
pub struct SecondaryGraphicsCommandBuffer<R> {
inner: InnerCommandBuffer,
pub struct SecondaryGraphicsCommandBuffer<R, P = Arc<StandardCommandPool>> where P: CommandPool {
inner: InnerCommandBuffer<P>,
render_pass: Arc<R>,
render_pass_subpass: u32,
}
/// A prototype of a secondary compute command buffer.
pub struct SecondaryComputeCommandBufferBuilder {
inner: InnerCommandBufferBuilder,
pub struct SecondaryComputeCommandBufferBuilder<P = Arc<StandardCommandPool>> where P: CommandPool {
inner: InnerCommandBufferBuilder<P>,
}
impl SecondaryComputeCommandBufferBuilder {
/// See the docs of new().
#[inline]
pub fn raw(pool: &Arc<CommandBufferPool>)
-> Result<SecondaryComputeCommandBufferBuilder, OomError>
{
let inner = try!(InnerCommandBufferBuilder::new::<UnsafeRenderPass>(pool, true, None, None));
Ok(SecondaryComputeCommandBufferBuilder { inner: inner })
}
impl SecondaryComputeCommandBufferBuilder<Arc<StandardCommandPool>> {
/// Builds a new secondary command buffer and start recording commands in it.
///
/// # Panic
///
/// - Panicks if the device or host ran out of memory.
/// - Panicks if the device and queue family do not belong to the same physical device.
///
#[inline]
pub fn new(pool: &Arc<CommandBufferPool>)
-> SecondaryComputeCommandBufferBuilder
pub fn new(device: &Arc<Device>, queue_family: QueueFamily)
-> SecondaryComputeCommandBufferBuilder<Arc<StandardCommandPool>>
{
SecondaryComputeCommandBufferBuilder::raw(pool).unwrap()
SecondaryComputeCommandBufferBuilder::raw(Device::standard_command_pool(device,
queue_family)).unwrap()
}
}
impl<P> SecondaryComputeCommandBufferBuilder<P> where P: CommandPool {
/// See the docs of new().
#[inline]
pub fn raw(pool: P) -> Result<SecondaryComputeCommandBufferBuilder<P>, OomError> {
let inner = try!(InnerCommandBufferBuilder::new::<UnsafeRenderPass>(pool, true, None, None));
Ok(SecondaryComputeCommandBufferBuilder { inner: inner })
}
/// Writes data to a buffer.
@ -728,7 +752,7 @@ impl SecondaryComputeCommandBufferBuilder {
/// - Panicks if the queue family doesn't support transfer operations.
///
#[inline]
pub fn update_buffer<'a, B, T, Bb>(self, buffer: B, data: &T) -> SecondaryComputeCommandBufferBuilder
pub fn update_buffer<'a, B, T, Bb>(self, buffer: B, data: &T) -> SecondaryComputeCommandBufferBuilder<P>
where B: Into<BufferSlice<'a, T, Bb>>, Bb: Buffer + 'static, T: Clone + 'static + Send + Sync
{
unsafe {
@ -754,7 +778,7 @@ impl SecondaryComputeCommandBufferBuilder {
///
/// - Type safety is not enforced by the API.
pub unsafe fn fill_buffer<B>(self, buffer: &Arc<B>, offset: usize, size: usize, data: u32)
-> SecondaryComputeCommandBufferBuilder
-> SecondaryComputeCommandBufferBuilder<P>
where B: Buffer + 'static
{
SecondaryComputeCommandBufferBuilder {
@ -764,7 +788,7 @@ impl SecondaryComputeCommandBufferBuilder {
/// See the docs of build().
#[inline]
pub fn build_raw(self) -> Result<SecondaryComputeCommandBuffer, OomError> {
pub fn build_raw(self) -> Result<SecondaryComputeCommandBuffer<P>, OomError> {
let inner = try!(self.inner.build());
Ok(SecondaryComputeCommandBuffer { inner: inner })
}
@ -776,7 +800,7 @@ impl SecondaryComputeCommandBufferBuilder {
/// - Panicks if the device or host ran out of memory.
///
#[inline]
pub fn build(self) -> Arc<SecondaryComputeCommandBuffer> {
pub fn build(self) -> Arc<SecondaryComputeCommandBuffer<P>> {
Arc::new(self.build_raw().unwrap())
}
}
@ -785,8 +809,10 @@ impl SecondaryComputeCommandBufferBuilder {
///
/// A secondary compute command buffer contains non-draw commands (like copy commands, compute
/// shader execution, etc.). It can only be called outside of a renderpass.
pub struct SecondaryComputeCommandBuffer {
inner: InnerCommandBuffer,
pub struct SecondaryComputeCommandBuffer<P = Arc<StandardCommandPool>>
where P: CommandPool
{
inner: InnerCommandBuffer<P>,
}
/// The dynamic state to use for a draw command.

View File

@ -1,113 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;
use instance::QueueFamily;
use device::Device;
use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;
/// A pool from which command buffers are created from.
pub struct CommandBufferPool {
pool: Mutex<vk::CommandPool>,
device: Arc<Device>,
queue_family_index: u32,
}
impl CommandBufferPool {
/// See the docs of new().
#[inline]
pub fn raw(device: &Arc<Device>, queue_family: &QueueFamily)
-> Result<CommandBufferPool, OomError>
{
assert_eq!(device.physical_device().internal_object(),
queue_family.physical_device().internal_object());
let vk = device.pointers();
let pool = unsafe {
let infos = vk::CommandPoolCreateInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
pNext: ptr::null(),
flags: 0, // TODO:
queueFamilyIndex: queue_family.id(),
};
let mut output = mem::uninitialized();
try!(check_errors(vk.CreateCommandPool(device.internal_object(), &infos,
ptr::null(), &mut output)));
output
};
Ok(CommandBufferPool {
pool: Mutex::new(pool),
device: device.clone(),
queue_family_index: queue_family.id(),
})
}
/// Creates a new pool.
///
/// The command buffers created with this pool can only be executed on queues of the given
/// family.
///
/// # Panic
///
/// - Panicks if the queue family doesn't belong to the same physical device as `device`.
/// - Panicks if the device or host ran out of memory.
///
#[inline]
pub fn new(device: &Arc<Device>, queue_family: &QueueFamily)
-> Arc<CommandBufferPool>
{
Arc::new(CommandBufferPool::raw(device, queue_family).unwrap())
}
/// Returns the device this command pool was created with.
#[inline]
pub fn device(&self) -> &Arc<Device> {
&self.device
}
/// Returns the queue family on which command buffers of this pool can be executed.
#[inline]
pub fn queue_family(&self) -> QueueFamily {
self.device.physical_device().queue_family_by_id(self.queue_family_index).unwrap()
}
}
unsafe impl SynchronizedVulkanObject for CommandBufferPool {
type Object = vk::CommandPool;
#[inline]
fn internal_object_guard(&self) -> MutexGuard<vk::CommandPool> {
self.pool.lock().unwrap()
}
}
impl Drop for CommandBufferPool {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
let pool = self.pool.lock().unwrap();
vk.DestroyCommandPool(self.device.internal_object(), *pool, ptr::null());
}
}
}

View File

@ -0,0 +1,121 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! In the Vulkan API, command buffers must be allocated from *command pools*.
//!
//! A command pool holds and manages the memory of one or more command buffers. If you destroy a
//! command pool, all of its command buffers are automatically destroyed.
//!
//! In vulkano, creating a command buffer requires passing an implementation of the `CommandPool`
//! trait. By default vulkano will use the `StandardCommandPool` struct, but you can implement
//! this trait yourself by wrapping around the `UnsafeCommandPool` type.
use std::sync::Arc;
use instance::QueueFamily;
use device::Device;
use OomError;
use VulkanObject;
use vk;
pub use self::standard::StandardCommandPool;
pub use self::standard::StandardCommandPoolFinished;
pub use self::sys::UnsafeCommandPool;
pub use self::sys::UnsafeCommandPoolAllocIter;
mod standard;
mod sys;
/// Types that manage the memory of command buffers.
pub unsafe trait CommandPool {
/// See `alloc()`.
type Iter: Iterator<Item = AllocatedCommandBuffer>;
/// See `lock()`.
type Lock;
/// See `finish()`.
type Finished: CommandPoolFinished;
/// Allocates command buffers from this pool.
fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError>;
/// Frees command buffers from this pool.
///
/// # Safety
///
/// - The command buffers must have been allocated from this pool.
/// - `secondary` must have the same value as what was passed to `alloc`.
///
unsafe fn free<I>(&self, secondary: bool, command_buffers: I)
where I: Iterator<Item = AllocatedCommandBuffer>;
/// Once a command buffer has finished being built, it should call this method in order to
/// produce a `Finished` object.
///
/// The `Finished` object must hold the pool alive.
///
/// The point of this object is to change the Send/Sync strategy after a command buffer has
/// finished being built compared to before.
fn finish(self) -> Self::Finished;
/// Before any command buffer allocated from this pool can be modified, the pool itself must
/// be locked by calling this method.
///
/// All the operations are atomic at the thread level, so the point of this lock is to
/// prevent the pool from being accessed from multiple threads in parallel.
fn lock(&self) -> Self::Lock;
/// Returns true if command buffers can be reset individually. In other words, if the pool
/// was created with `reset_cb` set to true.
fn can_reset_invidual_command_buffers(&self) -> bool;
/// Returns the device used to create this pool.
fn device(&self) -> &Arc<Device>;
/// Returns the queue family that this pool targets.
fn queue_family(&self) -> QueueFamily;
}
/// See `CommandPool::finish()`.
pub unsafe trait CommandPoolFinished {
/// Frees command buffers.
///
/// # Safety
///
/// - The command buffers must have been allocated from this pool.
/// - `secondary` must have the same value as what was passed to `alloc`.
///
unsafe fn free<I>(&self, secondary: bool, command_buffers: I)
where I: Iterator<Item = AllocatedCommandBuffer>;
/// Returns the device used to create this pool.
fn device(&self) -> &Arc<Device>;
/// Returns the queue family that this pool targets.
fn queue_family(&self) -> QueueFamily;
}
/// Opaque type that represents a command buffer allocated from a pool.
pub struct AllocatedCommandBuffer(vk::CommandBuffer);
impl From<vk::CommandBuffer> for AllocatedCommandBuffer {
#[inline]
fn from(cmd: vk::CommandBuffer) -> AllocatedCommandBuffer {
AllocatedCommandBuffer(cmd)
}
}
unsafe impl VulkanObject for AllocatedCommandBuffer {
type Object = vk::CommandBuffer;
#[inline]
fn internal_object(&self) -> vk::CommandBuffer {
self.0
}
}

View File

@ -0,0 +1,214 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::cmp;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::iter::Chain;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::Mutex;
use std::vec::IntoIter as VecIntoIter;
use command_buffer::pool::AllocatedCommandBuffer;
use command_buffer::pool::CommandPool;
use command_buffer::pool::CommandPoolFinished;
use command_buffer::pool::UnsafeCommandPool;
use command_buffer::pool::UnsafeCommandPoolAllocIter;
use instance::QueueFamily;
use device::Device;
use OomError;
use VulkanObject;
// Since the stdlib doesn't have a "thread ID" yet, we store a `Box<u8>` for each thread and the
// value of the pointer will be used as a thread id.
thread_local!(static THREAD_ID: Box<u8> = Box::new(0));
#[inline]
fn curr_thread_id() -> usize { THREAD_ID.with(|data| &**data as *const u8 as usize) }
/// Standard implementation of a command pool.
///
/// Will use one Vulkan pool per thread in order to avoid locking. Will try to reuse command
/// buffers. Locking is required only when allocating/freeing command buffers.
pub struct StandardCommandPool {
// The device.
device: Arc<Device>,
// Identifier of the queue family.
queue_family: u32,
// For each "thread id" (see `THREAD_ID` above), we store thread-specific info.
per_thread: Mutex<HashMap<usize, StandardCommandPoolPerThread>>,
// Dummy marker in order to not implement `Send` and `Sync`.
//
// Since `StandardCommandPool` isn't Send/Sync, then the command buffers that use this pool
// won't be Send/Sync either, which means that we don't need to lock the pool while the CB
// is being built.
//
// However `StandardCommandPoolFinished` *is* Send/Sync because the only operation that can
// be called on `StandardCommandPoolFinished` is freeing, and freeing does actually lock.
dummy_avoid_send_sync: PhantomData<*const u8>,
}
impl StandardCommandPool {
/// Builds a new pool.
///
/// # Panic
///
/// - Panicks if the device and the queue family don't belong to the same physical device.
///
pub fn new(device: &Arc<Device>, queue_family: QueueFamily) -> StandardCommandPool {
assert_eq!(device.physical_device().internal_object(),
queue_family.physical_device().internal_object());
StandardCommandPool {
device: device.clone(),
queue_family: queue_family.id(),
per_thread: Mutex::new(HashMap::new()),
dummy_avoid_send_sync: PhantomData,
}
}
}
struct StandardCommandPoolPerThread {
// The Vulkan pool of this thread.
pool: UnsafeCommandPool,
// List of existing primary command buffers that are available for reuse.
available_primary_command_buffers: Vec<AllocatedCommandBuffer>,
// List of existing secondary command buffers that are available for reuse.
available_secondary_command_buffers: Vec<AllocatedCommandBuffer>,
}
unsafe impl CommandPool for Arc<StandardCommandPool> {
type Iter = Chain<VecIntoIter<AllocatedCommandBuffer>, UnsafeCommandPoolAllocIter>;
type Lock = ();
type Finished = StandardCommandPoolFinished;
fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError> {
// Find the correct `StandardCommandPoolPerThread` structure.
let mut per_thread = self.per_thread.lock().unwrap();
let mut per_thread = match per_thread.entry(curr_thread_id()) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
let new_pool = try!(UnsafeCommandPool::new(&self.device, self.queue_family(),
false, true));
entry.insert(StandardCommandPoolPerThread {
pool: new_pool,
available_primary_command_buffers: Vec::new(),
available_secondary_command_buffers: Vec::new(),
})
},
};
// Which list of already-existing command buffers we are going to pick CBs from.
let mut existing = if secondary { &mut per_thread.available_secondary_command_buffers }
else { &mut per_thread.available_primary_command_buffers };
// Build an iterator to pick from already-existing command buffers.
let num_from_existing = cmp::min(count as usize, existing.len());
let from_existing = existing.drain(0 .. num_from_existing).collect::<Vec<_>>().into_iter();
// Build an iterator to construct the missing command buffers from the Vulkan pool.
let num_new = count as usize - num_from_existing;
debug_assert!(num_new <= count as usize); // Check overflows.
let newly_allocated = try!(per_thread.pool.alloc_command_buffers(secondary, num_new));
// Returning them as a chain.
Ok(from_existing.chain(newly_allocated))
}
unsafe fn free<I>(&self, secondary: bool, command_buffers: I)
where I: Iterator<Item = AllocatedCommandBuffer>
{
// Do not actually free the command buffers. Instead adding them to the list of command
// buffers available for reuse.
let mut per_thread = self.per_thread.lock().unwrap();
let mut per_thread = per_thread.get_mut(&curr_thread_id()).unwrap();
if secondary {
for cb in command_buffers {
per_thread.available_secondary_command_buffers.push(cb);
}
} else {
for cb in command_buffers {
per_thread.available_primary_command_buffers.push(cb);
}
}
}
#[inline]
fn finish(self) -> Self::Finished {
StandardCommandPoolFinished {
pool: self,
thread_id: curr_thread_id(),
}
}
#[inline]
fn lock(&self) -> Self::Lock {
()
}
#[inline]
fn can_reset_invidual_command_buffers(&self) -> bool {
true
}
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
#[inline]
fn queue_family(&self) -> QueueFamily {
self.device.physical_device().queue_family_by_id(self.queue_family).unwrap()
}
}
pub struct StandardCommandPoolFinished {
pool: Arc<StandardCommandPool>,
thread_id: usize,
}
unsafe impl CommandPoolFinished for StandardCommandPoolFinished {
unsafe fn free<I>(&self, secondary: bool, command_buffers: I)
where I: Iterator<Item = AllocatedCommandBuffer>
{
let mut per_thread = self.pool.per_thread.lock().unwrap();
let mut per_thread = per_thread.get_mut(&curr_thread_id()).unwrap();
if secondary {
for cb in command_buffers {
per_thread.available_secondary_command_buffers.push(cb);
}
} else {
for cb in command_buffers {
per_thread.available_primary_command_buffers.push(cb);
}
}
}
#[inline]
fn device(&self) -> &Arc<Device> {
self.pool.device()
}
#[inline]
fn queue_family(&self) -> QueueFamily {
self.pool.queue_family()
}
}
// See `StandardCommandPool` for comments about this.
unsafe impl Send for StandardCommandPoolFinished {}
unsafe impl Sync for StandardCommandPoolFinished {}

View File

@ -0,0 +1,205 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;
use smallvec::SmallVec;
use command_buffer::pool::AllocatedCommandBuffer;
use instance::QueueFamily;
use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;
/// Low-level implementation of a command pool.
pub struct UnsafeCommandPool {
pool: vk::CommandPool,
device: Arc<Device>,
queue_family_index: u32,
// We don't want `UnsafeCommandPool` to implement Sync, since the Vulkan command pool isn't
// thread safe.
//
// This marker unimplements both Send and Sync, but we reimplement Send manually right under.
dummy_avoid_sync: PhantomData<*const u8>,
}
unsafe impl Send for UnsafeCommandPool {}
impl UnsafeCommandPool {
/// Creates a new pool.
///
/// The command buffers created with this pool can only be executed on queues of the given
/// family.
///
/// Setting `transient` to true is a hint to the implementation that the command buffers will
/// be short-lived.
/// Setting `reset_cb` to true means that command buffers can be reset individually.
///
/// # Panic
///
/// - Panicks if the queue family doesn't belong to the same physical device as `device`.
///
pub fn new(device: &Arc<Device>, queue_family: QueueFamily, transient: bool,
reset_cb: bool) -> Result<UnsafeCommandPool, OomError>
{
assert_eq!(device.physical_device().internal_object(),
queue_family.physical_device().internal_object());
let vk = device.pointers();
let flags = {
let flag1 = if transient { vk::COMMAND_POOL_CREATE_TRANSIENT_BIT } else { 0 };
let flag2 = if reset_cb { vk::COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT }
else { 0 };
flag1 | flag2
};
let pool = unsafe {
let infos = vk::CommandPoolCreateInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
pNext: ptr::null(),
flags: flags,
queueFamilyIndex: queue_family.id(),
};
let mut output = mem::uninitialized();
try!(check_errors(vk.CreateCommandPool(device.internal_object(), &infos,
ptr::null(), &mut output)));
output
};
Ok(UnsafeCommandPool {
pool: pool,
device: device.clone(),
queue_family_index: queue_family.id(),
dummy_avoid_sync: PhantomData,
})
}
/// Resets the pool, which resets all the command buffers that were allocated from it.
///
/// # Safety
///
/// The command buffers allocated from this pool jump to the initial state.
///
#[inline]
pub unsafe fn reset(&self, release_resources: bool) -> Result<(), OomError> {
let flags = if release_resources { vk::COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT }
else { 0 };
let vk = self.device.pointers();
try!(check_errors(vk.ResetCommandPool(self.device.internal_object(), self.pool, flags)));
Ok(())
}
/// Allocates `count` command buffers.
///
/// If `secondary` is true, allocates secondary command buffers. Otherwise, allocates primary
/// command buffers.
pub fn alloc_command_buffers(&self, secondary: bool, count: usize)
-> Result<UnsafeCommandPoolAllocIter, OomError>
{
if count == 0 {
return Ok(UnsafeCommandPoolAllocIter(None));
}
let infos = vk::CommandBufferAllocateInfo {
sType: vk::STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
pNext: ptr::null(),
commandPool: self.pool,
level: if secondary { vk::COMMAND_BUFFER_LEVEL_SECONDARY }
else { vk::COMMAND_BUFFER_LEVEL_PRIMARY },
commandBufferCount: count as u32,
};
unsafe {
let vk = self.device.pointers();
let mut out = Vec::with_capacity(count);
try!(check_errors(vk.AllocateCommandBuffers(self.device.internal_object(), &infos,
out.as_mut_ptr())));
out.set_len(count);
Ok(UnsafeCommandPoolAllocIter(Some(out.into_iter())))
}
}
/// Frees individual command buffers.
///
/// # Safety
///
/// The command buffers must have been allocated from this pool.
///
pub unsafe fn free_command_buffers<I>(&self, command_buffers: I)
where I: Iterator<Item = AllocatedCommandBuffer>
{
let command_buffers: SmallVec<[_; 4]> = command_buffers.map(|cb| cb.0).collect();
let vk = self.device.pointers();
vk.FreeCommandBuffers(self.device.internal_object(), self.pool,
command_buffers.len() as u32, command_buffers.as_ptr())
}
/// Returns the device this command pool was created with.
#[inline]
pub fn device(&self) -> &Arc<Device> {
&self.device
}
/// Returns the queue family on which command buffers of this pool can be executed.
#[inline]
pub fn queue_family(&self) -> QueueFamily {
self.device.physical_device().queue_family_by_id(self.queue_family_index).unwrap()
}
}
unsafe impl VulkanObject for UnsafeCommandPool {
type Object = vk::CommandPool;
#[inline]
fn internal_object(&self) -> vk::CommandPool {
self.pool
}
}
impl Drop for UnsafeCommandPool {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
vk.DestroyCommandPool(self.device.internal_object(), self.pool, ptr::null());
}
}
}
/// Iterator for newly-allocated command buffers.
pub struct UnsafeCommandPoolAllocIter(Option<VecIntoIter<vk::CommandBuffer>>);
impl Iterator for UnsafeCommandPoolAllocIter {
type Item = AllocatedCommandBuffer;
#[inline]
fn next(&mut self) -> Option<AllocatedCommandBuffer> {
self.0.as_mut().and_then(|i| i.next()).map(|cb| AllocatedCommandBuffer(cb))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.as_ref().map(|i| i.size_hint()).unwrap_or((0, Some(0)))
}
}
impl ExactSizeIterator for UnsafeCommandPoolAllocIter {}

View File

@ -12,6 +12,8 @@
//! The `Device` is one of the most important objects of Vulkan. Creating a `Device` is required
//! before you can create buffers, textures, shaders, etc.
//!
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt;
use std::error;
use std::mem;
@ -22,6 +24,7 @@ use std::sync::MutexGuard;
use std::sync::Weak;
use smallvec::SmallVec;
use command_buffer::pool::StandardCommandPool;
use instance::Features;
use instance::Instance;
use instance::PhysicalDevice;
@ -46,10 +49,16 @@ pub struct Device {
device: vk::Device,
vk: vk::DevicePointers,
standard_pool: Mutex<Option<Weak<StdMemoryPool>>>, // TODO: use Weak::new() instead
standard_command_pools: Mutex<HashMap<u32, Weak<StandardCommandPool>>>, // TODO: use a better hasher
features: Features,
extensions: DeviceExtensions,
}
// The `StandardCommandPool` type doesn't implement Send/Sync, so we have to manually reimplement
// them for the device itself.
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
impl Device {
/// Builds a new Vulkan device for the given physical device.
///
@ -189,6 +198,7 @@ impl Device {
device: device,
vk: vk,
standard_pool: Mutex::new(None),
standard_command_pools: Mutex::new(HashMap::new()),
features: requested_features.clone(),
extensions: extensions.clone(),
});
@ -265,6 +275,34 @@ impl Device {
*pool = Some(Arc::downgrade(&new_pool));
new_pool
}
/// Returns the standard command buffer pool used by default if you don't provide any other
/// pool.
///
/// # Panic
///
/// - Panicks if the device and the queue family don't belong to the same physical device.
///
pub fn standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool> {
let mut standard_command_pools = me.standard_command_pools.lock().unwrap();
match standard_command_pools.entry(queue.id()) {
Entry::Occupied(mut entry) => {
if let Some(pool) = entry.get().upgrade() {
return pool;
}
let new_pool = Arc::new(StandardCommandPool::new(me, queue));
*entry.get_mut() = Arc::downgrade(&new_pool);
new_pool
},
Entry::Vacant(entry) => {
let new_pool = Arc::new(StandardCommandPool::new(me, queue));
entry.insert(Arc::downgrade(&new_pool));
new_pool
}
}
}
}
impl fmt::Debug for Device {