Rework CmdDispatch

This commit is contained in:
Pierre Krieger 2016-11-10 13:39:08 +01:00
parent 4c6e879dbb
commit 61ef92563f
2 changed files with 49 additions and 208 deletions

View File

@ -11,14 +11,17 @@ use std::iter;
use std::sync::Arc;
use smallvec::SmallVec;
use command_buffer::DynamicState;
use command_buffer::StatesManager;
use command_buffer::SubmitInfo;
use command_buffer::cmd::CommandsListPossibleOutsideRenderPass;
use command_buffer::cmd::CommandsList;
use command_buffer::cmd::CommandsListConcrete;
use command_buffer::cmd::CommandsListOutput;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use command_buffer::cmd::CmdBindDescriptorSets;
use command_buffer::cmd::CmdBindPipeline;
use command_buffer::cmd::CmdBindVertexBuffers;
use command_buffer::cmd::CmdPushConstants;
use command_buffer::cmd::CmdSetState;
use command_buffer::RawCommandBufferPrototype;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use descriptor::PipelineLayoutRef;
use descriptor::descriptor::ShaderStages;
use descriptor::descriptor_set::collection::TrackedDescriptorSetsCollection;
@ -26,226 +29,63 @@ use device::Device;
use device::Queue;
use instance::QueueFamily;
use pipeline::ComputePipeline;
use pipeline::vertex::Source;
use sync::Fence;
use VulkanObject;
use VulkanPointers;
use vk;
/// Wraps around a commands list and adds a dispatch command at the end of it.
pub struct DispatchCommand<'a, L, Pl, S, Pc>
where L: CommandsList, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection, Pc: 'a
pub struct CmdDispatch<L, Pl, S, Pc>
where L: CommandsList, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection
{
// Parent commands list.
previous: L,
// The compute pipeline.
pipeline: Arc<ComputePipeline<Pl>>,
// The descriptor sets to bind.
sets: S,
// Pipeline barrier to inject in the final command buffer.
pipeline_barrier: (usize, PipelineBarrierBuilder),
// The push constants. TODO: use Cow
push_constants: &'a Pc,
previous: CmdPushConstants<
CmdBindDescriptorSets<
CmdBindPipeline<L, Arc<ComputePipeline<Pl>>>,
S, Arc<ComputePipeline<Pl>>
>,
Pc, Arc<ComputePipeline<Pl>>
>,
// Dispatch dimensions.
dimensions: [u32; 3],
// States of the resources, or `None` if it has been extracted.
resources_states: Option<StatesManager>,
}
impl<'a, L, Pl, S, Pc> DispatchCommand<'a, L, Pl, S, Pc>
where L: CommandsList + CommandsListPossibleOutsideRenderPass,
Pl: PipelineLayoutRef,
S: TrackedDescriptorSetsCollection, Pc: 'a
impl<L, Pl, S, Pc> CmdDispatch<L, Pl, S, Pc>
where L: CommandsList, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection
{
/// See the documentation of the `dispatch` method.
pub fn new(mut previous: L, pipeline: Arc<ComputePipeline<Pl>>, sets: S, dimensions: [u32; 3],
push_constants: &'a Pc) -> DispatchCommand<'a, L, Pl, S, Pc>
pub fn new(previous: L, pipeline: Arc<ComputePipeline<Pl>>, sets: S, dimensions: [u32; 3],
push_constants: Pc) -> CmdDispatch<L, Pl, S, Pc>
{
assert!(previous.is_outside_render_pass());
let previous = CmdBindPipeline::bind_compute_pipeline(previous, pipeline.clone());
let device = previous.device().clone();
let previous = CmdBindDescriptorSets::new(previous, false, pipeline.clone(), sets).unwrap() /* TODO: error */;
let previous = CmdPushConstants::new(previous, pipeline.clone(), push_constants).unwrap() /* TODO: error */;
let mut states = previous.extract_states();
// TODO: check dimensions limits
let (barrier_loc, barrier) = unsafe {
sets.transition(&mut states)
};
DispatchCommand {
CmdDispatch {
previous: previous,
pipeline: pipeline,
sets: sets,
pipeline_barrier: (barrier_loc, barrier),
push_constants: push_constants,
dimensions: dimensions,
resources_states: Some(states),
}
}
}
unsafe impl<'a, L, Pl, S, Pc> CommandsList for DispatchCommand<'a, L, Pl, S, Pc>
where L: CommandsList, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection, Pc: 'a
unsafe impl<L, Pl, S, Pc> CommandsList for CmdDispatch<L, Pl, S, Pc>
where L: CommandsList, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection
{
#[inline]
fn num_commands(&self) -> usize {
self.previous.num_commands() + 1
}
fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>) {
self.previous.append(builder);
#[inline]
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
if !queue.supports_compute() {
return Err(());
}
self.previous.check_queue_validity(queue)
}
#[inline]
fn is_compute_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool {
self.pipeline.internal_object() == pipeline
}
#[inline]
fn is_graphics_pipeline_bound(&self, pipeline: vk::Pipeline) -> bool {
self.previous.is_graphics_pipeline_bound(pipeline)
}
#[inline]
fn extract_states(&mut self) -> StatesManager {
self.resources_states.take().unwrap()
}
#[inline]
fn buildable_state(&self) -> bool {
true
}
}
unsafe impl<'a, L, Pl, S, Pc> CommandsListConcrete for DispatchCommand<'a, L, Pl, S, Pc>
where L: CommandsListConcrete, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection, Pc: 'a
{
type Pool = L::Pool;
type Output = DispatchCommandCb<L::Output, Pl, S>;
unsafe fn raw_build<I, F>(self, in_s: &mut StatesManager, out: &mut StatesManager,
additional_elements: F, barriers: I,
mut final_barrier: PipelineBarrierBuilder) -> Self::Output
where F: FnOnce(&mut UnsafeCommandBufferBuilder<L::Pool>),
I: Iterator<Item = (usize, PipelineBarrierBuilder)>
{
let my_command_num = self.num_commands();
// Computing the finished state of the sets.
final_barrier.merge(self.sets.finish(in_s, out));
// 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.
// The transitions to apply immediately after our command.
let mut transitions_to_apply = PipelineBarrierBuilder::new();
// The barriers to transfer to the parent.
let barriers = barriers.filter_map(|(after_command_num, barrier)| {
if after_command_num >= my_command_num || !transitions_to_apply.is_empty() {
transitions_to_apply.merge(barrier);
None
} else {
Some((after_command_num, barrier))
builder.add_command(Box::new(move |raw: &mut RawCommandBufferPrototype| {
unsafe {
let vk = raw.device.pointers();
let cmd = raw.command_buffer.clone().take().unwrap();
vk.CmdDispatch(cmd, self.dimensions[0], self.dimensions[1], self.dimensions[2]);
}
}).collect::<SmallVec<[_; 8]>>();
// Moving out some values, otherwise Rust complains that the closure below uses `self`
// while it's partially moved out.
let my_barrier = self.pipeline_barrier;
let my_pipeline = self.pipeline;
let my_sets = self.sets;
let my_push_constants = self.push_constants;
let my_dimensions = self.dimensions;
let bind_pipeline = !self.previous.is_compute_pipeline_bound(my_pipeline.internal_object());
// Passing to the parent.
let parent = self.previous.raw_build(in_s, out, |cb| {
// TODO: is the pipeline layout always the same as in the compute pipeline?
if bind_pipeline {
cb.bind_pipeline_compute(&my_pipeline);
}
cb.bind_descriptor_sets(false, my_pipeline.layout(), 0, // TODO: shouldn't unwrap
(0 .. my_sets.num_sets()).map(|n| my_sets.descriptor_set(n).unwrap()), iter::empty()); // TODO: dynamic ranges, and don't bind if not necessary
cb.push_constants(my_pipeline.layout(), ShaderStages::all(), 0, // TODO: stages
&my_push_constants);
cb.dispatch(my_dimensions[0], my_dimensions[1], my_dimensions[2]);
cb.pipeline_barrier(transitions_to_apply);
additional_elements(cb);
}, Some(my_barrier).into_iter().chain(barriers.into_iter()), final_barrier);
DispatchCommandCb {
previous: parent,
pipeline: my_pipeline,
sets: my_sets,
}
}
}
unsafe impl<'a, L, Pl, S, Pc> CommandsListPossibleOutsideRenderPass for DispatchCommand<'a, L, Pl, S, Pc>
where L: CommandsList, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection, Pc: 'a
{
#[inline]
fn is_outside_render_pass(&self) -> bool {
true
}
}
/// Wraps around a command buffer and adds an update buffer command at the end of it.
pub struct DispatchCommandCb<L, Pl, S>
where L: CommandsListOutput, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection
{
// The previous commands.
previous: L,
// The barrier. We store it here to keep it alive.
pipeline: Arc<ComputePipeline<Pl>>,
// The descriptor sets. Stored here to keep them alive.
sets: S,
}
unsafe impl<L, Pl, S> CommandsListOutput for DispatchCommandCb<L, Pl, S>
where L: CommandsListOutput, Pl: PipelineLayoutRef, S: TrackedDescriptorSetsCollection
{
#[inline]
fn inner(&self) -> vk::CommandBuffer {
self.previous.inner()
}
#[inline]
fn device(&self) -> &Arc<Device> {
self.previous.device()
}
unsafe fn on_submit(&self, states: &StatesManager, queue: &Arc<Queue>,
fence: &mut FnMut() -> Arc<Fence>) -> SubmitInfo
{
// We query the parent.
let mut parent = self.previous.on_submit(states, queue, fence);
// We query our sets.
let my_infos = self.sets.on_submit(states, queue, fence);
// We merge the two.
SubmitInfo {
semaphores_wait: {
parent.semaphores_wait.extend(my_infos.semaphores_wait.into_iter());
parent.semaphores_wait
},
semaphores_signal: {
parent.semaphores_signal.extend(my_infos.semaphores_signal.into_iter());
parent.semaphores_signal
},
pre_pipeline_barrier: {
let mut b = parent.pre_pipeline_barrier;
b.merge(my_infos.pre_pipeline_barrier);
b
},
post_pipeline_barrier: {
let mut b = parent.post_pipeline_barrier;
b.merge(my_infos.post_pipeline_barrier);
b
},
}
}));
}
}

View File

@ -45,6 +45,7 @@ pub use self::bind_vertex_buffers::CmdBindVertexBuffers;
pub use self::blit_image_unsynced::{BlitRegion, BlitRegionAspect};
pub use self::blit_image_unsynced::{CmdBlitImageUnsynced, CmdBlitImageUnsyncedError};
pub use self::copy_buffer::{CmdCopyBuffer, CmdCopyBufferError};
pub use self::dispatch::CmdDispatch;
pub use self::draw::CmdDraw;
pub use self::empty::{empty, EmptyCommandsList};
pub use self::end_render_pass::CmdEndRenderPass;
@ -61,7 +62,7 @@ mod bind_pipeline;
mod bind_vertex_buffers;
mod blit_image_unsynced;
mod copy_buffer;
pub mod dispatch;
mod dispatch;
mod draw;
mod empty;
mod end_render_pass;
@ -131,13 +132,13 @@ pub unsafe trait CommandsList {
/// The `pipeline` is the compute pipeline that will be executed, and the sets and push
/// constants will be accessible to all the invocations.
#[inline]
fn dispatch<'a, Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
dimensions: [u32; 3], push_constants: &'a Pc)
-> dispatch::DispatchCommand<'a, Self, Pl, S, Pc>
where Self: Sized + CommandsList + CommandsListPossibleOutsideRenderPass, Pl: PipelineLayoutRef,
S: TrackedDescriptorSetsCollection, Pc: 'a
fn dispatch<Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
dimensions: [u32; 3], push_constants: Pc)
-> CmdDispatch<Self, Pl, S, Pc>
where Self: Sized + CommandsList, Pl: PipelineLayoutRef,
S: TrackedDescriptorSetsCollection
{
dispatch::DispatchCommand::new(self, pipeline, sets, dimensions, push_constants)
CmdDispatch::new(self, pipeline, sets, dimensions, push_constants)
}
/// Adds a command that starts a render pass.