mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-23 15:24:25 +00:00
Draft for execute()
This commit is contained in:
parent
7a4cac1792
commit
57d2a39685
213
vulkano/src/command_buffer/std/execute.rs
Normal file
213
vulkano/src/command_buffer/std/execute.rs
Normal file
@ -0,0 +1,213 @@
|
||||
// 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::sync::Arc;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use buffer::traits::TrackedBuffer;
|
||||
use command_buffer::std::InsideRenderPass;
|
||||
use command_buffer::std::OutsideRenderPass;
|
||||
use command_buffer::std::ResourcesStates;
|
||||
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 image::traits::TrackedImage;
|
||||
use instance::QueueFamily;
|
||||
use pipeline::ComputePipeline;
|
||||
use pipeline::GraphicsPipeline;
|
||||
use sync::Fence;
|
||||
|
||||
/// Wraps around a commands list and adds a command at the end of it that executes a secondary
|
||||
/// command buffer.
|
||||
pub struct ExecuteCommand<Cb, L> where Cb: CommandBuffer, L: StdCommandsList {
|
||||
// Parent commands list.
|
||||
previous: L,
|
||||
// Command buffer to execute.
|
||||
command_buffer: Cb,
|
||||
}
|
||||
|
||||
impl<Cb, L> ExecuteCommand<Cb, L>
|
||||
where Cb: CommandBuffer, L: StdCommandsList
|
||||
{
|
||||
/// See the documentation of the `execute` method.
|
||||
#[inline]
|
||||
pub fn new(previous: L, command_buffer: Cb) -> ExecuteCommand<Cb, L> {
|
||||
// FIXME: check that the number of subpasses is correct
|
||||
|
||||
ExecuteCommand {
|
||||
previous: previous,
|
||||
command_buffer: command_buffer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: specialize `execute()` so that multiple calls to `execute` are grouped together
|
||||
unsafe impl<Cb, L> StdCommandsList for ExecuteCommand<Cb, L>
|
||||
where Cb: CommandBuffer, L: StdCommandsList
|
||||
{
|
||||
type Pool = L::Pool;
|
||||
type Output = ExecuteCommandCb<Cb, L::Output>;
|
||||
|
||||
#[inline]
|
||||
fn num_commands(&self) -> usize {
|
||||
self.previous.num_commands() + 1
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
|
||||
// FIXME: check the secondary cb's queue validity
|
||||
self.previous.check_queue_validity(queue)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn buildable_state(&self) -> bool {
|
||||
self.previous.buildable_state()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_compute_pipeline_bound<Pl>(&self, pipeline: &Arc<ComputePipeline<Pl>>) -> bool {
|
||||
// Bindings are always invalidated after a execute command ends.
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_graphics_pipeline_bound<Pv, Pl, Prp>(&self, pipeline: &Arc<GraphicsPipeline<Pv, Pl, Prp>>)
|
||||
-> bool
|
||||
{
|
||||
// Bindings are always invalidated after a execute command ends.
|
||||
false
|
||||
}
|
||||
|
||||
unsafe fn raw_build<I, F>(self, additional_elements: F, barriers: I,
|
||||
final_barrier: PipelineBarrierBuilder) -> Self::Output
|
||||
where F: FnOnce(&mut UnsafeCommandBufferBuilder<L::Pool>),
|
||||
I: Iterator<Item = (usize, PipelineBarrierBuilder)>
|
||||
{
|
||||
// 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();
|
||||
|
||||
// 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(barrier);
|
||||
None
|
||||
} else {
|
||||
Some((after_command_num, barrier))
|
||||
}
|
||||
}).collect::<SmallVec<[_; 8]>>();
|
||||
|
||||
// Passing to the parent.
|
||||
let parent = {
|
||||
let local_cb_to_exec = self.command_buffer.inner();
|
||||
self.previous.raw_build(|cb| {
|
||||
cb.execute_commands(Some(local_cb_to_exec));
|
||||
cb.pipeline_barrier(transitions_to_apply);
|
||||
additional_elements(cb);
|
||||
}, barriers.into_iter(), final_barrier)
|
||||
};
|
||||
|
||||
ExecuteCommandCb {
|
||||
previous: parent,
|
||||
command_buffer: self.command_buffer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Cb, L> ResourcesStates for ExecuteCommand<Cb, L>
|
||||
where Cb: CommandBuffer, L: StdCommandsList
|
||||
{
|
||||
#[inline]
|
||||
unsafe fn extract_buffer_state<Ob>(&mut self, buffer: &Ob)
|
||||
-> Option<Ob::CommandListState>
|
||||
where Ob: TrackedBuffer
|
||||
{
|
||||
// FIXME:
|
||||
self.previous.extract_buffer_state(buffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn extract_image_state<I>(&mut self, image: &I) -> Option<I::CommandListState>
|
||||
where I: TrackedImage
|
||||
{
|
||||
// FIXME:
|
||||
self.previous.extract_image_state(image)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Cb, L> InsideRenderPass for ExecuteCommand<Cb, L>
|
||||
where Cb: CommandBuffer, L: InsideRenderPass
|
||||
{
|
||||
type RenderPass = L::RenderPass;
|
||||
type Framebuffer = L::Framebuffer;
|
||||
|
||||
#[inline]
|
||||
fn current_subpass(&self) -> u32 {
|
||||
self.previous.current_subpass()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn secondary_subpass(&self) -> bool {
|
||||
debug_assert!(self.previous.secondary_subpass());
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn render_pass(&self) -> &Arc<Self::RenderPass> {
|
||||
self.previous.render_pass()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn framebuffer(&self) -> &Self::Framebuffer {
|
||||
self.previous.framebuffer()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Cb, L> OutsideRenderPass for ExecuteCommand<Cb, L>
|
||||
where Cb: CommandBuffer, L: OutsideRenderPass
|
||||
{
|
||||
}
|
||||
|
||||
/// Wraps around a command buffer and adds an execute command at the end of it.
|
||||
pub struct ExecuteCommandCb<Cb, L> where Cb: CommandBuffer, L: CommandBuffer {
|
||||
// The previous commands.
|
||||
previous: L,
|
||||
// The secondary command buffer to execute.
|
||||
command_buffer: Cb,
|
||||
}
|
||||
|
||||
unsafe impl<Cb, L> CommandBuffer for ExecuteCommandCb<Cb, L>
|
||||
where Cb: CommandBuffer, L: CommandBuffer
|
||||
{
|
||||
type Pool = L::Pool;
|
||||
type SemaphoresWaitIterator = L::SemaphoresWaitIterator;
|
||||
type SemaphoresSignalIterator = L::SemaphoresSignalIterator;
|
||||
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool> {
|
||||
self.previous.inner()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn on_submit<F>(&self, queue: &Arc<Queue>, mut fence: F)
|
||||
-> SubmitInfo<Self::SemaphoresWaitIterator,
|
||||
Self::SemaphoresSignalIterator>
|
||||
where F: FnMut() -> Arc<Fence>
|
||||
{
|
||||
self.previous.on_submit(queue, &mut fence)
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ pub use self::empty::PrimaryCbBuilder;
|
||||
pub mod dispatch;
|
||||
pub mod draw;
|
||||
pub mod empty;
|
||||
pub mod execute;
|
||||
pub mod fill_buffer;
|
||||
pub mod render_pass;
|
||||
pub mod update_buffer;
|
||||
@ -63,6 +64,21 @@ pub unsafe trait StdCommandsList: ResourcesStates {
|
||||
fill_buffer::FillCommand::new(self, buffer, data)
|
||||
}
|
||||
|
||||
/// Adds a command that executes a secondary command buffer.
|
||||
///
|
||||
/// When you create a command buffer, you have the possibility to create either a primary
|
||||
/// command buffer or a secondary command buffer. Secondary command buffers can't be executed
|
||||
/// directly, but can be executed from a primary command buffer.
|
||||
///
|
||||
/// A secondary command buffer can't execute another secondary command buffer. The only way
|
||||
/// you can use `execute` is to make a primary command buffer call a secondary command buffer.
|
||||
#[inline]
|
||||
fn execute<Cb>(self, command_buffer: Cb) -> execute::ExecuteCommand<Cb, Self>
|
||||
where Self: Sized, Cb: CommandBuffer
|
||||
{
|
||||
execute::ExecuteCommand::new(self, command_buffer)
|
||||
}
|
||||
|
||||
/// Adds a command that executes a compute shader.
|
||||
///
|
||||
/// The `dimensions` are the number of working groups to start. The GPU will execute the
|
||||
|
@ -644,6 +644,23 @@ impl<P> UnsafeCommandBufferBuilder<P> where P: CommandPool {
|
||||
regions.as_ptr());
|
||||
}
|
||||
|
||||
/// Executes secondary command buffers..
|
||||
// TODO: check for same device
|
||||
// TODO: allow multiple command buffers from different pools
|
||||
pub unsafe fn execute_commands<'sec, I, SecP: 'sec>(&mut self, command_buffers: I)
|
||||
where I: IntoIterator<Item = &'sec UnsafeCommandBuffer<SecP>>,
|
||||
SecP: CommandPool
|
||||
{
|
||||
let raw_cbs: SmallVec<[_; 16]> = command_buffers.into_iter().map(|cb| {
|
||||
debug_assert!(cb.secondary_cb);
|
||||
cb.cmd
|
||||
}).collect();
|
||||
|
||||
let vk = self.device.pointers();
|
||||
let cmd = self.cmd.clone().take().unwrap();
|
||||
vk.CmdExecuteCommands(cmd, raw_cbs.len() as u32, raw_cbs.as_ptr());
|
||||
}
|
||||
|
||||
/// Adds a pipeline barrier to the command buffer.
|
||||
///
|
||||
/// This function itself is not unsafe, but creating a pipeline barrier builder is.
|
||||
|
Loading…
Reference in New Issue
Block a user