mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
Merge pull request #125 from tomaka/cb-pool-rework
[breaking-change] Rework command pools
This commit is contained in:
commit
164389d6c4
@ -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])
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
121
vulkano/src/command_buffer/pool/mod.rs
Normal file
121
vulkano/src/command_buffer/pool/mod.rs
Normal 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
|
||||
}
|
||||
}
|
214
vulkano/src/command_buffer/pool/standard.rs
Normal file
214
vulkano/src/command_buffer/pool/standard.rs
Normal 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 {}
|
205
vulkano/src/command_buffer/pool/sys.rs
Normal file
205
vulkano/src/command_buffer/pool/sys.rs
Normal 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 {}
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user