Merge pull request #222 from tomaka/render-pass

Add begin_render_pass(), next_subpass() and end_render_pass() with the new system
This commit is contained in:
tomaka 2016-08-19 17:43:15 +02:00 committed by GitHub
commit 82f9c0096b
5 changed files with 522 additions and 10 deletions

View File

@ -116,6 +116,11 @@ unsafe impl<'a, L, Pl, S, Pc> StdCommandsList for DispatchCommand<'a, L, Pl, S,
self.previous.extract_current_image_state(image)
}
#[inline]
fn buildable_state(&self) -> bool {
true
}
unsafe fn raw_build<I, F>(self, additional_elements: F, barriers: I,
mut final_barrier: PipelineBarrierBuilder) -> Self::Output
where F: FnOnce(&mut UnsafeCommandBufferBuilder<L::Pool>),

View File

@ -85,6 +85,11 @@ unsafe impl<P> StdCommandsList for PrimaryCbBuilder<P> where P: CommandPool {
None
}
#[inline]
fn buildable_state(&self) -> bool {
true
}
unsafe fn raw_build<I, F>(self, additional_elements: F, barriers: I,
final_barrier: PipelineBarrierBuilder) -> Self::Output
where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),

View File

@ -17,19 +17,20 @@ use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBufferBuilder;
use descriptor::PipelineLayout;
use descriptor::descriptor_set::collection::TrackedDescriptorSetsCollection;
use framebuffer::Framebuffer;
use framebuffer::RenderPass;
use framebuffer::RenderPassClearValues;
use image::traits::TrackedImage;
use instance::QueueFamily;
use pipeline::ComputePipeline;
pub use self::dispatch::DispatchCommand;
pub use self::empty::PrimaryCb;
pub use self::empty::PrimaryCbBuilder;
pub use self::update_buffer::UpdateCommand;
mod dispatch;
mod empty;
mod update_buffer;
pub mod dispatch;
pub mod empty;
pub mod render_pass;
pub mod update_buffer;
/// A list of commands that can be turned into a command buffer.
pub unsafe trait StdCommandsList {
@ -43,10 +44,10 @@ pub unsafe trait StdCommandsList {
/// 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>
-> update_buffer::UpdateCommand<'a, Self, B, D>
where Self: Sized + OutsideRenderPass, B: TrackedBuffer, D: Copy + 'static
{
UpdateCommand::new(self, buffer, data)
update_buffer::UpdateCommand::new(self, buffer, data)
}
/// Adds a command that executes a compute shader.
@ -59,15 +60,56 @@ pub unsafe trait StdCommandsList {
#[inline]
fn dispatch<'a, Pl, S, Pc>(self, pipeline: Arc<ComputePipeline<Pl>>, sets: S,
dimensions: [u32; 3], push_constants: &'a Pc)
-> DispatchCommand<'a, Self, Pl, S, Pc>
-> dispatch::DispatchCommand<'a, Self, Pl, S, Pc>
where Self: Sized + StdCommandsList + OutsideRenderPass, Pl: PipelineLayout,
S: TrackedDescriptorSetsCollection, Pc: 'a
{
DispatchCommand::new(self, pipeline, sets, dimensions, push_constants)
dispatch::DispatchCommand::new(self, pipeline, sets, dimensions, push_constants)
}
/// Adds a command that starts a render pass.
///
/// If `secondary` is true, then you will only be able to add secondary command buffers while
/// you're inside the first subpass on the render pass. If `secondary` is false, you will only
/// be able to add inline draw commands and not secondary command buffers.
///
/// You must call this before you can add draw commands.
#[inline]
fn begin_render_pass<Rp, C>(self, framebuffer: Arc<Framebuffer<Rp>>, secondary: bool,
clear_values: C)
-> render_pass::BeginRenderPassCommand<Self, Rp, Rp>
where Self: Sized + OutsideRenderPass,
Rp: RenderPass + RenderPassClearValues<C>
{
render_pass::BeginRenderPassCommand::new(self, framebuffer, secondary, clear_values)
}
/// Adds a command that jumps to the next subpass of the current render pass.
fn next_subpass(self, secondary: bool) -> render_pass::NextSubpassCommand<Self>
where Self: Sized + InsideRenderPass
{
render_pass::NextSubpassCommand::new(self, secondary)
}
/// Adds a command that ends the current render pass.
///
/// This must be called after you went through all the subpasses and before you can build
/// the command buffer or add further commands.
fn end_render_pass(self) -> render_pass::EndRenderPassCommand<Self>
where Self: Sized + InsideRenderPass
{
render_pass::EndRenderPassCommand::new(self)
}
/// Returns true if the command buffer can be built. This function should always return true,
/// except when we're building a primary command buffer that is inside a render pass.
fn buildable_state(&self) -> bool;
/// Turns the commands list into a command buffer that can be submitted.
fn build(self) -> Self::Output where Self: Sized {
assert!(self.buildable_state(), "Tried to build a command buffer still inside a \
render pass");
unsafe {
self.raw_build(|_| {}, iter::empty(), PipelineBarrierBuilder::new())
}
@ -122,6 +164,8 @@ pub unsafe trait StdCommandsList {
/// the command numbers to be inferior to `num_commands`.
/// - `final_barrier` is a pipeline barrier that must be added at the end of the
/// command buffer builder.
///
/// This function doesn't check that `buildable_state` returns true.
unsafe fn raw_build<I, F>(self, additional_elements: F, barriers: I,
final_barrier: PipelineBarrierBuilder) -> Self::Output
where F: FnOnce(&mut UnsafeCommandBufferBuilder<Self::Pool>),
@ -136,7 +180,18 @@ pub unsafe trait InsideRenderPass: StdCommandsList {
type RenderPass: RenderPass;
type Framebuffer;
fn render_pass(&self) -> &Self::RenderPass;
/// Returns the number of the subpass we're in. The value is 0-indexed, so immediately after
/// calling `begin_render_pass` the value will be `0`.
///
/// The value should always be strictly inferior to the number of subpasses in the render pass.
fn current_subpass(&self) -> u32;
/// If true, only secondary command buffers can be added inside the subpass. If false, only
/// inline draw commands can be added.
fn secondary_subpass(&self) -> bool;
// TODO: don't use Arc
fn render_pass(&self) -> &Arc<Self::RenderPass>;
fn framebuffer(&self) -> &Self::Framebuffer;
}

View File

@ -0,0 +1,442 @@
// 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::sync::Arc;
use std::ops::Range;
use smallvec::SmallVec;
use buffer::traits::TrackedBuffer;
use command_buffer::std::InsideRenderPass;
use command_buffer::std::OutsideRenderPass;
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 format::ClearValue;
use framebuffer::Framebuffer;
use framebuffer::RenderPass;
use framebuffer::RenderPassClearValues;
use image::traits::TrackedImage;
use instance::QueueFamily;
use sync::Fence;
/// Wraps around a commands list and adds an update buffer command at the end of it.
pub struct BeginRenderPassCommand<L, Rp, Rpf>
where L: StdCommandsList, Rp: RenderPass, Rpf: RenderPass
{
// Parent commands list.
previous: L,
// True if only secondary command buffers can be added.
secondary: bool,
rect: [Range<u32>; 2],
clear_values: SmallVec<[ClearValue; 6]>,
render_pass: Arc<Rp>,
framebuffer: Arc<Framebuffer<Rpf>>,
}
impl<L, Rp> BeginRenderPassCommand<L, Rp, Rp>
where L: StdCommandsList + OutsideRenderPass, Rp: RenderPass
{
/// See the documentation of the `begin_render_pass` method.
// TODO: allow setting more parameters
pub fn new<C>(previous: L, framebuffer: Arc<Framebuffer<Rp>>, secondary: bool, clear_values: C)
-> BeginRenderPassCommand<L, Rp, Rp>
where Rp: RenderPassClearValues<C>
{
// FIXME: transition states of the images in the framebuffer
let clear_values = framebuffer.render_pass().convert_clear_values(clear_values)
.collect();
BeginRenderPassCommand {
previous: previous,
secondary: secondary,
rect: [0 .. framebuffer.width(), 0 .. framebuffer.height()],
clear_values: clear_values,
render_pass: framebuffer.render_pass().clone(),
framebuffer: framebuffer.clone(),
}
}
}
unsafe impl<L, Rp, Rpf> StdCommandsList for BeginRenderPassCommand<L, Rp, Rpf>
where L: StdCommandsList, Rp: RenderPass, Rpf: RenderPass
{
type Pool = L::Pool;
type Output = BeginRenderPassCommandCb<L, Rp, Rpf>;
#[inline]
fn num_commands(&self) -> usize {
self.previous.num_commands() + 1
}
#[inline]
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
if !queue.supports_graphics() {
return Err(());
}
self.previous.check_queue_validity(queue)
}
#[inline]
fn buildable_state(&self) -> bool {
// We are no longer in a buildable state after entering a render pass.
false
}
unsafe fn extract_current_buffer_state<Ob>(&mut self, buffer: &Ob)
-> Option<Ob::CommandListState>
where Ob: TrackedBuffer
{
// FIXME: state of images in the framebuffer
self.previous.extract_current_buffer_state(buffer)
}
unsafe fn extract_current_image_state<I>(&mut self, image: &I) -> Option<I::CommandListState>
where I: TrackedImage
{
// FIXME: state of images in the framebuffer
self.previous.extract_current_image_state(image)
}
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)>
{
let my_command_num = self.num_commands();
let barriers = barriers.map(move |(n, b)| { assert!(n < my_command_num); (n, b) });
let my_render_pass = self.render_pass;
let my_framebuffer = self.framebuffer;
let mut my_clear_values = self.clear_values;
let my_rect = self.rect;
let my_secondary = self.secondary;
let parent = self.previous.raw_build(|cb| {
cb.begin_render_pass(my_render_pass.inner(), &my_framebuffer,
my_clear_values.into_iter(), my_rect, my_secondary);
additional_elements(cb);
}, barriers, final_barrier);
BeginRenderPassCommandCb {
previous: parent,
render_pass: my_render_pass,
framebuffer: my_framebuffer,
}
}
}
unsafe impl<L, Rp, Rpf> InsideRenderPass for BeginRenderPassCommand<L, Rp, Rpf>
where L: StdCommandsList, Rp: RenderPass, Rpf: RenderPass
{
type RenderPass = Rp;
type Framebuffer = Arc<Framebuffer<Rpf>>;
#[inline]
fn current_subpass(&self) -> u32 {
0
}
#[inline]
fn secondary_subpass(&self) -> bool {
self.secondary
}
#[inline]
fn render_pass(&self) -> &Arc<Self::RenderPass> {
&self.render_pass
}
#[inline]
fn framebuffer(&self) -> &Self::Framebuffer {
&self.framebuffer
}
}
/// Wraps around a command buffer and adds an update buffer command at the end of it.
pub struct BeginRenderPassCommandCb<L, Rp, Rpf>
where L: StdCommandsList, Rp: RenderPass, Rpf: RenderPass
{
// The previous commands.
previous: L::Output,
render_pass: Arc<Rp>,
framebuffer: Arc<Framebuffer<Rpf>>,
}
unsafe impl<L, Rp, Rpf> CommandBuffer for BeginRenderPassCommandCb<L, Rp, Rpf>
where L: StdCommandsList, Rp: RenderPass, Rpf: RenderPass
{
type Pool = L::Pool;
type SemaphoresWaitIterator = <L::Output as CommandBuffer>::SemaphoresWaitIterator;
type SemaphoresSignalIterator = <L::Output as CommandBuffer>::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)
}
}
/// Wraps around a commands list and adds a command at the end of it that jumps to the next subpass.
pub struct NextSubpassCommand<L> where L: StdCommandsList {
// Parent commands list.
previous: L,
// True if only secondary command buffers can be added.
secondary: bool,
}
impl<L> NextSubpassCommand<L> where L: StdCommandsList + InsideRenderPass {
/// See the documentation of the `next_subpass` method.
#[inline]
pub fn new(previous: L, secondary: bool) -> NextSubpassCommand<L> {
// FIXME: put this check
//assert!(previous.current_subpass() + 1 < previous.render_pass().num_subpasses()); // TODO: error instead
NextSubpassCommand {
previous: previous,
secondary: secondary,
}
}
}
unsafe impl<L> StdCommandsList for NextSubpassCommand<L>
where L: StdCommandsList + InsideRenderPass
{
type Pool = L::Pool;
type Output = NextSubpassCommandCb<L>;
#[inline]
fn num_commands(&self) -> usize {
self.previous.num_commands() + 1
}
#[inline]
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
if !queue.supports_graphics() {
return Err(());
}
self.previous.check_queue_validity(queue)
}
#[inline]
fn buildable_state(&self) -> bool {
false
}
#[inline]
unsafe fn extract_current_buffer_state<Ob>(&mut self, buffer: &Ob)
-> Option<Ob::CommandListState>
where Ob: TrackedBuffer
{
self.previous.extract_current_buffer_state(buffer)
}
#[inline]
unsafe fn extract_current_image_state<I>(&mut self, image: &I) -> Option<I::CommandListState>
where I: TrackedImage
{
self.previous.extract_current_image_state(image)
}
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)>
{
let secondary = self.secondary;
let parent = self.previous.raw_build(|cb| {
cb.next_subpass(secondary);
additional_elements(cb);
}, barriers, final_barrier);
NextSubpassCommandCb {
previous: parent,
}
}
}
unsafe impl<L> InsideRenderPass for NextSubpassCommand<L>
where L: StdCommandsList + InsideRenderPass
{
type RenderPass = L::RenderPass;
type Framebuffer = L::Framebuffer;
#[inline]
fn current_subpass(&self) -> u32 {
self.previous.current_subpass() + 1
}
#[inline]
fn secondary_subpass(&self) -> bool {
self.secondary
}
#[inline]
fn render_pass(&self) -> &Arc<Self::RenderPass> {
self.previous.render_pass()
}
#[inline]
fn framebuffer(&self) -> &Self::Framebuffer {
self.previous.framebuffer()
}
}
/// Wraps around a command buffer and adds an end render pass command at the end of it.
pub struct NextSubpassCommandCb<L> where L: StdCommandsList {
// The previous commands.
previous: L::Output,
}
unsafe impl<L> CommandBuffer for NextSubpassCommandCb<L> where L: StdCommandsList {
type Pool = L::Pool;
type SemaphoresWaitIterator = <L::Output as CommandBuffer>::SemaphoresWaitIterator;
type SemaphoresSignalIterator = <L::Output as CommandBuffer>::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)
}
}
/// Wraps around a commands list and adds an end render pass command at the end of it.
pub struct EndRenderPassCommand<L> where L: StdCommandsList {
// Parent commands list.
previous: L,
}
impl<L> EndRenderPassCommand<L> where L: StdCommandsList + InsideRenderPass {
/// See the documentation of the `end_render_pass` method.
#[inline]
pub fn new(previous: L) -> EndRenderPassCommand<L> {
// FIXME: check that the number of subpasses is correct
EndRenderPassCommand {
previous: previous,
}
}
}
unsafe impl<L> StdCommandsList for EndRenderPassCommand<L> where L: StdCommandsList {
type Pool = L::Pool;
type Output = EndRenderPassCommandCb<L>;
#[inline]
fn num_commands(&self) -> usize {
self.previous.num_commands() + 1
}
#[inline]
fn check_queue_validity(&self, queue: QueueFamily) -> Result<(), ()> {
if !queue.supports_graphics() {
return Err(());
}
self.previous.check_queue_validity(queue)
}
#[inline]
fn buildable_state(&self) -> bool {
true
}
#[inline]
unsafe fn extract_current_buffer_state<Ob>(&mut self, buffer: &Ob)
-> Option<Ob::CommandListState>
where Ob: TrackedBuffer
{
self.previous.extract_current_buffer_state(buffer)
}
#[inline]
unsafe fn extract_current_image_state<I>(&mut self, image: &I) -> Option<I::CommandListState>
where I: TrackedImage
{
self.previous.extract_current_image_state(image)
}
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 need to flush all the barriers because regular (ie. non-self-referencing) barriers
// aren't allowed inside render passes.
let mut pipeline_barrier = PipelineBarrierBuilder::new();
for (num, barrier) in barriers {
debug_assert!(num <= self.num_commands());
pipeline_barrier.merge(barrier);
}
let parent = self.previous.raw_build(|cb| {
cb.end_render_pass();
cb.pipeline_barrier(pipeline_barrier);
additional_elements(cb);
}, iter::empty(), final_barrier);
EndRenderPassCommandCb {
previous: parent,
}
}
}
unsafe impl<L> OutsideRenderPass for EndRenderPassCommand<L> where L: StdCommandsList {
}
/// Wraps around a command buffer and adds an end render pass command at the end of it.
pub struct EndRenderPassCommandCb<L> where L: StdCommandsList {
// The previous commands.
previous: L::Output,
}
unsafe impl<L> CommandBuffer for EndRenderPassCommandCb<L> where L: StdCommandsList {
type Pool = L::Pool;
type SemaphoresWaitIterator = <L::Output as CommandBuffer>::SemaphoresWaitIterator;
type SemaphoresSignalIterator = <L::Output as CommandBuffer>::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)
}
}

View File

@ -101,6 +101,11 @@ unsafe impl<'a, L, B, D: ?Sized> StdCommandsList for UpdateCommand<'a, L, B, D>
self.previous.check_queue_validity(queue)
}
#[inline]
fn buildable_state(&self) -> bool {
true
}
unsafe fn extract_current_buffer_state<Ob>(&mut self, buffer: &Ob)
-> Option<Ob::CommandListState>
where Ob: TrackedBuffer