diff --git a/examples/src/bin/image.rs b/examples/src/bin/image.rs index 710136b1..85963c2e 100644 --- a/examples/src/bin/image.rs +++ b/examples/src/bin/image.rs @@ -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::>(); let mut previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box; @@ -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() diff --git a/examples/src/bin/teapot.rs b/examples/src/bin/teapot.rs index ed4f748d..82096518 100644 --- a/examples/src/bin/teapot.rs +++ b/examples/src/bin/teapot.rs @@ -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::>(); @@ -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()), diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 77c569a4..24e29a86 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -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::>(); // 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. diff --git a/vulkano/src/framebuffer/attachments_list.rs b/vulkano/src/framebuffer/attachments_list.rs index 2c49ea7e..28a7b71e 100644 --- a/vulkano/src/framebuffer/attachments_list.rs +++ b/vulkano/src/framebuffer/attachments_list.rs @@ -105,69 +105,40 @@ unsafe impl AttachmentsList for Vec> { } } -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 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); diff --git a/vulkano/src/framebuffer/framebuffer.rs b/vulkano/src/framebuffer/framebuffer.rs index 4a343fa9..0d97cd07 100644 --- a/vulkano/src/framebuffer/framebuffer.rs +++ b/vulkano/src/framebuffer/framebuffer.rs @@ -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 { + // TODO: is this field really needed? device: Arc, render_pass: Rp, framebuffer: vk::Framebuffer, @@ -129,28 +131,121 @@ pub struct Framebuffer { resources: A, } -impl Framebuffer> { - /// Builds a new framebuffer. +impl Framebuffer { + /// Starts building a framebuffer. + pub fn start(render_pass: Rp) -> FramebufferBuilder { + FramebufferBuilder { + render_pass: render_pass, + dimensions: FramebufferBuilderDimensions::AutoIdentical, + attachments: (), + } + } +} + +/// Prototype of a framebuffer. +pub struct FramebufferBuilder { + render_pass: Rp, + dimensions: FramebufferBuilderDimensions, + attachments: A, +} + +enum FramebufferBuilderDimensions { + AutoIdentical, + AutoSmaller, + Specific([u32; 3]), +} + +impl FramebufferBuilder + 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(render_pass: Rp, dimensions: [u32; 3], attachments: Ia) - -> Result>>, FramebufferCreationError> - where Rp: RenderPassAbstract + RenderPassDescAttachmentsList + /// Attachments must be added in the same order as the one defined in the render pass. + pub fn add(self, attachment: T) + -> Result, 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>`. + /// + /// 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> + 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, 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 Framebuffer> { } } - // 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 Framebuffer> { output }; - Ok(Arc::new(Framebuffer { + Ok(Framebuffer { device: device, - render_pass: render_pass, + render_pass: self.render_pass, framebuffer: framebuffer, dimensions: dimensions, resources: attachments, - })) + }) } }