mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2025-02-18 18:12:32 +00:00
New command buffers system
This commit is contained in:
parent
71b641594e
commit
94b22ab82f
@ -37,10 +37,17 @@ use buffer::sys::UnsafeBuffer;
|
||||
use buffer::sys::Usage;
|
||||
use buffer::traits::AccessRange;
|
||||
use buffer::traits::Buffer;
|
||||
use buffer::traits::CommandBufferState;
|
||||
use buffer::traits::CommandListState;
|
||||
use buffer::traits::GpuAccessResult;
|
||||
use buffer::traits::SubmitInfos;
|
||||
use buffer::traits::TrackedBuffer;
|
||||
use buffer::traits::TypedBuffer;
|
||||
use buffer::traits::PipelineBarrierRequest;
|
||||
use buffer::traits::PipelineMemoryBarrierRequest;
|
||||
use command_buffer::Submission;
|
||||
use device::Device;
|
||||
use device::Queue;
|
||||
use instance::QueueFamily;
|
||||
use memory::Content;
|
||||
use memory::CpuAccess as MemCpuAccess;
|
||||
@ -50,6 +57,9 @@ use memory::pool::MemoryPoolAlloc;
|
||||
use memory::pool::StdMemoryPool;
|
||||
use sync::FenceWaitError;
|
||||
use sync::Sharing;
|
||||
use sync::Fence;
|
||||
use sync::AccessFlagBits;
|
||||
use sync::PipelineStages;
|
||||
|
||||
use OomError;
|
||||
|
||||
@ -392,6 +402,173 @@ unsafe impl<T: ?Sized, A> TypedBuffer for CpuAccessibleBuffer<T, A>
|
||||
type Content = T;
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, A> TrackedBuffer for CpuAccessibleBuffer<T, A>
|
||||
where T: 'static + Send + Sync, A: MemoryPool
|
||||
{
|
||||
type CommandListState = CpuAccessibleBufferClState;
|
||||
type FinishedState = CpuAccessibleBufferFinished;
|
||||
|
||||
#[inline]
|
||||
fn initial_state(&self) -> Self::CommandListState {
|
||||
// We don't know when the user is going to write to the buffer, so we just assume that it's
|
||||
// all the time.
|
||||
CpuAccessibleBufferClState {
|
||||
size: self.size(),
|
||||
stages: PipelineStages { host: true, .. PipelineStages::none() },
|
||||
access: AccessFlagBits { host_write: true, .. AccessFlagBits::none() },
|
||||
first_stages: None,
|
||||
write: true,
|
||||
earliest_previous_transition: 0,
|
||||
needs_flush_at_the_end: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CpuAccessibleBufferClState {
|
||||
size: usize,
|
||||
stages: PipelineStages,
|
||||
access: AccessFlagBits,
|
||||
first_stages: Option<PipelineStages>,
|
||||
write: bool,
|
||||
earliest_previous_transition: usize,
|
||||
needs_flush_at_the_end: bool,
|
||||
}
|
||||
|
||||
impl CommandListState for CpuAccessibleBufferClState {
|
||||
type FinishedState = CpuAccessibleBufferFinished;
|
||||
|
||||
fn transition(self, num_command: usize, _: &UnsafeBuffer, _: usize, _: usize, write: bool,
|
||||
stage: PipelineStages, access: AccessFlagBits)
|
||||
-> (Self, Option<PipelineBarrierRequest>)
|
||||
{
|
||||
debug_assert!(!stage.host);
|
||||
debug_assert!(!access.host_read);
|
||||
debug_assert!(!access.host_write);
|
||||
|
||||
if write {
|
||||
// Write after read or write after write.
|
||||
let new_state = CpuAccessibleBufferClState {
|
||||
size: self.size,
|
||||
stages: stage,
|
||||
access: access,
|
||||
first_stages: Some(self.first_stages.clone().unwrap_or(stage)),
|
||||
write: true,
|
||||
earliest_previous_transition: num_command,
|
||||
needs_flush_at_the_end: true,
|
||||
};
|
||||
|
||||
let barrier = PipelineBarrierRequest {
|
||||
after_command_num: self.earliest_previous_transition,
|
||||
source_stage: self.stages,
|
||||
destination_stages: stage,
|
||||
by_region: true,
|
||||
memory_barrier: if self.write {
|
||||
Some(PipelineMemoryBarrierRequest {
|
||||
offset: 0,
|
||||
size: self.size,
|
||||
source_access: self.access,
|
||||
destination_access: access,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
(new_state, Some(barrier))
|
||||
|
||||
} else if self.write {
|
||||
// Read after write.
|
||||
let new_state = CpuAccessibleBufferClState {
|
||||
size: self.size,
|
||||
stages: stage,
|
||||
access: access,
|
||||
first_stages: Some(self.first_stages.clone().unwrap_or(stage)),
|
||||
write: false,
|
||||
earliest_previous_transition: num_command,
|
||||
needs_flush_at_the_end: self.needs_flush_at_the_end,
|
||||
};
|
||||
|
||||
let barrier = PipelineBarrierRequest {
|
||||
after_command_num: self.earliest_previous_transition,
|
||||
source_stage: self.stages,
|
||||
destination_stages: stage,
|
||||
by_region: true,
|
||||
memory_barrier: Some(PipelineMemoryBarrierRequest {
|
||||
offset: 0,
|
||||
size: self.size,
|
||||
source_access: self.access,
|
||||
destination_access: access,
|
||||
}),
|
||||
};
|
||||
|
||||
(new_state, Some(barrier))
|
||||
|
||||
} else {
|
||||
// Read after read.
|
||||
let new_state = CpuAccessibleBufferClState {
|
||||
size: self.size,
|
||||
stages: self.stages | stage,
|
||||
access: self.access | access,
|
||||
first_stages: Some(self.first_stages.clone().unwrap_or(stage)),
|
||||
write: false,
|
||||
earliest_previous_transition: self.earliest_previous_transition,
|
||||
needs_flush_at_the_end: self.needs_flush_at_the_end,
|
||||
};
|
||||
|
||||
(new_state, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(self) -> (Self::FinishedState, Option<PipelineBarrierRequest>) {
|
||||
let barrier = if self.needs_flush_at_the_end {
|
||||
let barrier = PipelineBarrierRequest {
|
||||
after_command_num: self.earliest_previous_transition,
|
||||
source_stage: self.stages,
|
||||
destination_stages: PipelineStages { host: true, .. PipelineStages::none() },
|
||||
by_region: true,
|
||||
memory_barrier: Some(PipelineMemoryBarrierRequest {
|
||||
offset: 0,
|
||||
size: self.size,
|
||||
source_access: self.access,
|
||||
destination_access: AccessFlagBits { host_read: true,
|
||||
.. AccessFlagBits::none() },
|
||||
}),
|
||||
};
|
||||
|
||||
Some(barrier)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let finished = CpuAccessibleBufferFinished {
|
||||
first_stages: self.first_stages.unwrap_or(PipelineStages::none()),
|
||||
write: self.needs_flush_at_the_end,
|
||||
};
|
||||
|
||||
(finished, barrier)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CpuAccessibleBufferFinished {
|
||||
first_stages: PipelineStages,
|
||||
write: bool,
|
||||
}
|
||||
|
||||
impl CommandBufferState for CpuAccessibleBufferFinished {
|
||||
fn on_submit<B, F>(&self, buffer: &B, queue: &Arc<Queue>, fence: F) -> SubmitInfos
|
||||
where B: Buffer, F: FnOnce() -> Arc<Fence>
|
||||
{
|
||||
// FIXME: implement correctly
|
||||
|
||||
SubmitInfos {
|
||||
pre_semaphore: None,
|
||||
post_semaphore: None,
|
||||
pre_barrier: None,
|
||||
post_barrier: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Object that can be used to read or write the content of a `CpuAccessBuffer`.
|
||||
///
|
||||
/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
|
||||
|
@ -348,6 +348,15 @@ impl Usage {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `Usage` with `transfer_dest` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub fn transfer_dest() -> Usage {
|
||||
Usage {
|
||||
transfer_dest: true,
|
||||
.. Usage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `Usage` with `vertex_buffer` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub fn vertex_buffer() -> Usage {
|
||||
|
@ -7,14 +7,24 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::any::Any;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use buffer::sys::UnsafeBuffer;
|
||||
use command_buffer::Submission;
|
||||
use device::Queue;
|
||||
use memory::Content;
|
||||
|
||||
use sync::AccessFlagBits;
|
||||
use sync::Fence;
|
||||
use sync::PipelineStages;
|
||||
use sync::Semaphore;
|
||||
|
||||
use VulkanObject;
|
||||
|
||||
pub unsafe trait Buffer: 'static + Send + Sync {
|
||||
/// Returns the inner buffer.
|
||||
fn inner(&self) -> &UnsafeBuffer;
|
||||
@ -58,6 +68,147 @@ pub unsafe trait Buffer: 'static + Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension trait for `Buffer`. Types that implement this can used in a `StdCommandBuffer`.
|
||||
///
|
||||
/// Each buffer and image used in a `StdCommandBuffer` have an associated state which is
|
||||
/// represented by the `CommandListState` associated type of this trait. You can make multiple
|
||||
/// buffers or images share the same state by making `is_same` return true.
|
||||
pub unsafe trait TrackedBuffer: Buffer {
|
||||
/// State of the buffer in a list of commands.
|
||||
///
|
||||
/// The `Any` bound is here for stupid reasons, sorry.
|
||||
// TODO: remove Any bound
|
||||
type CommandListState: Any + CommandListState<FinishedState = Self::FinishedState>;
|
||||
/// State of the buffer in a finished list of commands.
|
||||
type FinishedState: CommandBufferState;
|
||||
|
||||
/// Returns true if TODO.
|
||||
///
|
||||
/// If `is_same` returns true, then the type of `CommandListState` must be the same as for the
|
||||
/// other buffer. Otherwise a panic will occur.
|
||||
#[inline]
|
||||
fn is_same<B>(&self, other: &B) -> bool where B: Buffer {
|
||||
self.inner().internal_object() == other.inner().internal_object()
|
||||
}
|
||||
|
||||
/// Returns the state of the buffer when it has not yet been used.
|
||||
fn initial_state(&self) -> Self::CommandListState;
|
||||
}
|
||||
|
||||
/// Trait for objects that represent the state of a slice of the buffer in a list of commands.
|
||||
pub trait CommandListState {
|
||||
type FinishedState: CommandBufferState;
|
||||
|
||||
/// Returns a new state that corresponds to the moment after a slice of the buffer has been
|
||||
/// used in the pipeline. The parameters indicate in which way it has been used.
|
||||
///
|
||||
/// If the transition should result in a pipeline barrier, then it must be returned by this
|
||||
/// function.
|
||||
fn transition(self, num_command: usize, buffer: &UnsafeBuffer, offset: usize, size: usize,
|
||||
write: bool, stage: PipelineStages, access: AccessFlagBits)
|
||||
-> (Self, Option<PipelineBarrierRequest>)
|
||||
where Self: Sized;
|
||||
|
||||
/// Function called when the command buffer builder is turned into a real command buffer.
|
||||
///
|
||||
/// This function can return an additional pipeline barrier that will be applied at the end
|
||||
/// of the command buffer.
|
||||
fn finish(self) -> (Self::FinishedState, Option<PipelineBarrierRequest>);
|
||||
}
|
||||
|
||||
/// Requests that a pipeline barrier is created.
|
||||
pub struct PipelineBarrierRequest {
|
||||
/// The number of the command after which the barrier should be placed. Must usually match
|
||||
/// the number that was passed to the previous call to `transition`, or 0 if the buffer hasn't
|
||||
/// been used yet.
|
||||
pub after_command_num: usize,
|
||||
|
||||
/// The source pipeline stages of the transition.
|
||||
pub source_stage: PipelineStages,
|
||||
|
||||
/// The destination pipeline stages of the transition.
|
||||
pub destination_stages: PipelineStages,
|
||||
|
||||
/// If true, the pipeliner barrier is by region. There is literaly no reason to pass `false`
|
||||
/// here, but it is included just in case.
|
||||
pub by_region: bool,
|
||||
|
||||
/// An optional memory barrier. See the docs of `PipelineMemoryBarrierRequest`.
|
||||
pub memory_barrier: Option<PipelineMemoryBarrierRequest>,
|
||||
}
|
||||
|
||||
/// Requests that a memory barrier is created as part of the pipeline barrier.
|
||||
///
|
||||
/// By default, a pipeline barrier only guarantees that the source operations are executed before
|
||||
/// the destination operations, but it doesn't make memory writes made by source operations visible
|
||||
/// to the destination operations. In order to make so, you have to add a memory barrier.
|
||||
///
|
||||
/// The memory barrier always concerns the buffer that is currently being processed. You can't add
|
||||
/// a memory barrier that concerns another resource.
|
||||
pub struct PipelineMemoryBarrierRequest {
|
||||
/// Offset of start of the range to flush.
|
||||
pub offset: usize,
|
||||
/// Size of the range to flush.
|
||||
pub size: usize,
|
||||
/// Source accesses.
|
||||
pub source_access: AccessFlagBits,
|
||||
/// Destination accesses.
|
||||
pub destination_access: AccessFlagBits,
|
||||
}
|
||||
|
||||
/// Trait for objects that represent the state of a slice of the buffer in a command buffer.
|
||||
pub trait CommandBufferState {
|
||||
/// Called right before the command buffer is submitted.
|
||||
// TODO: function should be unsafe because it must be guaranteed that a cb is submitted
|
||||
fn on_submit<B, F>(&self, buffer: &B, queue: &Arc<Queue>, fence: F) -> SubmitInfos
|
||||
where B: Buffer, F: FnOnce() -> Arc<Fence>;
|
||||
}
|
||||
|
||||
pub struct SubmitInfos {
|
||||
pub pre_semaphore: Option<(Receiver<Arc<Semaphore>>, PipelineStages)>,
|
||||
pub post_semaphore: Option<Sender<Arc<Semaphore>>>,
|
||||
pub pre_barrier: Option<PipelineBarrierRequest>,
|
||||
pub post_barrier: Option<PipelineBarrierRequest>,
|
||||
}
|
||||
|
||||
unsafe impl<B> Buffer for Arc<B> where B: Buffer {
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeBuffer {
|
||||
(**self).inner()
|
||||
}
|
||||
|
||||
fn needs_fence(&self, _: bool, _: Range<usize>) -> Option<bool> { unimplemented!() }
|
||||
|
||||
fn host_accesses(&self, _: usize) -> bool { unimplemented!() }
|
||||
|
||||
fn blocks(&self, _: Range<usize>) -> Vec<usize> { unimplemented!() }
|
||||
|
||||
fn block_memory_range(&self, _: usize) -> Range<usize> { unimplemented!() }
|
||||
|
||||
unsafe fn gpu_access(&self, _: &mut Iterator<Item = AccessRange>,
|
||||
_: &Arc<Submission>) -> GpuAccessResult { unimplemented!() }
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
(**self).size()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<B> TrackedBuffer for Arc<B> where B: TrackedBuffer, Arc<B>: Buffer {
|
||||
type CommandListState = B::CommandListState;
|
||||
type FinishedState = B::FinishedState;
|
||||
|
||||
#[inline]
|
||||
fn is_same<Bo>(&self, other: &Bo) -> bool where Bo: Buffer {
|
||||
(**self).is_same(other)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn initial_state(&self) -> Self::CommandListState {
|
||||
(**self).initial_state()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait TypedBuffer: Buffer {
|
||||
type Content: ?Sized + 'static;
|
||||
|
||||
|
@ -59,6 +59,7 @@ mod inner;
|
||||
mod outer;
|
||||
|
||||
pub mod pool;
|
||||
pub mod std;
|
||||
pub mod submit;
|
||||
pub mod sys;
|
||||
|
||||
|
76
vulkano/src/command_buffer/std/copy_buffer.rs
Normal file
76
vulkano/src/command_buffer/std/copy_buffer.rs
Normal file
@ -0,0 +1,76 @@
|
||||
// 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::any::Any;
|
||||
|
||||
pub struct CopyCommand<L, B> where B: Buffer, L: CommandsList {
|
||||
previous: L,
|
||||
buffer: B,
|
||||
buffer_state: B::CommandBufferState,
|
||||
transition: Option<>,
|
||||
}
|
||||
|
||||
impl<L, B> CommandsList for CopyCommand<L, B> where B: Buffer, L: CommandsList {
|
||||
pub fn new(previous: L, buffer: B) -> CopyCommand<L, B> {
|
||||
let (state, transition) = previous.current_buffer_state(buffer)
|
||||
.transition(false, self.num_commands(), ShaderStages, AccessFlagBits);
|
||||
assert!(transition.after_command_num < self.num_commands());
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<L, B> CommandsList for CopyCommand<L, B> where B: Buffer, L: CommandsList {
|
||||
fn num_commands(&self) -> usize {
|
||||
self.previous.num_commands() + 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn requires_graphics_queue(&self) -> bool {
|
||||
self.previous.requires_graphics_queue()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn requires_compute_queue(&self) -> bool {
|
||||
self.previous.requires_compute_queue()
|
||||
}
|
||||
|
||||
fn current_buffer_state<Ob>(&self, other: &Ob) -> Ob::CommandBufferState
|
||||
where Ob: Buffer
|
||||
{
|
||||
if self.buffer.is_same(b) {
|
||||
let s: &Ob::CommandBufferState = (&self.buffer_state as &Any).downcast_ref().unwrap();
|
||||
s.clone()
|
||||
} else {
|
||||
self.previous.current_buffer_state(b)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn build_unsafe_command_buffer<P, I>(&self, pool: P, transitions: I) -> UnsafeCommandBufferBuilder<P>
|
||||
where P: CommandPool
|
||||
{
|
||||
let my_command_num = self.num_commands();
|
||||
|
||||
let mut transitions_to_apply = PipelineBarrierBuilder::new();
|
||||
|
||||
let transitions = transitions.filter_map(|transition| {
|
||||
if transition.after_command_num >= my_command_num {
|
||||
transitions_to_apply.push(transition);
|
||||
None
|
||||
} else {
|
||||
Some(transition)
|
||||
}
|
||||
}).chain(self.transition.clone().into_iter());
|
||||
|
||||
let mut parent_cb = self.previous.build_unsafe_command_buffer(pool, transitions.clone().chain());
|
||||
parent_cb.copy_buffer();
|
||||
parent_cb.pipeline_barrier(transitions_to_apply);
|
||||
parent_cb
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl StdPrimaryCommandsList
|
143
vulkano/src/command_buffer/std/empty.rs
Normal file
143
vulkano/src/command_buffer/std/empty.rs
Normal file
@ -0,0 +1,143 @@
|
||||
// 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::iter;
|
||||
use std::iter::Empty;
|
||||
use std::sync::Arc;
|
||||
|
||||
use buffer::traits::TrackedBuffer;
|
||||
use command_buffer::pool::CommandPool;
|
||||
use command_buffer::pool::StandardCommandPool;
|
||||
use command_buffer::std::StdCommandsList;
|
||||
use command_buffer::submit::CommandBuffer;
|
||||
use command_buffer::submit::SubmitInfo;
|
||||
use command_buffer::sys::PipelineBarrierBuilder;
|
||||
use command_buffer::sys::UnsafeCommandBuffer;
|
||||
use command_buffer::sys::UnsafeCommandBufferBuilder;
|
||||
use command_buffer::sys::Flags;
|
||||
use command_buffer::sys::Kind;
|
||||
use device::Device;
|
||||
use device::Queue;
|
||||
use framebuffer::EmptySinglePassRenderPass;
|
||||
use instance::QueueFamily;
|
||||
use sync::Fence;
|
||||
use sync::PipelineStages;
|
||||
use sync::Semaphore;
|
||||
|
||||
pub struct PrimaryCbBuilder<P = Arc<StandardCommandPool>> where P: CommandPool {
|
||||
pool: P,
|
||||
flags: Flags,
|
||||
}
|
||||
|
||||
impl PrimaryCbBuilder<Arc<StandardCommandPool>> {
|
||||
/// Builds a new primary command buffer builder.
|
||||
#[inline]
|
||||
pub fn new(device: &Arc<Device>, family: QueueFamily)
|
||||
-> PrimaryCbBuilder<Arc<StandardCommandPool>>
|
||||
{
|
||||
PrimaryCbBuilder::with_pool(Device::standard_command_pool(device, family))
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> PrimaryCbBuilder<P> where P: CommandPool {
|
||||
/// Builds a new primary command buffer builder that uses a specific pool.
|
||||
pub fn with_pool(pool: P) -> PrimaryCbBuilder<P> {
|
||||
PrimaryCbBuilder {
|
||||
pool: pool,
|
||||
flags: Flags::SimultaneousUse, // TODO: allow customization
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<P> StdCommandsList for PrimaryCbBuilder<P> where P: CommandPool {
|
||||
type Pool = P;
|
||||
type Output = PrimaryCb<P>;
|
||||
|
||||
#[inline]
|
||||
fn num_commands(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn extract_current_buffer_state<B>(&mut self, buffer: &B) -> Option<B::CommandListState>
|
||||
where B: TrackedBuffer
|
||||
{
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn raw_build<I, F>(self, additional_elements: F, transitions: I,
|
||||
final_transitions: PipelineBarrierBuilder) -> Self::Output
|
||||
where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
|
||||
I: Iterator<Item = (usize, PipelineBarrierBuilder)>
|
||||
{
|
||||
let mut pipeline_barrier = PipelineBarrierBuilder::new();
|
||||
for (_, transition) in transitions {
|
||||
pipeline_barrier.merge(transition);
|
||||
}
|
||||
|
||||
let kind = Kind::Primary::<EmptySinglePassRenderPass, EmptySinglePassRenderPass>;
|
||||
let mut cb = UnsafeCommandBufferBuilder::new(self.pool, kind,
|
||||
self.flags).unwrap(); // TODO: handle
|
||||
cb.pipeline_barrier(pipeline_barrier);
|
||||
additional_elements(&mut cb);
|
||||
cb.pipeline_barrier(final_transitions);
|
||||
|
||||
PrimaryCb {
|
||||
cb: cb.build().unwrap(), // TODO: handle error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrimaryCb<P = Arc<StandardCommandPool>> where P: CommandPool {
|
||||
cb: UnsafeCommandBuffer<P>,
|
||||
}
|
||||
|
||||
unsafe impl<P> CommandBuffer for PrimaryCb<P> where P: CommandPool {
|
||||
type Pool = P;
|
||||
type SemaphoresWaitIterator = Empty<(Arc<Semaphore>, PipelineStages)>;
|
||||
type SemaphoresSignalIterator = Empty<Arc<Semaphore>>;
|
||||
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool> {
|
||||
&self.cb
|
||||
}
|
||||
|
||||
unsafe fn on_submit<F>(&self, queue: &Arc<Queue>, fence: F)
|
||||
-> SubmitInfo<Self::SemaphoresWaitIterator,
|
||||
Self::SemaphoresSignalIterator>
|
||||
where F: FnMut() -> Arc<Fence>
|
||||
{
|
||||
// TODO: must handle SimultaneousUse and Once flags
|
||||
|
||||
SubmitInfo {
|
||||
semaphores_wait: iter::empty(),
|
||||
semaphores_signal: iter::empty(),
|
||||
pre_pipeline_barrier: PipelineBarrierBuilder::new(),
|
||||
post_pipeline_barrier: PipelineBarrierBuilder::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use command_buffer::std::PrimaryCbBuilder;
|
||||
use command_buffer::std::StdCommandsList;
|
||||
use command_buffer::submit::CommandBuffer;
|
||||
|
||||
#[test]
|
||||
fn basic_submit() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
let _ = PrimaryCbBuilder::new(&device, queue.family()).build().submit(&queue);
|
||||
}
|
||||
}
|
96
vulkano/src/command_buffer/std/mod.rs
Normal file
96
vulkano/src/command_buffer/std/mod.rs
Normal file
@ -0,0 +1,96 @@
|
||||
// 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::iter;
|
||||
|
||||
use buffer::traits::TrackedBuffer;
|
||||
use command_buffer::pool::CommandPool;
|
||||
use command_buffer::submit::CommandBuffer;
|
||||
use command_buffer::sys::PipelineBarrierBuilder;
|
||||
use command_buffer::sys::UnsafeCommandBufferBuilder;
|
||||
use instance::QueueFamily;
|
||||
|
||||
pub use self::empty::PrimaryCb;
|
||||
pub use self::empty::PrimaryCbBuilder;
|
||||
pub use self::update_buffer::UpdateCommand;
|
||||
|
||||
mod empty;
|
||||
mod update_buffer;
|
||||
|
||||
/// A list of commands that can be turned into a command buffer.
|
||||
pub unsafe trait StdCommandsList {
|
||||
/// The type of the pool that will be used to create the command buffer.
|
||||
type Pool: CommandPool;
|
||||
/// The type of the command buffer that will be generated.
|
||||
type Output: CommandBuffer<Pool = Self::Pool>;
|
||||
|
||||
/// Adds a command that writes the content of a buffer.
|
||||
///
|
||||
/// After this command is executed, the content of `buffer` will become `data`.
|
||||
#[inline]
|
||||
fn update_buffer<'a, B, D: ?Sized>(self, buffer: B, data: &'a D)
|
||||
-> UpdateCommand<'a, Self, B, D>
|
||||
where Self: Sized, B: TrackedBuffer, D: Copy + 'static
|
||||
{
|
||||
UpdateCommand::new(self, buffer, data)
|
||||
}
|
||||
|
||||
/// Turns the commands list into a command buffer that can be submitted.
|
||||
fn build(self) -> Self::Output where Self: Sized {
|
||||
unsafe {
|
||||
self.raw_build(|_| {}, iter::empty(), PipelineBarrierBuilder::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of commands in the commands list.
|
||||
///
|
||||
/// Note that multiple actual commands may count for just 1.
|
||||
fn num_commands(&self) -> usize;
|
||||
|
||||
/// Checks whether the command can be executed on the given queue family.
|
||||
// TODO: error type?
|
||||
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()>;
|
||||
|
||||
/// Returns the current status of a buffer, or `None` if the buffer hasn't been used yet.
|
||||
///
|
||||
/// Whether the buffer passed as parameter is the same as the one in the commands list must be
|
||||
/// determined with the `is_same` method of `TrackedBuffer`.
|
||||
///
|
||||
/// Calling this function tells the commands list that you are going to manage the
|
||||
/// synchronization that buffer yourself. Hence why the function is unsafe.
|
||||
///
|
||||
/// This function is not meant to be called, except when writing a wrapper around a
|
||||
/// commands list.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// - Panics if the state of that buffer has already been previously extracted.
|
||||
///
|
||||
unsafe fn extract_current_buffer_state<B>(&mut self, buffer: &B) -> Option<B::CommandListState>
|
||||
where B: TrackedBuffer;
|
||||
|
||||
/// Turns the commands list into a command buffer.
|
||||
///
|
||||
/// This function accepts additional arguments that will customize the output:
|
||||
///
|
||||
/// - `additional_elements` is a closure that must be called on the command buffer builder
|
||||
/// after it has finished building and before `final_transitions` are added.
|
||||
/// - `transitions` is a list of pipeline barriers accompanied by a command number. The
|
||||
/// pipeline barrier must happen after the given command number. Usually you want all the
|
||||
/// the command numbers to be inferior to `num_commands`.
|
||||
/// - `final_transitions` is a pipeline barrier that must be added at the end of the
|
||||
/// command buffer builder.
|
||||
unsafe fn raw_build<I, F>(self, additional_elements: F, transitions: I,
|
||||
final_transitions: PipelineBarrierBuilder) -> Self::Output
|
||||
where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
|
||||
I: Iterator<Item = (usize, PipelineBarrierBuilder)>;
|
||||
}
|
||||
|
||||
/// Extension trait for `StdCommandsList` that indicates that we're outside a render pass.
|
||||
pub unsafe trait OutsideRenderPass: StdCommandsList {}
|
240
vulkano/src/command_buffer/std/update_buffer.rs
Normal file
240
vulkano/src/command_buffer/std/update_buffer.rs
Normal file
@ -0,0 +1,240 @@
|
||||
// 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::any::Any;
|
||||
use std::iter;
|
||||
use std::iter::Empty;
|
||||
use std::sync::Arc;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use buffer::traits::CommandBufferState;
|
||||
use buffer::traits::CommandListState;
|
||||
use buffer::traits::PipelineBarrierRequest;
|
||||
use buffer::traits::TrackedBuffer;
|
||||
use command_buffer::std::StdCommandsList;
|
||||
use command_buffer::submit::CommandBuffer;
|
||||
use command_buffer::submit::SubmitInfo;
|
||||
use command_buffer::sys::PipelineBarrierBuilder;
|
||||
use command_buffer::sys::UnsafeCommandBuffer;
|
||||
use command_buffer::sys::UnsafeCommandBufferBuilder;
|
||||
use device::Queue;
|
||||
use instance::QueueFamily;
|
||||
use sync::AccessFlagBits;
|
||||
use sync::Fence;
|
||||
use sync::PipelineStages;
|
||||
use sync::Semaphore;
|
||||
|
||||
pub struct UpdateCommand<'a, L, B, D: ?Sized> where B: TrackedBuffer, L: StdCommandsList, D: 'static {
|
||||
previous: L,
|
||||
buffer: B,
|
||||
buffer_state: Option<B::CommandListState>,
|
||||
data: &'a D,
|
||||
transition: Option<PipelineBarrierRequest>,
|
||||
}
|
||||
|
||||
impl<'a, L, B, D: ?Sized> UpdateCommand<'a, L, B, D>
|
||||
where B: TrackedBuffer,
|
||||
L: StdCommandsList,
|
||||
D: Copy + 'static,
|
||||
{
|
||||
pub fn new(mut previous: L, buffer: B, data: &'a D) -> UpdateCommand<'a, L, B, D> {
|
||||
let stage = PipelineStages {
|
||||
transfer: true,
|
||||
.. PipelineStages::none()
|
||||
};
|
||||
|
||||
let access = AccessFlagBits {
|
||||
transfer_write: true,
|
||||
.. AccessFlagBits::none()
|
||||
};
|
||||
|
||||
let (state, transition) = unsafe {
|
||||
previous.extract_current_buffer_state(&buffer)
|
||||
.unwrap_or(buffer.initial_state())
|
||||
.transition(previous.num_commands() + 1, buffer.inner(),
|
||||
0, buffer.size(), true, stage, access)
|
||||
};
|
||||
|
||||
if let Some(ref transition) = transition {
|
||||
assert!(transition.after_command_num <= previous.num_commands());
|
||||
}
|
||||
|
||||
UpdateCommand {
|
||||
previous: previous,
|
||||
buffer: buffer,
|
||||
buffer_state: Some(state),
|
||||
data: data,
|
||||
transition: transition,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, L, B, D: ?Sized> StdCommandsList for UpdateCommand<'a, L, B, D>
|
||||
where B: TrackedBuffer,
|
||||
L: StdCommandsList,
|
||||
D: Copy + 'static,
|
||||
{
|
||||
type Pool = L::Pool;
|
||||
type Output = UpdateCommandCb<L, B>;
|
||||
|
||||
#[inline]
|
||||
fn num_commands(&self) -> usize {
|
||||
self.previous.num_commands() + 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
|
||||
// No restriction
|
||||
self.previous.check_queue_validity(queue)
|
||||
}
|
||||
|
||||
unsafe fn extract_current_buffer_state<Ob>(&mut self, buffer: &Ob)
|
||||
-> Option<Ob::CommandListState>
|
||||
where Ob: TrackedBuffer
|
||||
{
|
||||
if self.buffer.is_same(buffer) {
|
||||
let s: &mut Option<Ob::CommandListState> = (&mut self.buffer_state as &mut Any)
|
||||
.downcast_mut().unwrap();
|
||||
Some(s.take().unwrap())
|
||||
|
||||
} else {
|
||||
self.previous.extract_current_buffer_state(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn raw_build<I, F>(mut self, additional_elements: F, transitions: I,
|
||||
mut final_transitions: PipelineBarrierBuilder) -> Self::Output
|
||||
where F: FnOnce(&mut UnsafeCommandBufferBuilder<L::Pool>),
|
||||
I: Iterator<Item = (usize, PipelineBarrierBuilder)>
|
||||
{
|
||||
let finished_state = match self.buffer_state.take().map(|s| s.finish()) {
|
||||
Some((s, t)) => {
|
||||
if let Some(t) = t {
|
||||
final_transitions.add_buffer_barrier_request(self.buffer.inner(), t);
|
||||
}
|
||||
Some(s)
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
// We split the transitions in two: those to apply after the actual command, and those to
|
||||
// transfer to the parent so that they are applied before the actual command.
|
||||
|
||||
let my_command_num = self.num_commands();
|
||||
|
||||
let mut transitions_to_apply = PipelineBarrierBuilder::new();
|
||||
let mut transitions = transitions.filter_map(|(after_command_num, transition)| {
|
||||
if after_command_num >= my_command_num || !transitions_to_apply.is_empty() {
|
||||
transitions_to_apply.merge(transition);
|
||||
None
|
||||
} else {
|
||||
Some((after_command_num, transition))
|
||||
}
|
||||
}).collect::<SmallVec<[_; 8]>>();
|
||||
|
||||
let my_transition = if let Some(my_transition) = self.transition.take() {
|
||||
let mut t = PipelineBarrierBuilder::new();
|
||||
let c_num = my_transition.after_command_num;
|
||||
t.add_buffer_barrier_request(self.buffer.inner(), my_transition);
|
||||
Some((c_num, t))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let transitions = my_transition.into_iter().chain(transitions.into_iter());
|
||||
|
||||
let my_buffer = self.buffer;
|
||||
let my_data = self.data;
|
||||
let parent = self.previous.raw_build(|cb| {
|
||||
cb.update_buffer(my_buffer.inner(), 0, my_buffer.size(), my_data);
|
||||
cb.pipeline_barrier(transitions_to_apply);
|
||||
additional_elements(cb);
|
||||
}, transitions, final_transitions);
|
||||
|
||||
UpdateCommandCb {
|
||||
previous: parent,
|
||||
buffer: my_buffer,
|
||||
buffer_state: finished_state,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UpdateCommandCb<L, B> where B: TrackedBuffer, L: StdCommandsList {
|
||||
previous: L::Output,
|
||||
buffer: B,
|
||||
buffer_state: Option<B::FinishedState>,
|
||||
}
|
||||
|
||||
unsafe impl<L, B> CommandBuffer for UpdateCommandCb<L, B>
|
||||
where B: TrackedBuffer, L: StdCommandsList
|
||||
{
|
||||
type Pool = L::Pool;
|
||||
type SemaphoresWaitIterator = Empty<(Arc<Semaphore>, PipelineStages)>;
|
||||
type SemaphoresSignalIterator = Empty<Arc<Semaphore>>;
|
||||
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool> {
|
||||
self.previous.inner()
|
||||
}
|
||||
|
||||
unsafe fn on_submit<F>(&self, queue: &Arc<Queue>, mut fence: F)
|
||||
-> SubmitInfo<Self::SemaphoresWaitIterator,
|
||||
Self::SemaphoresSignalIterator>
|
||||
where F: FnMut() -> Arc<Fence>
|
||||
{
|
||||
let parent = self.previous.on_submit(queue, &mut fence);
|
||||
|
||||
let mut my_output = SubmitInfo {
|
||||
semaphores_wait: iter::empty(), // FIXME:
|
||||
semaphores_signal: iter::empty(), // FIXME:
|
||||
pre_pipeline_barrier: parent.pre_pipeline_barrier,
|
||||
post_pipeline_barrier: parent.post_pipeline_barrier,
|
||||
};
|
||||
|
||||
if let Some(ref buffer_state) = self.buffer_state {
|
||||
let submit_infos = buffer_state.on_submit(&self.buffer, queue, fence);
|
||||
|
||||
if let Some(pre) = submit_infos.pre_barrier {
|
||||
my_output.pre_pipeline_barrier.add_buffer_barrier_request(self.buffer.inner(), pre);
|
||||
}
|
||||
|
||||
if let Some(post) = submit_infos.post_barrier {
|
||||
my_output.post_pipeline_barrier.add_buffer_barrier_request(self.buffer.inner(), post);
|
||||
}
|
||||
}
|
||||
|
||||
my_output
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
use buffer::BufferUsage;
|
||||
use buffer::CpuAccessibleBuffer;
|
||||
use command_buffer::std::PrimaryCbBuilder;
|
||||
use command_buffer::std::StdCommandsList;
|
||||
use command_buffer::submit::CommandBuffer;
|
||||
|
||||
#[test]
|
||||
fn basic_submit() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
let buffer = CpuAccessibleBuffer::from_data(&device, &BufferUsage::transfer_dest(),
|
||||
Some(queue.family()), 0u32).unwrap();
|
||||
|
||||
let _ = PrimaryCbBuilder::new(&device, queue.family())
|
||||
.update_buffer(buffer.clone(), &128u32)
|
||||
.build()
|
||||
.submit(&queue);
|
||||
|
||||
let content = buffer.read(Duration::from_secs(0)).unwrap();
|
||||
assert_eq!(*content, 128);
|
||||
}
|
||||
}
|
@ -39,8 +39,9 @@ pub unsafe trait CommandBuffer {
|
||||
/// multiple command buffers at once instead.
|
||||
///
|
||||
/// This is a simple shortcut for creating a `Submit` object.
|
||||
// TODO: remove 'static
|
||||
#[inline]
|
||||
fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized {
|
||||
fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized + 'static {
|
||||
Submit::new().add(self).submit(queue)
|
||||
}
|
||||
|
||||
@ -80,10 +81,10 @@ pub unsafe trait CommandBuffer {
|
||||
/// The implementation must ensure that the command buffer doesn't get destroyed before the
|
||||
/// fence is signaled, or before a fence of a later submission to the same queue is signaled.
|
||||
///
|
||||
unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
|
||||
unsafe fn on_submit<F>(&self, queue: &Arc<Queue>, fence: F)
|
||||
-> SubmitInfo<Self::SemaphoresWaitIterator,
|
||||
Self::SemaphoresSignalIterator>
|
||||
where F: FnOnce() -> Arc<Fence>;
|
||||
where F: FnMut() -> Arc<Fence>;
|
||||
}
|
||||
|
||||
/// Information about how the submitting function should synchronize the submission.
|
||||
@ -163,8 +164,9 @@ impl<L> Submit<L> where L: SubmitList {
|
||||
/// In the Vulkan API, a submission is divided into batches that each contain one or more
|
||||
/// command buffers. Vulkano will automatically determine which command buffers can be grouped
|
||||
/// into the same batch.
|
||||
// TODO: remove 'static
|
||||
#[inline]
|
||||
pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
|
||||
pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer + 'static {
|
||||
Submit { list: (command_buffer, self.list) }
|
||||
}
|
||||
|
||||
@ -172,7 +174,7 @@ impl<L> Submit<L> where L: SubmitList {
|
||||
pub fn submit(self, queue: &Arc<Queue>) -> Submission {
|
||||
let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
|
||||
signal_semaphores, mut submits, keep_alive }
|
||||
= self.list.infos(queue.family().id(), queue.id_within_family());
|
||||
= self.list.infos(queue);
|
||||
|
||||
// TODO: for now we always create a Fence in order to put it in the submission
|
||||
let fence = fence.unwrap_or_else(|| Fence::new(queue.device().clone()));
|
||||
@ -238,11 +240,11 @@ pub struct SubmitListOpaque {
|
||||
}
|
||||
|
||||
pub unsafe trait SubmitList {
|
||||
fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
|
||||
fn infos(self, queue: &Arc<Queue>) -> SubmitListOpaque;
|
||||
}
|
||||
|
||||
unsafe impl SubmitList for () {
|
||||
fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
|
||||
fn infos(self, queue: &Arc<Queue>) -> SubmitListOpaque {
|
||||
SubmitListOpaque {
|
||||
fence: None,
|
||||
wait_semaphores: SmallVec::new(),
|
||||
@ -255,16 +257,16 @@ unsafe impl SubmitList for () {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
|
||||
fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
|
||||
// TODO: remove 'static
|
||||
unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer + 'static, R: SubmitList {
|
||||
fn infos(self, queue: &Arc<Queue>) -> SubmitListOpaque {
|
||||
// TODO: attempt to group multiple submits into one when possible
|
||||
|
||||
let (current, rest) = self;
|
||||
|
||||
let mut infos = rest.infos(queue_family, queue_within_family);
|
||||
let mut infos = rest.infos(queue);
|
||||
let device = current.inner().device().clone();
|
||||
let qf = device.physical_device().queue_family_by_id(queue_family).unwrap();
|
||||
let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
|
||||
let current_infos = unsafe { current.on_submit(queue, || {
|
||||
if let Some(fence) = infos.fence.as_ref() {
|
||||
return fence.clone();
|
||||
}
|
||||
@ -287,7 +289,7 @@ unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
|
||||
};
|
||||
|
||||
if !current_infos.pre_pipeline_barrier.is_empty() {
|
||||
let mut cb = UnsafeCommandBufferBuilder::new(Device::standard_command_pool(&device, qf),
|
||||
let mut cb = UnsafeCommandBufferBuilder::new(Device::standard_command_pool(&device, queue.family()),
|
||||
Kind::Primary::<EmptySinglePassRenderPass,
|
||||
EmptySinglePassRenderPass>,
|
||||
Flags::OneTimeSubmit).unwrap();
|
||||
@ -300,7 +302,7 @@ unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
|
||||
infos.command_buffers.push(current.inner().internal_object());
|
||||
|
||||
if !current_infos.post_pipeline_barrier.is_empty() {
|
||||
let mut cb = UnsafeCommandBufferBuilder::new(Device::standard_command_pool(&device, qf),
|
||||
let mut cb = UnsafeCommandBufferBuilder::new(Device::standard_command_pool(&device, queue.family()),
|
||||
Kind::Primary::<EmptySinglePassRenderPass,
|
||||
EmptySinglePassRenderPass>,
|
||||
Flags::OneTimeSubmit).unwrap();
|
||||
@ -324,6 +326,7 @@ unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
|
||||
}
|
||||
|
||||
infos.submits.push(new_submit);
|
||||
infos.keep_alive.push(Arc::new(current) as Arc<_>);
|
||||
|
||||
infos
|
||||
}
|
||||
@ -344,6 +347,7 @@ mod tests {
|
||||
use command_buffer::sys::UnsafeCommandBuffer;
|
||||
use command_buffer::sys::UnsafeCommandBufferBuilder;
|
||||
use device::Device;
|
||||
use device::Queue;
|
||||
use framebuffer::EmptySinglePassRenderPass;
|
||||
use sync::Fence;
|
||||
use sync::PipelineStages;
|
||||
@ -359,7 +363,7 @@ mod tests {
|
||||
|
||||
fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool> { &self.inner }
|
||||
|
||||
unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
|
||||
unsafe fn on_submit<F>(&self, _: &Arc<Queue>, fence: F)
|
||||
-> SubmitInfo<Self::SemaphoresWaitIterator,
|
||||
Self::SemaphoresSignalIterator>
|
||||
where F: FnOnce() -> Arc<Fence>
|
||||
|
@ -39,8 +39,10 @@ use smallvec::SmallVec;
|
||||
use buffer::Buffer;
|
||||
use buffer::BufferSlice;
|
||||
use buffer::sys::UnsafeBuffer;
|
||||
use buffer::traits::PipelineBarrierRequest as BufferPipelineBarrierRequest;
|
||||
use command_buffer::pool::AllocatedCommandBuffer;
|
||||
use command_buffer::pool::CommandPool;
|
||||
use command_buffer::pool::CommandPoolFinished;
|
||||
use descriptor::pipeline_layout::PipelineLayout;
|
||||
use descriptor::descriptor_set::UnsafeDescriptorSet;
|
||||
use descriptor::descriptor::ShaderStages;
|
||||
@ -302,7 +304,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
else { vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdClearColorImage(cmd, image.internal_object(), layout, &clear_value,
|
||||
ranges.len() as u32, ranges.as_ptr());
|
||||
}
|
||||
@ -399,7 +401,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
else { vk::IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdClearDepthStencilImage(cmd, image.internal_object(), layout, &clear_value,
|
||||
ranges.len() as u32, ranges.as_ptr());
|
||||
}
|
||||
@ -503,7 +505,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
}
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdClearAttachments(cmd, attachments.len() as u32, attachments.as_ptr(),
|
||||
rects.len() as u32, rects.as_ptr());
|
||||
}
|
||||
@ -543,7 +545,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
};
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdFillBuffer(cmd, buffer.internal_object(), offset as vk::DeviceSize,
|
||||
size as vk::DeviceSize, data);
|
||||
}
|
||||
@ -580,7 +582,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
debug_assert!(size <= 65536);
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdUpdateBuffer(cmd, buffer.internal_object(), offset as vk::DeviceSize,
|
||||
size as vk::DeviceSize, data as *const D as *const _);
|
||||
}
|
||||
@ -637,7 +639,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
}
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdCopyBuffer(cmd, src.internal_object(), dest.internal_object(), regions.len() as u32,
|
||||
regions.as_ptr());
|
||||
}
|
||||
@ -656,7 +658,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
}
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
|
||||
unsafe {
|
||||
vk.CmdPipelineBarrier(cmd, barrier.src_stage_mask, barrier.dst_stage_mask,
|
||||
@ -751,7 +753,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
};
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdBeginRenderPass(cmd, &infos,
|
||||
if secondary { vk::SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS }
|
||||
else { vk::SUBPASS_CONTENTS_INLINE });
|
||||
@ -767,7 +769,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
#[inline]
|
||||
pub unsafe fn next_subpass(&mut self, secondary: bool) {
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdNextSubpass(cmd, if secondary { vk::SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS }
|
||||
else { vk::SUBPASS_CONTENTS_INLINE });
|
||||
}
|
||||
@ -782,7 +784,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
#[inline]
|
||||
pub unsafe fn end_render_pass(&mut self) {
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdEndRenderPass(cmd);
|
||||
}
|
||||
|
||||
@ -799,7 +801,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
#[inline]
|
||||
pub unsafe fn bind_pipeline_graphics<V, L, R>(&mut self, pipeline: &GraphicsPipeline<V, L, R>) {
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdBindPipeline(cmd, vk::PIPELINE_BIND_POINT_GRAPHICS, pipeline.internal_object());
|
||||
}
|
||||
|
||||
@ -812,7 +814,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
#[inline]
|
||||
pub unsafe fn bind_pipeline_compute<L>(&mut self, pipeline: &ComputePipeline<L>) {
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdBindPipeline(cmd, vk::PIPELINE_BIND_POINT_COMPUTE, pipeline.internal_object());
|
||||
}
|
||||
|
||||
@ -822,7 +824,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
first_instance: u32)
|
||||
{
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdDraw(cmd, vertex_count, instance_count, first_vertex, first_instance);
|
||||
}
|
||||
|
||||
@ -832,7 +834,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
first_vertex: u32, vertex_offset: i32, first_instance: u32)
|
||||
{
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdDrawIndexed(cmd, vertex_count, instance_count, first_vertex, vertex_offset,
|
||||
first_instance);
|
||||
}
|
||||
@ -850,7 +852,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
assert_eq!(buffer.device().internal_object(), self.device.internal_object());
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdDrawIndirect(cmd, buffer.internal_object(), offset as vk::DeviceSize, draw_count,
|
||||
stride);
|
||||
}
|
||||
@ -868,7 +870,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
assert_eq!(buffer.device().internal_object(), self.device.internal_object());
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdDrawIndexedIndirect(cmd, buffer.internal_object(), offset as vk::DeviceSize,
|
||||
draw_count, stride);
|
||||
}
|
||||
@ -877,7 +879,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
#[inline]
|
||||
pub unsafe fn dispatch(&mut self, x: u32, y: u32, z: u32) {
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdDispatch(cmd, x, y, z);
|
||||
}
|
||||
|
||||
@ -892,7 +894,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
assert_eq!(buffer.device().internal_object(), self.device.internal_object());
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdDispatchIndirect(cmd, buffer.internal_object(), offset as vk::DeviceSize);
|
||||
}
|
||||
|
||||
@ -919,7 +921,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
}
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdBindVertexBuffers(cmd, first_binding, raw_buffers.len() as u32, raw_buffers.as_ptr(),
|
||||
raw_offsets.as_ptr());
|
||||
}
|
||||
@ -937,7 +939,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
assert_eq!(buffer.device().internal_object(), self.device.internal_object());
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdBindIndexBuffer(cmd, buffer.internal_object(), offset as vk::DeviceSize,
|
||||
index_ty as u32);
|
||||
}
|
||||
@ -972,7 +974,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
let dynamic_offsets: SmallVec<[_; 64]> = dynamic_offsets.into_iter().collect();
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdBindDescriptorSets(cmd, bind_point, layout.inner().internal_object(), first_set,
|
||||
descriptor_sets.len() as u32, descriptor_sets.as_ptr(),
|
||||
dynamic_offsets.len() as u32, dynamic_offsets.as_ptr());
|
||||
@ -995,7 +997,7 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
debug_assert!(mem::size_of_val(data) <= u32::MAX as usize);
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.take().unwrap();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdPushConstants(cmd, layout.inner().internal_object(), stages.into(), offset as u32,
|
||||
mem::size_of_val(data) as u32, data as *const D as *const _);
|
||||
}
|
||||
@ -1113,6 +1115,18 @@ impl PipelineBarrierBuilder {
|
||||
self.src_stage_mask == 0 || self.dst_stage_mask == 0
|
||||
}
|
||||
|
||||
/// Merges another pipeline builder into this one.
|
||||
#[inline]
|
||||
pub fn merge(&mut self, mut other: PipelineBarrierBuilder) {
|
||||
self.src_stage_mask |= other.src_stage_mask;
|
||||
self.dst_stage_mask |= other.dst_stage_mask;
|
||||
self.dependency_flags &= other.dependency_flags;
|
||||
|
||||
self.memory_barriers.extend(other.memory_barriers.into_iter());
|
||||
self.buffer_barriers.extend(other.buffer_barriers.into_iter());
|
||||
self.image_barriers.extend(other.image_barriers.into_iter());
|
||||
}
|
||||
|
||||
/// Adds an execution dependency. This means that all the stages in `source` of the previous
|
||||
/// commands must finish before any of the stages in `dest` of the following commands can start.
|
||||
///
|
||||
@ -1160,6 +1174,37 @@ impl PipelineBarrierBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
pub unsafe fn add_buffer_barrier_request(&mut self, buffer: &UnsafeBuffer,
|
||||
request: BufferPipelineBarrierRequest)
|
||||
{
|
||||
if !request.by_region {
|
||||
self.dependency_flags = 0;
|
||||
}
|
||||
|
||||
self.src_stage_mask |= request.source_stage.into();
|
||||
self.dst_stage_mask |= request.destination_stages.into();
|
||||
|
||||
if let Some(memory_barrier) = request.memory_barrier {
|
||||
let (src_queue, dest_queue) = /*if let Some((src_queue, dest_queue)) = queue_transfer {
|
||||
(src_queue, dest_queue)
|
||||
} else {*/
|
||||
(vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
|
||||
/*}*/;
|
||||
|
||||
self.buffer_barriers.push(vk::BufferMemoryBarrier {
|
||||
sType: vk::STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
pNext: ptr::null(),
|
||||
srcAccessMask: memory_barrier.source_access.into(),
|
||||
dstAccessMask: memory_barrier.destination_access.into(),
|
||||
srcQueueFamilyIndex: src_queue,
|
||||
dstQueueFamilyIndex: dest_queue,
|
||||
buffer: buffer.internal_object(),
|
||||
offset: memory_barrier.offset as vk::DeviceSize,
|
||||
size: memory_barrier.size as vk::DeviceSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a buffer memory barrier. This means that all the memory writes to the given buffer by
|
||||
/// the given source stages for the given source accesses must be visible by the given dest
|
||||
/// stages for the given dest accesses.
|
||||
@ -1306,3 +1351,12 @@ unsafe impl<P> VulkanObject for UnsafeCommandBuffer<P> where P: CommandPool {
|
||||
self.cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> Drop for UnsafeCommandBuffer<P> where P: CommandPool {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.pool.free(self.secondary_cb, Some(self.cmd.into()).into_iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user