mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2025-02-12 15:12:33 +00:00
Rework framebuffer creation
This commit is contained in:
parent
1afbdde27f
commit
db3e128143
@ -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()
|
||||
|
@ -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()),
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user