Add documentation to the update buffer and empty modules

This commit is contained in:
Pierre Krieger 2016-08-17 18:58:51 +02:00
parent 3ca46f2348
commit 0e887544e8
3 changed files with 70 additions and 48 deletions

View File

@ -85,22 +85,26 @@ unsafe impl<P> StdCommandsList for PrimaryCbBuilder<P> where P: CommandPool {
None
}
unsafe fn raw_build<I, F>(self, additional_elements: F, transitions: I,
final_transitions: PipelineBarrierBuilder) -> Self::Output
unsafe fn raw_build<I, F>(self, additional_elements: F, barriers: I,
final_barrier: 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
self.flags).unwrap(); // TODO: handle error
// Since we're at the start of the command buffer, there's no need wonder when to add the
// barriers. We have no choice but to add them immediately.
let mut pipeline_barrier = PipelineBarrierBuilder::new();
for (_, barrier) in barriers {
pipeline_barrier.merge(barrier);
}
cb.pipeline_barrier(pipeline_barrier);
// Then add the rest.
additional_elements(&mut cb);
cb.pipeline_barrier(final_transitions);
cb.pipeline_barrier(final_barrier);
PrimaryCb {
cb: cb.build().unwrap(), // TODO: handle error
@ -129,7 +133,9 @@ unsafe impl<P> CommandBuffer for PrimaryCb<P> where P: CommandPool {
Self::SemaphoresSignalIterator>
where F: FnMut() -> Arc<Fence>
{
// TODO: must handle SimultaneousUse and Once flags
// TODO: Must handle non-SimultaneousUse and Once flags ; for now the `SimultaneousUse`
// flag is mandatory, so there's no safety issue. However it will need to be handled
// before allowing other flags to be used.
SubmitInfo {
semaphores_wait: iter::empty(),

View File

@ -93,14 +93,14 @@ pub unsafe trait StdCommandsList {
/// 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
/// after it has finished building and before `final_barrier` are added.
/// - `barriers` 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
/// - `final_barrier` 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
unsafe fn raw_build<I, F>(self, additional_elements: F, barriers: I,
final_barrier: PipelineBarrierBuilder) -> Self::Output
where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
I: Iterator<Item = (usize, PipelineBarrierBuilder)>;
}

View File

@ -32,12 +32,20 @@ use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;
pub struct UpdateCommand<'a, L, B, D: ?Sized> where B: TrackedBuffer, L: StdCommandsList, D: 'static {
/// Wraps around a commands list and adds an update buffer command at the end of it.
pub struct UpdateCommand<'a, L, B, D: ?Sized>
where B: TrackedBuffer, L: StdCommandsList, D: 'static
{
// Parent commands list.
previous: L,
// The buffer to update.
buffer: B,
// Current state of the buffer to update, or `None` if it has been extracted.
buffer_state: Option<B::CommandListState>,
// The data to write to the buffer.
data: &'a D,
transition: Option<PipelineBarrierRequest>,
// Pipeline barrier to perform before this command.
barrier: Option<PipelineBarrierRequest>,
}
impl<'a, L, B, D: ?Sized> UpdateCommand<'a, L, B, D>
@ -45,26 +53,23 @@ impl<'a, L, B, D: ?Sized> UpdateCommand<'a, L, B, D>
L: StdCommandsList + OutsideRenderPass,
D: Copy + 'static,
{
/// See the documentation of the `update_buffer` method.
pub fn new(mut previous: L, buffer: B, data: &'a D) -> UpdateCommand<'a, L, B, D> {
let stage = PipelineStages {
transfer: true,
.. PipelineStages::none()
};
// Determining the new state of the buffer, and the optional pipeline barrier to add
// before our command in the final output.
let (state, barrier) = unsafe {
let stage = PipelineStages { transfer: true, .. PipelineStages::none() };
let access = AccessFlagBits { transfer_write: true, .. AccessFlagBits::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());
// Minor safety check.
if let Some(ref barrier) = barrier {
assert!(barrier.after_command_num <= previous.num_commands());
}
UpdateCommand {
@ -72,7 +77,7 @@ impl<'a, L, B, D: ?Sized> UpdateCommand<'a, L, B, D>
buffer: buffer,
buffer_state: Some(state),
data: data,
transition: transition,
barrier: barrier,
}
}
}
@ -123,54 +128,58 @@ unsafe impl<'a, L, B, D: ?Sized> StdCommandsList for UpdateCommand<'a, L, B, D>
}
}
unsafe fn raw_build<I, F>(mut self, additional_elements: F, transitions: I,
mut final_transitions: PipelineBarrierBuilder) -> Self::Output
unsafe fn raw_build<I, F>(mut self, additional_elements: F, barriers: I,
mut final_barrier: PipelineBarrierBuilder) -> Self::Output
where F: FnOnce(&mut UnsafeCommandBufferBuilder<L::Pool>),
I: Iterator<Item = (usize, PipelineBarrierBuilder)>
{
// Computing the finished state, or `None` if we don't have to manage it.
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);
final_barrier.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.
// We split the barriers in two: those to apply after our command, and those to
// transfer to the parent so that they are applied before our command.
let my_command_num = self.num_commands();
// The transitions to apply immediately after our command.
let mut transitions_to_apply = PipelineBarrierBuilder::new();
let mut transitions = transitions.filter_map(|(after_command_num, transition)| {
// The barriers to transfer to the parent.
let mut barriers = barriers.filter_map(|(after_command_num, barrier)| {
if after_command_num >= my_command_num || !transitions_to_apply.is_empty() {
transitions_to_apply.merge(transition);
transitions_to_apply.merge(barrier);
None
} else {
Some((after_command_num, transition))
Some((after_command_num, barrier))
}
}).collect::<SmallVec<[_; 8]>>();
let my_transition = if let Some(my_transition) = self.transition.take() {
// The local barrier requested by this command, or `None` if no barrier requested.
let my_barrier = if let Some(my_barrier) = self.barrier.take() {
let mut t = PipelineBarrierBuilder::new();
let c_num = my_transition.after_command_num;
t.add_buffer_barrier_request(self.buffer.inner(), my_transition);
let c_num = my_barrier.after_command_num;
t.add_buffer_barrier_request(self.buffer.inner(), my_barrier);
Some((c_num, t))
} else {
None
};
let transitions = my_transition.into_iter().chain(transitions.into_iter());
// Passing to the parent.
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);
}, my_barrier.into_iter().chain(barriers.into_iter()), final_barrier);
UpdateCommandCb {
previous: parent,
@ -180,9 +189,14 @@ unsafe impl<'a, L, B, D: ?Sized> StdCommandsList for UpdateCommand<'a, L, B, D>
}
}
/// Wraps around a command buffer and adds an update buffer command at the end of it.
pub struct UpdateCommandCb<L, B> where B: TrackedBuffer, L: StdCommandsList {
// The previous commands.
previous: L::Output,
// The buffer to update.
buffer: B,
// The state of the buffer to update, or `None` if we don't manage it. Will be used to
// determine which semaphores or barriers to add when submitting.
buffer_state: Option<B::FinishedState>,
}
@ -203,9 +217,11 @@ unsafe impl<L, B> CommandBuffer for UpdateCommandCb<L, B>
Self::SemaphoresSignalIterator>
where F: FnMut() -> Arc<Fence>
{
// We query the parent.
let parent = self.previous.on_submit(queue, &mut fence);
let mut my_output = SubmitInfo {
// Then build our own output that modifies the parent's.
let mut out = SubmitInfo {
semaphores_wait: iter::empty(), // FIXME:
semaphores_signal: iter::empty(), // FIXME:
pre_pipeline_barrier: parent.pre_pipeline_barrier,
@ -216,15 +232,15 @@ unsafe impl<L, B> CommandBuffer for UpdateCommandCb<L, B>
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);
out.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);
out.post_pipeline_barrier.add_buffer_barrier_request(self.buffer.inner(), post);
}
}
my_output
out
}
}