Merge pull request #486 from tomaka/fb-cleanup

Lots of cleanups in the framebuffer modules
This commit is contained in:
tomaka 2017-06-03 11:20:39 +02:00 committed by GitHub
commit 77797d0eec
9 changed files with 431 additions and 370 deletions

View File

@ -7,43 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::cmp;
use std::sync::Arc;
use SafeDeref;
use image::ImageViewAccess;
use image::sys::UnsafeImageView;
//use sync::AccessFlagBits;
//use sync::PipelineStages;
/// A list of attachments.
// TODO: rework this trait
pub unsafe trait AttachmentsList {
/// Returns the image views of this list.
// TODO: better return type
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView>;
/// Returns the dimensions of the intersection of the views. Returns `None` if the list is
/// empty.
///
/// For example if one view is 256x256x2 and another one is 128x512x3, then this function
/// should return 128x256x2.
fn intersection_dimensions(&self) -> Option<[u32; 3]>;
// TODO: meh for API
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess>;
}
unsafe impl<T> AttachmentsList for T where T: SafeDeref, T::Target: AttachmentsList {
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
(**self).raw_image_view_handles()
}
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
(**self).intersection_dimensions()
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
(**self).as_image_view_accesses()
@ -51,16 +28,6 @@ unsafe impl<T> AttachmentsList for T where T: SafeDeref, T::Target: AttachmentsL
}
unsafe impl AttachmentsList for () {
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
vec![]
}
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
None
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
vec![]
@ -68,37 +35,6 @@ unsafe impl AttachmentsList for () {
}
unsafe impl AttachmentsList for Vec<Arc<ImageViewAccess + Send + Sync>> {
#[inline]
fn raw_image_view_handles(&self) -> Vec<&UnsafeImageView> {
self.iter().map(|img| img.inner()).collect()
}
#[inline]
fn intersection_dimensions(&self) -> Option<[u32; 3]> {
let mut dims = None;
for view in self.iter() {
debug_assert_eq!(view.dimensions().depth(), 1);
match dims {
None => {
dims = Some([
view.dimensions().width(),
view.dimensions().height(),
view.dimensions().array_layers()
]);
},
Some(ref mut d) => {
d[0] = cmp::min(view.dimensions().width(), d[0]);
d[1] = cmp::min(view.dimensions().height(), d[1]);
d[2] = cmp::min(view.dimensions().array_layers(), d[2]);
},
}
}
dims
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
self.iter().map(|p| &**p as &ImageViewAccess).collect()
@ -108,33 +44,6 @@ unsafe impl AttachmentsList for Vec<Arc<ImageViewAccess + Send + Sync>> {
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]
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 = 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,
};
Some(dims)
}
#[inline]
fn as_image_view_accesses(&self) -> Vec<&ImageViewAccess> {
let mut list = self.0.as_image_view_accesses();

View File

@ -14,12 +14,10 @@ use format::ClearValue;
use format::Format;
use format::FormatTy;
use framebuffer::RenderPass;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassCompatible;
use framebuffer::RenderPassCreationError;
use image::ImageLayout as ImageLayout;
use image::ImageViewAccess;
use sync::AccessFlagBits;
use sync::PipelineStages;
@ -44,9 +42,7 @@ use vk;
/// - The provided methods shouldn't be overriden with fancy implementations. For example
/// `build_render_pass` must build a render pass from the description and not a different one.
///
pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> +
RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>>
{
pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> {
/// Returns the number of attachments of the render pass.
fn num_attachments(&self) -> usize;

View File

@ -8,17 +8,12 @@
// according to those terms.
use std::iter;
use std::sync::Arc;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::FramebufferCreationError;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDescClearValues;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::LayoutPassDependencyDescription;
use image::ImageViewAccess;
/// Description of an empty render pass.
///
@ -143,29 +138,6 @@ unsafe impl RenderPassDesc for EmptySinglePassRenderPassDesc {
}
}
unsafe impl RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>> for EmptySinglePassRenderPassDesc {
#[inline]
fn check_attachments_list(&self, list: Vec<Arc<ImageViewAccess + Send + Sync>>)
-> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError>
{
if list.is_empty() {
Ok(Box::new(()) as Box<_>)
} else {
Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: 0,
obtained: list.len(),
})
}
}
}
unsafe impl RenderPassDescAttachmentsList<()> for EmptySinglePassRenderPassDesc {
#[inline]
fn check_attachments_list(&self, list: ()) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
Ok(Box::new(()) as Box<_>)
}
}
unsafe impl RenderPassDescClearValues<Vec<ClearValue>> for EmptySinglePassRenderPassDesc {
#[inline]
fn convert_clear_values(&self, values: Vec<ClearValue>) -> Box<Iterator<Item = ClearValue>> {

View File

@ -7,6 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::cmp;
use std::error;
use std::fmt;
use std::marker::PhantomData;
@ -26,9 +27,9 @@ use framebuffer::LayoutPassDependencyDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassSys;
use framebuffer::ensure_image_view_compatible;
use image::ImageView;
use image::ImageViewAccess;
@ -39,91 +40,49 @@ use VulkanPointers;
use check_errors;
use vk;
/// Contains the list of images attached to a render pass.
/// Contains a render pass and the image views that are attached to it.
///
/// Creating a framebuffer is done by passing the render pass object, the dimensions of the
/// framebuffer, and the list of attachments to `Framebuffer::new()`.
/// Creating a framebuffer is done by calling `Framebuffer::start`, which returns a
/// `FramebufferBuilder` object. You can then add the framebuffer attachments one by one by
/// calling `add(image)`. When you are done, call `build()`.
///
/// Just like all render pass objects implement the `RenderPassAbstract` trait, all framebuffer
/// objects implement the `FramebufferAbstract` trait. This means that you can cast any
/// `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
/// Both the `add` and the `build` functions perform various checks to make sure that the number
/// of images is correct and that each image is compatible with the attachment definition in the
/// render pass.
///
/// ## With a generic list of attachments
///
/// The list of attachments passed to `Framebuffer::new()` can be of various types, but one of the
/// possibilities is to pass an object of type `Vec<Arc<ImageView + Send + Sync>>`.
///
/// > **Note**: If you access a render pass object through the `RenderPassAbstract` trait, passing
/// > a `Vec<Arc<ImageView + Send + Sync>>` is the only possible method.
///
/// The framebuffer constructor will perform various checks to make sure that the number of images
/// is correct and that each image can be used with this render pass.
///
/// ```ignore // FIXME: unignore
/// ```
/// # use std::sync::Arc;
/// # use vulkano::framebuffer::RenderPassAbstract;
/// use vulkano::framebuffer::Framebuffer;
///
/// # let render_pass: Arc<RenderPassAbstract + Send + Sync> = return;
/// # let my_image: Arc<vulkano::image::ImageViewAccess> = return;
/// // let render_pass: Arc<RenderPassAbstract + Send + Sync> = ...;
/// let framebuffer = Framebuffer::new(render_pass.clone(), [1024, 768, 1],
/// vec![my_image.clone() as Arc<_>]).unwrap();
/// # let my_image: Arc<vulkano::image::AttachmentImage<vulkano::format::Format>> = return;
/// // let render_pass: Arc<_> = ...;
/// let framebuffer = Framebuffer::start(render_pass.clone())
/// .add(my_image).unwrap()
/// .build().unwrap();
/// ```
///
/// ## With a specialized list of attachments
/// Just like render pass objects implement the `RenderPassAbstract` trait, all framebuffer
/// objects implement the `FramebufferAbstract` trait. This means that you can cast any
/// `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
///
/// The list of attachments can also be of any type `T`, as long as the render pass description
/// implements the trait `RenderPassDescAttachmentsList<T>`.
/// ## Framebuffer dimensions
///
/// For example if you pass a render pass object that implements
/// `RenderPassDescAttachmentsList<Foo>`, then you can pass a `Foo` as the list of attachments.
/// If you use `Framebuffer::start()` to create a framebuffer then vulkano will automatically
/// make sure that all the attachments have the same dimensions, as this is the most common
/// situation.
///
/// > **Note**: The reason why `Vec<Arc<ImageView + Send + Sync>>` always works (see previous section) is that
/// > render pass descriptions are required to always implement
/// > `RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>>`.
/// Alternatively you can also use `with_intersecting_dimensions`, in which case the dimensions of
/// the framebuffer will be the intersection of the dimensions of all attachments, or
/// `with_dimensions` if you want to specify exact dimensions. If you use `with_dimensions`, you
/// are allowed to attach images that are larger than these dimensions.
///
/// When it comes to the `single_pass_renderpass!` and `ordered_passes_renderpass!` macros, you can
/// build a list of attachments by calling `start_attachments()` on the render pass description,
/// which will return an object that has a method whose name is the name of the first attachment
/// and that can be used to specify it. This method will return another object that has a method
/// whose name is the name of the second attachment, and so on. See the documentation of the macros
/// for more details. TODO: put link here
/// If the dimensions of the framebuffer don't match the dimensions of one of its attachment, then
/// only the top-left hand corner of the image will be drawn to.
///
/// ```ignore // FIXME: unignore
/// # #[macro_use] extern crate vulkano;
/// # fn main() {
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// use std::sync::Arc;
/// use vulkano::format::Format;
/// use vulkano::framebuffer::Framebuffer;
///
/// let render_pass = single_pass_renderpass!(device.clone(),
/// attachments: {
/// // `foo` is a custom name we give to the first and only attachment.
/// foo: {
/// load: Clear,
/// store: Store,
/// format: Format::R8G8B8A8Unorm,
/// samples: 1,
/// }
/// },
/// pass: {
/// color: [foo], // Repeat the attachment name here.
/// depth_stencil: {}
/// }
/// ).unwrap();
///
/// # let my_image: Arc<vulkano::image::ImageViewAccess> = return;
/// let framebuffer = {
/// let atch = render_pass.desc().start_attachments().foo(my_image.clone() as Arc<_>);
/// Framebuffer::new(render_pass, [1024, 768, 1], atch).unwrap()
/// };
/// # }
/// ```
#[derive(Debug)]
pub struct Framebuffer<Rp, A> {
// TODO: is this field really needed?
device: Arc<Device>,
render_pass: Rp,
framebuffer: vk::Framebuffer,
@ -136,7 +95,29 @@ impl<Rp> Framebuffer<Rp, ()> {
pub fn start(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
dimensions: FramebufferBuilderDimensions::AutoIdentical,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::AutoIdentical(None),
attachments: (),
}
}
/// Starts building a framebuffer. The dimensions of the framebuffer will automatically be
/// the intersection of the dimensions of all the attachments.
pub fn with_intersecting_dimensions(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::AutoSmaller(None),
attachments: (),
}
}
/// Starts building a framebuffer.
pub fn with_dimensions(render_pass: Rp, dimensions: [u32; 3]) -> FramebufferBuilder<Rp, ()> {
FramebufferBuilder {
render_pass: render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::Specific(dimensions),
attachments: (),
}
}
@ -145,13 +126,26 @@ impl<Rp> Framebuffer<Rp, ()> {
/// Prototype of a framebuffer.
pub struct FramebufferBuilder<Rp, A> {
render_pass: Rp,
raw_ids: SmallVec<[vk::ImageView; 8]>,
dimensions: FramebufferBuilderDimensions,
attachments: A,
}
impl<Rp, A> fmt::Debug for FramebufferBuilder<Rp, A> where Rp: fmt::Debug, A: fmt::Debug {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("FramebufferBuilder")
.field("render_pass", &self.render_pass)
.field("dimensions", &self.dimensions)
.field("attachments", &self.attachments)
.finish()
}
}
#[derive(Debug)]
enum FramebufferBuilderDimensions {
AutoIdentical,
AutoSmaller,
AutoIdentical(Option<[u32; 3]>),
AutoSmaller(Option<[u32; 3]>),
Specific([u32; 3]),
}
@ -168,36 +162,75 @@ impl<Rp, A> FramebufferBuilder<Rp, A>
{
let access = attachment.access();
// TODO: check number of attachments
if self.raw_ids.len() >= self.render_pass.num_attachments() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.num_attachments(),
obtained: self.raw_ids.len() + 1,
});
}
match ensure_image_view_compatible(&self.render_pass, self.raw_ids.len(), &access) {
Ok(()) => (),
Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment(err))
};
let img_dims = access.dimensions();
debug_assert_eq!(img_dims.depth(), 1);
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::AutoIdentical(None) => {
let dims = [img_dims.width(), img_dims.height(), img_dims.array_layers()];
FramebufferBuilderDimensions::AutoIdentical(Some(dims))
},
FramebufferBuilderDimensions::AutoSmaller => {
FramebufferBuilderDimensions::AutoSmaller
FramebufferBuilderDimensions::AutoIdentical(Some(current)) => {
if img_dims.width() != current[0] || img_dims.height() != current[1] ||
img_dims.array_layers() != current[2]
{
return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
expected: current,
obtained: [img_dims.width(), img_dims.height(), img_dims.array_layers()]
});
}
FramebufferBuilderDimensions::AutoIdentical(Some(current))
}
FramebufferBuilderDimensions::AutoSmaller(None) => {
let dims = [img_dims.width(), img_dims.height(), img_dims.array_layers()];
FramebufferBuilderDimensions::AutoSmaller(Some(dims))
},
FramebufferBuilderDimensions::AutoSmaller(Some(current)) => {
let new_dims = [
cmp::min(current[0], img_dims.width()),
cmp::min(current[1], img_dims.height()),
cmp::min(current[2], img_dims.array_layers())
];
FramebufferBuilderDimensions::AutoSmaller(Some(new_dims))
},
FramebufferBuilderDimensions::Specific(current) => {
let dims = access.dimensions();
if dims.width() != current[0] || dims.height() != current[1] ||
dims.array_layers() != current[2]
if img_dims.width() < current[0] || img_dims.height() < current[1] ||
img_dims.array_layers() < current[2]
{
return Err(FramebufferCreationError::AttachmentTooSmall); // TODO: more precise?
return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
expected: current,
obtained: [img_dims.width(), img_dims.height(), img_dims.array_layers()]
});
}
FramebufferBuilderDimensions::Specific([
dims.width(),
dims.height(),
dims.array_layers()
img_dims.width(),
img_dims.height(),
img_dims.array_layers()
])
}
};
let mut raw_ids = self.raw_ids;
raw_ids.push(access.inner().internal_object());
Ok(FramebufferBuilder {
render_pass: self.render_pass,
raw_ids: raw_ids,
dimensions: dimensions,
attachments: (self.attachments, access),
})
@ -216,6 +249,7 @@ impl<Rp, A> FramebufferBuilder<Rp, A>
{
FramebufferBuilder {
render_pass: self.render_pass,
raw_ids: self.raw_ids,
dimensions: self.dimensions,
attachments: Box::new(self.attachments) as Box<_>,
}
@ -225,22 +259,25 @@ impl<Rp, A> FramebufferBuilder<Rp, A>
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.
// 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
// Check the number of attachments.
if self.raw_ids.len() != self.render_pass.num_attachments() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.num_attachments(),
obtained: self.raw_ids.len(),
});
}
// 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,
FramebufferBuilderDimensions::Specific(dims) |
FramebufferBuilderDimensions::AutoIdentical(Some(dims)) |
FramebufferBuilderDimensions::AutoSmaller(Some(dims)) => {
dims
},
FramebufferBuilderDimensions::AutoIdentical(None) |
FramebufferBuilderDimensions::AutoSmaller(None) => {
return Err(FramebufferCreationError::CantDetermineDimensions);
},
};
// Checking the dimensions against the limits.
@ -255,9 +292,6 @@ impl<Rp, A> FramebufferBuilder<Rp, A>
}
}
let ids: SmallVec<[vk::ImageView; 8]> =
attachments.raw_image_view_handles().into_iter().map(|v| v.internal_object()).collect();
let framebuffer = unsafe {
let vk = device.pointers();
@ -266,8 +300,8 @@ impl<Rp, A> FramebufferBuilder<Rp, A>
pNext: ptr::null(),
flags: 0, // reserved
renderPass: self.render_pass.inner().internal_object(),
attachmentCount: ids.len() as u32,
pAttachments: ids.as_ptr(),
attachmentCount: self.raw_ids.len() as u32,
pAttachments: self.raw_ids.as_ptr(),
width: dimensions[0],
height: dimensions[1],
layers: dimensions[2],
@ -284,7 +318,7 @@ impl<Rp, A> FramebufferBuilder<Rp, A>
render_pass: self.render_pass,
framebuffer: framebuffer,
dimensions: dimensions,
resources: attachments,
resources: self.attachments,
})
}
}
@ -379,15 +413,6 @@ unsafe impl<Rp, A> RenderPassDesc for Framebuffer<Rp, A> where Rp: RenderPassDes
}
}
unsafe impl<At, Rp, A> RenderPassDescAttachmentsList<At> for Framebuffer<Rp, A>
where Rp: RenderPassDescAttachmentsList<At>
{
#[inline]
fn check_attachments_list(&self, atch: At) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
self.render_pass.check_attachments_list(atch)
}
}
unsafe impl<C, Rp, A> RenderPassDescClearValues<C> for Framebuffer<Rp, A>
where Rp: RenderPassDescClearValues<C>
{
@ -441,8 +466,13 @@ pub enum FramebufferCreationError {
OomError(OomError),
/// The requested dimensions exceed the device's limits.
DimensionsTooLarge,
/// One of the attachments is too small compared to the requested framebuffer dimensions.
AttachmentTooSmall,
/// The attachment has a size that isn't compatible with the requested framebuffer dimensions.
AttachmentDimensionsIncompatible {
/// Expected dimensions.
expected: [u32; 3],
/// Attachment dimensions.
obtained: [u32; 3],
},
/// The number of attachments doesn't match the number expected by the render pass.
AttachmentsCountMismatch {
/// Expected number of attachments.
@ -451,12 +481,9 @@ pub enum FramebufferCreationError {
obtained: usize,
},
/// One of the images cannot be used as the requested attachment.
IncompatibleAttachment {
/// Zero-based id of the attachment.
attachment_num: usize,
/// The problem.
error: IncompatibleRenderPassAttachmentError,
},
IncompatibleAttachment(IncompatibleRenderPassAttachmentError),
/// The framebuffer has no attachment and no dimension was specified.
CantDetermineDimensions,
}
impl From<OomError> for FramebufferCreationError {
@ -473,16 +500,18 @@ impl error::Error for FramebufferCreationError {
FramebufferCreationError::OomError(_) => "no memory available",
FramebufferCreationError::DimensionsTooLarge => "the dimensions of the framebuffer \
are too large",
FramebufferCreationError::AttachmentTooSmall => {
"one of the attachments is too small compared to the requested framebuffer \
dimensions"
FramebufferCreationError::AttachmentDimensionsIncompatible { .. } => {
"the attachment has a size that isn't compatible with the framebuffer dimensions"
},
FramebufferCreationError::AttachmentsCountMismatch { .. } => {
"the number of attachments doesn't match the number expected by the render pass"
},
FramebufferCreationError::IncompatibleAttachment { .. } => {
FramebufferCreationError::IncompatibleAttachment(_) => {
"one of the images cannot be used as the requested attachment"
},
FramebufferCreationError::CantDetermineDimensions => {
"the framebuffer has no attachment and no dimension was specified"
},
}
}
@ -490,7 +519,7 @@ impl error::Error for FramebufferCreationError {
fn cause(&self) -> Option<&error::Error> {
match *self {
FramebufferCreationError::OomError(ref err) => Some(err),
FramebufferCreationError::IncompatibleAttachment { ref error, .. } => Some(error),
FramebufferCreationError::IncompatibleAttachment(ref err) => Some(err),
_ => None,
}
}
@ -510,70 +539,314 @@ impl From<Error> for FramebufferCreationError {
}
}
/* FIXME: restore
#[cfg(test)]
mod tests {
use format::R8G8B8A8Unorm;
use std::sync::Arc;
use format::Format;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::Framebuffer;
use framebuffer::FramebufferCreationError;
use framebuffer::RenderPassDesc;
use image::attachment::AttachmentImage;
#[test]
fn simple_create() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = single_pass_renderpass! {
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: R8G8B8A8Unorm,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
}.unwrap();
).unwrap());
let image = AttachmentImage::new(&device, [1024, 768], R8G8B8A8Unorm).unwrap();
let _ = Framebuffer::new(render_pass, [1024, 768, 1], example::AList {
color: image.clone()
}).unwrap();
let image = AttachmentImage::new(device.clone(), [1024, 768],
Format::R8G8B8A8Unorm).unwrap();
let _ = Framebuffer::start(render_pass).add(image.clone()).unwrap().build().unwrap();
}
#[test]
fn framebuffer_too_large() {
fn check_device_limits() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = example::CustomRenderPass::new(&device, &example::Formats {
color: (R8G8B8A8Unorm, 1)
}).unwrap();
let image = AttachmentImage::new(&device, [1024, 768], R8G8B8A8Unorm).unwrap();
let alist = example::AList { color: image.clone() };
match Framebuffer::new(render_pass, [0xffffffff, 0xffffffff, 0xffffffff], alist) {
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let res = Framebuffer::with_dimensions(rp, [0xffffffff, 0xffffffff, 0xffffffff]).build();
match res {
Err(FramebufferCreationError::DimensionsTooLarge) => (),
_ => panic!()
}
}
#[test]
fn attachment_too_small() {
fn attachment_format_mismatch() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = example::CustomRenderPass::new(&device, &example::Formats {
color: (R8G8B8A8Unorm, 1)
}).unwrap();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
let image = AttachmentImage::new(&device, [512, 512], R8G8B8A8Unorm).unwrap();
let image = AttachmentImage::new(device.clone(), [1024, 768],
Format::R8Unorm).unwrap();
let alist = example::AList { color: image.clone() };
match Framebuffer::new(render_pass, [600, 600, 1], alist) {
Err(FramebufferCreationError::AttachmentTooSmall) => (),
match Framebuffer::start(render_pass).add(image.clone()) {
Err(FramebufferCreationError::IncompatibleAttachment(_)) => (),
_ => panic!()
}
}
}*/
// TODO: check samples mismatch
#[test]
fn attachment_dims_larger_than_specified_valid() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
let img = AttachmentImage::new(device.clone(), [600, 600], Format::R8G8B8A8Unorm).unwrap();
let _ = Framebuffer::with_dimensions(render_pass, [512, 512, 1])
.add(img).unwrap()
.build().unwrap();
}
#[test]
fn attachment_dims_smaller_than_specified() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap());
let img = AttachmentImage::new(device.clone(), [512, 700], Format::R8G8B8A8Unorm).unwrap();
match Framebuffer::with_dimensions(render_pass, [600, 600, 1]).add(img) {
Err(FramebufferCreationError::AttachmentDimensionsIncompatible { expected, obtained }) => {
assert_eq!(expected, [600, 600, 1]);
assert_eq!(obtained, [512, 700, 1]);
},
_ => panic!()
}
}
#[test]
fn multi_attachments_dims_not_identical() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
},
b: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a, b],
depth_stencil: {}
}
).unwrap());
let a = AttachmentImage::new(device.clone(), [512, 512], Format::R8G8B8A8Unorm).unwrap();
let b = AttachmentImage::new(device.clone(), [512, 513], Format::R8G8B8A8Unorm).unwrap();
match Framebuffer::start(render_pass).add(a).unwrap().add(b) {
Err(FramebufferCreationError::AttachmentDimensionsIncompatible { expected, obtained }) => {
assert_eq!(expected, [512, 512, 1]);
assert_eq!(obtained, [512, 513, 1]);
},
_ => panic!()
}
}
#[test]
fn multi_attachments_auto_smaller() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
},
b: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a, b],
depth_stencil: {}
}
).unwrap());
let a = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let b = AttachmentImage::new(device.clone(), [512, 128], Format::R8G8B8A8Unorm).unwrap();
let fb = Framebuffer::with_intersecting_dimensions(render_pass)
.add(a).unwrap()
.add(b).unwrap()
.build().unwrap();
match (fb.width(), fb.height(), fb.layers()) {
(256, 128, 1) => (),
_ => panic!()
}
}
#[test]
fn not_enough_attachments() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
},
b: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a, b],
depth_stencil: {}
}
).unwrap());
let img = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let res = Framebuffer::with_intersecting_dimensions(render_pass)
.add(img).unwrap()
.build();
match res {
Err(FramebufferCreationError::AttachmentsCountMismatch { expected: 2,
obtained: 1 }) => (),
_ => panic!()
}
}
#[test]
fn too_many_attachments() {
let (device, _) = gfx_dev_and_queue!();
let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a],
depth_stencil: {}
}
).unwrap());
let a = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let b = AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap();
let res = Framebuffer::with_intersecting_dimensions(render_pass)
.add(a).unwrap()
.add(b);
match res {
Err(FramebufferCreationError::AttachmentsCountMismatch { expected: 1,
obtained: 2 }) => (),
_ => panic!()
}
}
#[test]
fn empty_working() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let _ = Framebuffer::with_dimensions(rp, [512, 512, 1]).build().unwrap();
}
#[test]
fn cant_determine_dimensions_auto() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let res = Framebuffer::start(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),
_ => panic!()
}
}
#[test]
fn cant_determine_dimensions_intersect() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc.build_render_pass(device).unwrap();
let res = Framebuffer::with_intersecting_dimensions(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),
_ => panic!()
}
}
}

View File

@ -65,20 +65,14 @@ macro_rules! ordered_passes_renderpass {
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::sync::Arc;
use $crate::format::ClearValue;
use $crate::format::Format;
use $crate::framebuffer::AttachmentsList;
use $crate::framebuffer::FramebufferCreationError;
use $crate::framebuffer::RenderPassDesc;
use $crate::framebuffer::RenderPassDescAttachmentsList;
use $crate::framebuffer::RenderPassDescClearValues;
use $crate::framebuffer::LayoutAttachmentDescription;
use $crate::framebuffer::LayoutPassDescription;
use $crate::framebuffer::LayoutPassDependencyDescription;
use $crate::framebuffer::ensure_image_view_compatible;
use $crate::image::ImageLayout;
use $crate::image::ImageViewAccess;
use $crate::sync::AccessFlagBits;
use $crate::sync::PipelineStages;
@ -128,29 +122,6 @@ macro_rules! ordered_passes_renderpass {
}
}
unsafe impl RenderPassDescAttachmentsList<Vec<Arc<ImageViewAccess + Send + Sync>>> for CustomRenderPassDesc {
fn check_attachments_list(&self, list: Vec<Arc<ImageViewAccess + Send + Sync>>) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
if list.len() != self.num_attachments() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.num_attachments(),
obtained: list.len(),
});
}
for n in 0 .. self.num_attachments() {
match ensure_image_view_compatible(self, n, &*list[n]) {
Ok(()) => (),
Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment {
attachment_num: n,
error: err,
})
}
}
Ok(Box::new(list) as Box<_>)
}
}
#[inline]
fn num_attachments() -> usize {
#![allow(unused_assignments)]

View File

@ -104,6 +104,7 @@ pub use self::desc::StoreOp;
pub use self::desc::LoadOp;
pub use self::empty::EmptySinglePassRenderPassDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferBuilder;
pub use self::framebuffer::FramebufferCreationError;
pub use self::framebuffer::FramebufferSys;
pub use self::sys::RenderPass;
@ -112,7 +113,6 @@ pub use self::sys::RenderPassSys;
pub use self::traits::FramebufferAbstract;
pub use self::traits::RenderPassDescClearValues;
pub use self::traits::RenderPassCompatible;
pub use self::traits::RenderPassDescAttachmentsList;
pub use self::traits::RenderPassAbstract;
pub use self::traits::RenderPassSubpassInterface;
pub use self::traits::Subpass;

View File

@ -19,15 +19,12 @@ use smallvec::SmallVec;
use device::Device;
use device::DeviceOwned;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::EmptySinglePassRenderPassDesc;
use framebuffer::FramebufferCreationError;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDependencyDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::LoadOp;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassAbstract;
@ -361,15 +358,6 @@ unsafe impl<D> RenderPassDesc for RenderPass<D> where D: RenderPassDesc {
}
}
unsafe impl<A, D> RenderPassDescAttachmentsList<A> for RenderPass<D>
where D: RenderPassDescAttachmentsList<A>
{
#[inline]
fn check_attachments_list(&self, atch: A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
self.desc.check_attachments_list(atch)
}
}
unsafe impl<C, D> RenderPassDescClearValues<C> for RenderPass<D>
where D: RenderPassDescClearValues<C>
{

View File

@ -9,8 +9,6 @@
use device::DeviceOwned;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::FramebufferCreationError;
use framebuffer::FramebufferSys;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassSys;
@ -108,40 +106,6 @@ unsafe impl<T> RenderPassAbstract for T where T: SafeDeref, T::Target: RenderPas
}
}
/// Extension trait for `RenderPassDesc`. Defines which types are allowed as an attachments list.
///
/// When the user creates a framebuffer, they need to pass a render pass object and a list of
/// attachments. In order for it to work, the render pass object must implement
/// `RenderPassDescAttachmentsList<A>` where `A` is the type of the list of attachments.
///
/// # Safety
///
/// This trait is unsafe because it's the job of the implementation to check whether the
/// attachments list is correct. What needs to be checked:
///
/// - That the attachments' format and samples count match the render pass layout.
/// - That the attachments have been created with the proper usage flags.
/// - That the attachments only expose one mipmap.
/// - That the attachments use identity components swizzling.
/// TODO: more stuff with aliasing
///
pub unsafe trait RenderPassDescAttachmentsList<A> {
/// Decodes a `A` into a list of attachments.
///
/// Checks that the attachments match the render pass, and returns a list. Returns an error if
/// one of the attachments is wrong.
fn check_attachments_list(&self, A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError>;
}
unsafe impl<A, T> RenderPassDescAttachmentsList<A> for T
where T: SafeDeref, T::Target: RenderPassDescAttachmentsList<A>
{
#[inline]
fn check_attachments_list(&self, atch: A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
(**self).check_attachments_list(atch)
}
}
/// Extension trait for `RenderPassDesc`. Defines which types are allowed as a list of clear values.
///
/// When the user enters a render pass, they need to pass a list of clear values to apply to

View File

@ -33,14 +33,11 @@ use descriptor::pipeline_layout::PipelineLayoutNotSupersetError;
use descriptor::pipeline_layout::PipelineLayoutSys;
use descriptor::pipeline_layout::EmptyPipelineDesc;
use format::ClearValue;
use framebuffer::AttachmentsList;
use framebuffer::LayoutAttachmentDescription;
use framebuffer::LayoutPassDescription;
use framebuffer::LayoutPassDependencyDescription;
use framebuffer::FramebufferCreationError;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassDesc;
use framebuffer::RenderPassDescAttachmentsList;
use framebuffer::RenderPassDescClearValues;
use framebuffer::RenderPassSubpassInterface;
use framebuffer::RenderPassSys;
@ -1178,15 +1175,6 @@ unsafe impl<Mv, L, Rp> RenderPassDesc for GraphicsPipeline<Mv, L, Rp>
}
}
unsafe impl<A, Mv, L, Rp> RenderPassDescAttachmentsList<A> for GraphicsPipeline<Mv, L, Rp>
where Rp: RenderPassDescAttachmentsList<A>
{
#[inline]
fn check_attachments_list(&self, atch: A) -> Result<Box<AttachmentsList + Send + Sync>, FramebufferCreationError> {
self.render_pass.check_attachments_list(atch)
}
}
unsafe impl<C, Mv, L, Rp> RenderPassDescClearValues<C> for GraphicsPipeline<Mv, L, Rp>
where Rp: RenderPassDescClearValues<C>
{