Rework framebuffer creation

This commit is contained in:
Pierre Krieger 2017-06-02 20:36:43 +02:00
parent 1afbdde27f
commit db3e128143
5 changed files with 159 additions and 118 deletions

View File

@ -157,11 +157,8 @@ fn main() {
}));
let framebuffers = images.iter().map(|image| {
let attachments = renderpass.desc().start_attachments()
.color(image.clone());
let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
vulkano::framebuffer::Framebuffer::new(renderpass.clone(), dimensions, attachments).unwrap()
Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
.add(image.clone()).unwrap().build().unwrap())
}).collect::<Vec<_>>();
let mut previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
@ -178,8 +175,7 @@ fn main() {
//.clear_color_image(&texture, [0.0, 1.0, 0.0, 1.0])
.begin_render_pass(
framebuffers[image_num].clone(), false,
renderpass.desc().start_clear_values()
.color([0.0, 0.0, 1.0, 1.0])).unwrap()
vec![[0.0, 0.0, 1.0, 1.0].into()]).unwrap()
.draw(pipeline.clone(), vulkano::command_buffer::DynamicState::none(), vertex_buffer.clone(),
set.clone(), ()).unwrap()
.end_render_pass().unwrap()

View File

@ -69,7 +69,7 @@ fn main() {
};
let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), images[0].dimensions(), vulkano::format::D16Unorm).unwrap().access();
let depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), images[0].dimensions(), vulkano::format::D16Unorm).unwrap();
let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), Some(queue.family()), examples::VERTICES.iter().cloned())
@ -113,7 +113,7 @@ fn main() {
depth: {
load: Clear,
store: DontCare,
format: vulkano::image::ImageAccess::format(&depth_buffer),
format: vulkano::format::Format::D16Unorm,
samples: 1,
}
},
@ -153,11 +153,10 @@ fn main() {
}));
let framebuffers = images.iter().map(|image| {
let attachments = renderpass.desc().start_attachments()
.color(image.clone()).depth(depth_buffer.clone());
let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
vulkano::framebuffer::Framebuffer::new(renderpass.clone(), dimensions, attachments).unwrap()
Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
.add(image.clone()).unwrap()
.add(depth_buffer.clone()).unwrap()
.build().unwrap())
}).collect::<Vec<_>>();
@ -182,8 +181,10 @@ fn main() {
let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::new(device.clone(), queue.family()).unwrap()
.begin_render_pass(
framebuffers[image_num].clone(), false,
renderpass.desc().start_clear_values()
.color([0.0, 0.0, 1.0, 1.0]).depth((1f32))).unwrap()
vec![
[0.0, 0.0, 1.0, 1.0].into(),
1f32.into()
]).unwrap()
.draw_indexed(
pipeline.clone(), vulkano::command_buffer::DynamicState::none(),
(vertex_buffer.clone(), normals_buffer.clone()),

View File

@ -325,22 +325,9 @@ fn main() {
// Since we need to draw to multiple images, we are going to create a different framebuffer for
// each image.
let framebuffers = images.iter().map(|image| {
// When we create the framebuffer we need to pass the actual list of images for the
// framebuffer's attachments.
//
// The type of data that corresponds to this list depends on the way you created the
// render pass. With the `single_pass_renderpass!` macro you need to call
// `.desc().start_attachments()`. The returned object will have a method whose name is the
// name of the first attachment. When called, it returns an object that will have a method
// whose name is the name of the second attachment. And so on. Only the object returned
// by the method of the last attachment can be passed to `Framebuffer::new`.
let attachments = render_pass.desc().start_attachments().color(image.clone());
// Actually creating the framebuffer. Note that we have to pass the dimensions of the
// framebuffer. These dimensions must be inferior or equal to the intersection of the
// dimensions of all the attachments.
let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
Framebuffer::new(render_pass.clone(), dimensions, attachments).unwrap()
Arc::new(Framebuffer::start(render_pass.clone())
.add(image.clone()).unwrap()
.build().unwrap())
}).collect::<Vec<_>>();
// Initialization is finally finished!
@ -388,7 +375,7 @@ fn main() {
// is similar to the list of attachments when building the framebuffers, except that
// only the attachments that use `load: Clear` appear in the list.
.begin_render_pass(framebuffers[image_num].clone(), false,
render_pass.desc().start_clear_values().color([0.0, 0.0, 1.0, 1.0]))
vec![[0.0, 0.0, 1.0, 1.0].into()])
.unwrap()
// We are now inside the first subpass of the render pass. We add a draw command.

View File

@ -105,69 +105,40 @@ unsafe impl AttachmentsList for Vec<Arc<ImageViewAccess + Send + Sync>> {
}
}
macro_rules! impl_into_atch_list {
($first:ident $(, $rest:ident)*) => (
unsafe impl<$first $(, $rest)*> AttachmentsList for ($first, $($rest),*)
where $first: ImageViewAccess,
$($rest: ImageViewAccess,)*
{
#[inline]
#[allow(non_snake_case)]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
let &(ref $first, $(ref $rest,)*) = self;
vec![
&$first.inner(),
$(
&$rest.inner(),
)*
]
}
unsafe impl<A, B> AttachmentsList for (A, B)
where A: AttachmentsList, B: ImageViewAccess
{
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
let mut list = self.0.raw_image_view_handles();
list.push(self.1.inner());
list
}
#[inline]
#[allow(non_snake_case)]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
let &(ref $first, $(ref $rest,)*) = self;
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
let dims = {
let d = self.1.dimensions();
debug_assert_eq!(d.depth(), 1);
[d.width(), d.height(), d.array_layers()]
};
let dims = {
let d = $first.dimensions();
debug_assert_eq!(d.depth(), 1);
[d.width(), d.height(), d.array_layers()]
};
let dims = match self.0.intersection_dimensions() {
Some(d) => [
cmp::min(d[0], dims[0]),
cmp::min(d[1], dims[1]),
cmp::min(d[2], dims[2])
],
None => dims,
};
$(
let dims = {
let d = $rest.dimensions();
debug_assert_eq!(d.depth(), 1);
[
cmp::min(d.width(), dims[0]),
cmp::min(d.height(), dims[1]),
cmp::min(d.array_layers(), dims[2])
]
};
)*
Some(dims)
}
Some(dims)
}
#[inline]
#[allow(non_snake_case)]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
let &(ref $first, $(ref $rest,)*) = self;
vec![
&*$first,
$(
&*$rest,
)*
]
}
}
impl_into_atch_list!($($rest),*);
);
() => ();
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
let mut list = self.0.as_image_view_accesses();
list.push(&self.1);
list
}
}
impl_into_atch_list!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);

View File

@ -29,6 +29,7 @@ use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassSys;
use image::ImageView;
use image::ImageViewAccess;
use Error;
@ -122,6 +123,7 @@ use vk;
/// ```
#[derive(Debug)]
pub struct Framebuffer<Rp, A> {
// TODO: is this field really needed?
device: Arc<Device>,
render_pass: Rp,
framebuffer: vk::Framebuffer,
@ -129,28 +131,121 @@ pub struct Framebuffer<Rp, A> {
resources: A,
}
impl<Rp> Framebuffer<Rp, Box<AttachmentsList + Send + Sync>> {
/// Builds a new framebuffer.
impl<Rp> Framebuffer<Rp, ()> {
/// Starts building a framebuffer.
pub fn start(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
dimensions: FramebufferBuilderDimensions::AutoIdentical,
attachments: (),
}
}
}
/// Prototype of a framebuffer.
pub struct FramebufferBuilder<Rp, A> {
render_pass: Rp,
dimensions: FramebufferBuilderDimensions,
attachments: A,
}
enum FramebufferBuilderDimensions {
AutoIdentical,
AutoSmaller,
Specific([u32; 3]),
}
impl<Rp, A> FramebufferBuilder<Rp, A>
where Rp: RenderPassAbstract,
A: AttachmentsList,
{
/// Appends an attachment to the prototype of the framebuffer.
///
/// The `attachments` parameter depends on which render pass implementation is used.
// TODO: allow ImageView
pub fn new<Ia>(render_pass: Rp, dimensions: [u32; 3], attachments: Ia)
-> Result<Arc<Framebuffer<Rp, Box<AttachmentsList + Send + Sync>>>, FramebufferCreationError>
where Rp: RenderPassAbstract + RenderPassDescAttachmentsList<Ia>
/// Attachments must be added in the same order as the one defined in the render pass.
pub fn add<T>(self, attachment: T)
-> Result<FramebufferBuilder<Rp, (A, T::Access)>, FramebufferCreationError>
where T: ImageView
{
let device = render_pass.device().clone();
let access = attachment.access();
// TODO: check number of attachments
let dimensions = match self.dimensions {
FramebufferBuilderDimensions::AutoIdentical => {
let dims = access.dimensions();
debug_assert_eq!(dims.depth(), 1);
let dims = [dims.width(), dims.height(), dims.array_layers()];
FramebufferBuilderDimensions::Specific(dims)
},
FramebufferBuilderDimensions::AutoSmaller => {
FramebufferBuilderDimensions::AutoSmaller
},
FramebufferBuilderDimensions::Specific(current) => {
let dims = access.dimensions();
if dims.width() != current[0] || dims.height() != current[1] ||
dims.array_layers() != current[2]
{
return Err(FramebufferCreationError::AttachmentTooSmall); // TODO: more precise?
}
FramebufferBuilderDimensions::Specific([
dims.width(),
dims.height(),
dims.array_layers()
])
}
};
Ok(FramebufferBuilder {
render_pass: self.render_pass,
dimensions: dimensions,
attachments: (self.attachments, access),
})
}
/// Turns this builder into a `FramebufferBuilder<Rp, Box<AttachmentsList>>`.
///
/// This allows you to store the builder in situations where you don't know in advance the
/// number of attachments.
///
/// > **Note**: This is a very rare corner case and you shouldn't have to use this function
/// > in most situations.
#[inline]
pub fn boxed(self) -> FramebufferBuilder<Rp, Box<AttachmentsList>>
where A: 'static
{
FramebufferBuilder {
render_pass: self.render_pass,
dimensions: self.dimensions,
attachments: Box::new(self.attachments) as Box<_>,
}
}
/// Builds the framebuffer.
pub fn build(self) -> Result<Framebuffer<Rp, A>, FramebufferCreationError> {
let device = self.render_pass.device().clone();
// This function call is supposed to check whether the attachments are valid.
// For more safety, we do some additional `debug_assert`s below.
let attachments = try!(render_pass.check_attachments_list(attachments));
// FIXME: check attachments when they are added to the builder instead of at the end
let attachments = self.attachments;
//let attachments = try!(self.render_pass.check_attachments_list(self.attachments));
// TODO: add a debug assertion that checks whether the attachments are compatible
// with the RP ; this should be checked by the RenderPassDescAttachmentsList trait
// impl, but we can double-check in debug mode
// also check the number of attachments
// Compute the dimensions.
let dimensions = match self.dimensions {
FramebufferBuilderDimensions::AutoIdentical => panic!(), // TODO: what if 0 attachment?
FramebufferBuilderDimensions::AutoSmaller => attachments.intersection_dimensions().unwrap(), // TODO: what if 0 attachment?
FramebufferBuilderDimensions::Specific(dims) => dims,
};
// Checking the dimensions against the limits.
{
let limits = render_pass.device().physical_device().limits();
let limits = device.physical_device().limits();
let limits = [limits.max_framebuffer_width(), limits.max_framebuffer_height(),
limits.max_framebuffer_layers()];
if dimensions[0] > limits[0] || dimensions[1] > limits[1] ||
@ -160,26 +255,17 @@ impl<Rp> Framebuffer<Rp, Box<AttachmentsList + Send + Sync>> {
}
}
// Checking the dimensions against the attachments.
if let Some(dims_constraints) = attachments.intersection_dimensions() {
if dims_constraints[0] < dimensions[0] || dims_constraints[1] < dimensions[1] ||
dims_constraints[2] < dimensions[2]
{
return Err(FramebufferCreationError::AttachmentTooSmall);
}
}
let ids: SmallVec<[vk::ImageView; 8]> =
attachments.raw_image_view_handles().into_iter().map(|v| v.internal_object()).collect();
let framebuffer = unsafe {
let vk = render_pass.device().pointers();
let vk = device.pointers();
let infos = vk::FramebufferCreateInfo {
sType: vk::STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
pNext: ptr::null(),
flags: 0, // reserved
renderPass: render_pass.inner().internal_object(),
renderPass: self.render_pass.inner().internal_object(),
attachmentCount: ids.len() as u32,
pAttachments: ids.as_ptr(),
width: dimensions[0],
@ -193,13 +279,13 @@ impl<Rp> Framebuffer<Rp, Box<AttachmentsList + Send + Sync>> {
output
};
Ok(Arc::new(Framebuffer {
Ok(Framebuffer {
device: device,
render_pass: render_pass,
render_pass: self.render_pass,
framebuffer: framebuffer,
dimensions: dimensions,
resources: attachments,
}))
})
}
}