mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 23:05:43 +00:00
Rework CmdDispatch
This commit is contained in:
parent
4c6e879dbb
commit
61ef92563f
@ -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
|
||||
},
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user