blob: b55be4d370eb977f6007975b68a9d91c6c7ef56c [file] [log] [blame]
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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 crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::render_pass::ensure_image_view_compatible;
use crate::render_pass::AttachmentsList;
use crate::render_pass::IncompatibleRenderPassAttachmentError;
use crate::render_pass::RenderPass;
use crate::Error;
use crate::OomError;
use crate::SafeDeref;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::cmp;
use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
/// The image views that are attached to a render pass during drawing.
///
/// A framebuffer is a collection of images, and supplies the actual inputs and outputs of each
/// subpass within a render pass. It is created from a subpass and must match it: each attachment
/// point in the subpass must have a matching image in the framebuffer.
///
/// 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()`.
///
/// 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.
///
/// ```
/// # use std::sync::Arc;
/// # use vulkano::render_pass::RenderPass;
/// use vulkano::render_pass::Framebuffer;
///
/// # let render_pass: Arc<RenderPass> = return;
/// # let view: Arc<vulkano::image::view::ImageView<Arc<vulkano::image::AttachmentImage<vulkano::format::Format>>>> = return;
/// // let render_pass: Arc<_> = ...;
/// let framebuffer = Framebuffer::start(render_pass.clone())
/// .add(view).unwrap()
/// .build().unwrap();
/// ```
///
/// 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.
///
/// ## Framebuffer dimensions
///
/// 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.
///
/// 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.
///
/// 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.
///
#[derive(Debug)]
pub struct Framebuffer<A> {
device: Arc<Device>,
render_pass: Arc<RenderPass>,
framebuffer: ash::vk::Framebuffer,
dimensions: [u32; 3],
resources: A,
}
impl Framebuffer<()> {
/// Starts building a framebuffer.
pub fn start(render_pass: Arc<RenderPass>) -> FramebufferBuilder<()> {
FramebufferBuilder {
render_pass,
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: Arc<RenderPass>) -> FramebufferBuilder<()> {
FramebufferBuilder {
render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::AutoSmaller(None),
attachments: (),
}
}
/// Starts building a framebuffer.
pub fn with_dimensions(
render_pass: Arc<RenderPass>,
dimensions: [u32; 3],
) -> FramebufferBuilder<()> {
FramebufferBuilder {
render_pass,
raw_ids: SmallVec::new(),
dimensions: FramebufferBuilderDimensions::Specific(dimensions),
attachments: (),
}
}
}
/// Prototype of a framebuffer.
pub struct FramebufferBuilder<A> {
render_pass: Arc<RenderPass>,
raw_ids: SmallVec<[ash::vk::ImageView; 8]>,
dimensions: FramebufferBuilderDimensions,
attachments: A,
}
impl<A> fmt::Debug for FramebufferBuilder<A>
where
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(Option<[u32; 3]>),
AutoSmaller(Option<[u32; 3]>),
Specific([u32; 3]),
}
impl<A> FramebufferBuilder<A>
where
A: AttachmentsList,
{
/// Appends an attachment to the prototype of the framebuffer.
///
/// 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<(A, T)>, FramebufferCreationError>
where
T: ImageViewAbstract,
{
if self.raw_ids.len() >= self.render_pass.desc().attachments().len() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.desc().attachments().len(),
obtained: self.raw_ids.len() + 1,
});
}
match ensure_image_view_compatible(self.render_pass.desc(), self.raw_ids.len(), &attachment)
{
Ok(()) => (),
Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment(err)),
};
let image_dimensions = attachment.image().dimensions();
let array_layers = attachment.array_layers();
debug_assert_eq!(image_dimensions.depth(), 1);
let view_dimensions = [
image_dimensions.width(),
image_dimensions.height(),
array_layers.end - array_layers.start,
];
let dimensions = match self.dimensions {
FramebufferBuilderDimensions::AutoIdentical(None) => {
FramebufferBuilderDimensions::AutoIdentical(Some(view_dimensions))
}
FramebufferBuilderDimensions::AutoIdentical(Some(current)) => {
if view_dimensions != current {
return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
expected: current,
obtained: view_dimensions,
});
}
FramebufferBuilderDimensions::AutoIdentical(Some(current))
}
FramebufferBuilderDimensions::AutoSmaller(None) => {
FramebufferBuilderDimensions::AutoSmaller(Some(view_dimensions))
}
FramebufferBuilderDimensions::AutoSmaller(Some(current)) => {
let new_dims = [
cmp::min(current[0], view_dimensions[0]),
cmp::min(current[1], view_dimensions[1]),
cmp::min(current[2], view_dimensions[2]),
];
FramebufferBuilderDimensions::AutoSmaller(Some(new_dims))
}
FramebufferBuilderDimensions::Specific(current) => {
if view_dimensions[0] < current[0]
|| view_dimensions[1] < current[1]
|| view_dimensions[2] < current[2]
{
return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
expected: current,
obtained: view_dimensions,
});
}
FramebufferBuilderDimensions::Specific(view_dimensions)
}
};
let mut raw_ids = self.raw_ids;
raw_ids.push(attachment.inner().internal_object());
Ok(FramebufferBuilder {
render_pass: self.render_pass,
raw_ids,
dimensions,
attachments: (self.attachments, attachment),
})
}
/// 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<Box<dyn AttachmentsList>>
where
A: 'static,
{
FramebufferBuilder {
render_pass: self.render_pass,
raw_ids: self.raw_ids,
dimensions: self.dimensions,
attachments: Box::new(self.attachments) as Box<_>,
}
}
/// Builds the framebuffer.
pub fn build(self) -> Result<Framebuffer<A>, FramebufferCreationError> {
let device = self.render_pass.device().clone();
// Check the number of attachments.
if self.raw_ids.len() != self.render_pass.desc().attachments().len() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.desc().attachments().len(),
obtained: self.raw_ids.len(),
});
}
// Compute the dimensions.
let dimensions = match self.dimensions {
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.
{
let properties = device.physical_device().properties();
let limits = [
properties.max_framebuffer_width,
properties.max_framebuffer_height,
properties.max_framebuffer_layers,
];
if dimensions[0] > limits[0] || dimensions[1] > limits[1] || dimensions[2] > limits[2] {
return Err(FramebufferCreationError::DimensionsTooLarge);
}
}
let mut layers = 1;
if let Some(multiview) = self.render_pass.desc().multiview() {
// There needs to be at least as many layers in the framebuffer
// as the highest layer that gets referenced by the multiview masking.
if multiview.highest_used_layer() > dimensions[2] {
return Err(FramebufferCreationError::InsufficientLayerCount {
minimum: multiview.highest_used_layer(),
current: dimensions[2],
});
}
// VUID-VkFramebufferCreateInfo-renderPass-02531
// The framebuffer has to be created with one layer if multiview is enabled even though
// the underlying images generally have more layers
// but these layers get used by the multiview functionality.
if multiview.view_masks.iter().any(|&mask| mask != 0) {
layers = 1;
}
}
let framebuffer = unsafe {
let fns = device.fns();
let infos = ash::vk::FramebufferCreateInfo {
flags: ash::vk::FramebufferCreateFlags::empty(),
render_pass: self.render_pass.inner().internal_object(),
attachment_count: self.raw_ids.len() as u32,
p_attachments: self.raw_ids.as_ptr(),
width: dimensions[0],
height: dimensions[1],
layers,
..Default::default()
};
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.create_framebuffer(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(Framebuffer {
device,
render_pass: self.render_pass,
framebuffer,
dimensions,
resources: self.attachments,
})
}
}
impl<A> Framebuffer<A> {
/// Returns the width, height and layers of this framebuffer.
#[inline]
pub fn dimensions(&self) -> [u32; 3] {
self.dimensions
}
/// Returns the width of the framebuffer in pixels.
#[inline]
pub fn width(&self) -> u32 {
self.dimensions[0]
}
/// Returns the height of the framebuffer in pixels.
#[inline]
pub fn height(&self) -> u32 {
self.dimensions[1]
}
/// Returns the number of layers (or depth) of the framebuffer.
#[inline]
pub fn layers(&self) -> u32 {
self.dimensions[2]
}
/// Returns the device that was used to create this framebuffer.
#[inline]
pub fn device(&self) -> &Arc<Device> {
&self.device
}
/// Returns the renderpass that was used to create this framebuffer.
#[inline]
pub fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
}
/// Trait for objects that contain a Vulkan framebuffer object.
///
/// Any `Framebuffer` object implements this trait. You can therefore turn a `Arc<Framebuffer<_>>`
/// into a `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
pub unsafe trait FramebufferAbstract {
/// Returns an opaque struct that represents the framebuffer's internals.
fn inner(&self) -> FramebufferSys;
/// Returns the width, height and array layers of the framebuffer.
fn dimensions(&self) -> [u32; 3];
/// Returns the render pass this framebuffer was created for.
fn render_pass(&self) -> &Arc<RenderPass>;
/// Returns the attachment of the framebuffer with the given index.
///
/// If the `index` is not between `0` and `num_attachments`, then `None` should be returned.
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract>;
/// Returns the width of the framebuffer in pixels.
#[inline]
fn width(&self) -> u32 {
self.dimensions()[0]
}
/// Returns the height of the framebuffer in pixels.
#[inline]
fn height(&self) -> u32 {
self.dimensions()[1]
}
/// Returns the number of layers (or depth) of the framebuffer.
#[inline]
fn layers(&self) -> u32 {
self.dimensions()[2]
}
}
unsafe impl<T> FramebufferAbstract for T
where
T: SafeDeref,
T::Target: FramebufferAbstract,
{
#[inline]
fn inner(&self) -> FramebufferSys {
FramebufferAbstract::inner(&**self)
}
#[inline]
fn dimensions(&self) -> [u32; 3] {
(**self).dimensions()
}
#[inline]
fn render_pass(&self) -> &Arc<RenderPass> {
(**self).render_pass()
}
#[inline]
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
(**self).attached_image_view(index)
}
}
unsafe impl<A> FramebufferAbstract for Framebuffer<A>
where
A: AttachmentsList,
{
#[inline]
fn inner(&self) -> FramebufferSys {
FramebufferSys(self.framebuffer, PhantomData)
}
#[inline]
fn dimensions(&self) -> [u32; 3] {
self.dimensions
}
#[inline]
fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
#[inline]
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
self.resources.as_image_view_access(index)
}
}
unsafe impl<A> DeviceOwned for Framebuffer<A> {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl<A> Drop for Framebuffer<A> {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0.destroy_framebuffer(
self.device.internal_object(),
self.framebuffer,
ptr::null(),
);
}
}
}
/// Opaque object that represents the internals of a framebuffer.
#[derive(Debug, Copy, Clone)]
pub struct FramebufferSys<'a>(ash::vk::Framebuffer, PhantomData<&'a ()>);
unsafe impl<'a> VulkanObject for FramebufferSys<'a> {
type Object = ash::vk::Framebuffer;
#[inline]
fn internal_object(&self) -> ash::vk::Framebuffer {
self.0
}
}
/// Error that can happen when creating a framebuffer object.
#[derive(Copy, Clone, Debug)]
pub enum FramebufferCreationError {
/// Out of memory.
OomError(OomError),
/// The requested dimensions exceed the device's limits.
DimensionsTooLarge,
/// The number of minimum layers expected by the render pass exceed the framebuffer layers.
/// This can happen when the multiview feature is enabled and the specified view or correlation
/// masks refer to more layers than the framebuffer has.
InsufficientLayerCount {
/// Minimum number of layers.
minimum: u32,
/// Number of framebuffer layers.
current: u32,
},
/// 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.
expected: usize,
/// Number of attachments that were given.
obtained: usize,
},
/// One of the images cannot be used as the requested attachment.
IncompatibleAttachment(IncompatibleRenderPassAttachmentError),
/// The framebuffer has no attachment and no dimension was specified.
CantDetermineDimensions,
}
impl From<OomError> for FramebufferCreationError {
#[inline]
fn from(err: OomError) -> FramebufferCreationError {
FramebufferCreationError::OomError(err)
}
}
impl error::Error for FramebufferCreationError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
FramebufferCreationError::OomError(ref err) => Some(err),
FramebufferCreationError::IncompatibleAttachment(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for FramebufferCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
FramebufferCreationError::OomError(_) => "no memory available",
FramebufferCreationError::DimensionsTooLarge => {
"the dimensions of the framebuffer are too large"
}
FramebufferCreationError::InsufficientLayerCount { .. } => {
"the number of minimum layers expected by the render pass exceed the framebuffer layers"
}
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(_) => {
"one of the images cannot be used as the requested attachment"
}
FramebufferCreationError::CantDetermineDimensions => {
"the framebuffer has no attachment and no dimension was specified"
}
}
)
}
}
impl From<Error> for FramebufferCreationError {
#[inline]
fn from(err: Error) -> FramebufferCreationError {
FramebufferCreationError::from(OomError::from(err))
}
}
#[cfg(test)]
mod tests {
use crate::format::Format;
use crate::image::attachment::AttachmentImage;
use crate::image::view::ImageView;
use crate::render_pass::Framebuffer;
use crate::render_pass::FramebufferCreationError;
use crate::render_pass::RenderPass;
use std::sync::Arc;
#[test]
fn simple_create() {
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 view = ImageView::new(
AttachmentImage::new(device.clone(), [1024, 768], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
let _ = Framebuffer::start(render_pass)
.add(view)
.unwrap()
.build()
.unwrap();
}
#[test]
fn check_device_limits() {
let (device, _) = gfx_dev_and_queue!();
let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
let res = Framebuffer::with_dimensions(rp, [0xffffffff, 0xffffffff, 0xffffffff]).build();
match res {
Err(FramebufferCreationError::DimensionsTooLarge) => (),
_ => panic!(),
}
}
#[test]
fn attachment_format_mismatch() {
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 view = ImageView::new(
AttachmentImage::new(device.clone(), [1024, 768], Format::R8Unorm).unwrap(),
)
.unwrap();
match Framebuffer::start(render_pass).add(view) {
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 view = ImageView::new(
AttachmentImage::new(device.clone(), [600, 600], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
let _ = Framebuffer::with_dimensions(render_pass, [512, 512, 1])
.add(view)
.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 view = ImageView::new(
AttachmentImage::new(device.clone(), [512, 700], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
match Framebuffer::with_dimensions(render_pass, [600, 600, 1]).add(view) {
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 = ImageView::new(
AttachmentImage::new(device.clone(), [512, 512], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
let b = ImageView::new(
AttachmentImage::new(device.clone(), [512, 513], Format::R8G8B8A8Unorm).unwrap(),
)
.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 = ImageView::new(
AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
let b = ImageView::new(
AttachmentImage::new(device.clone(), [512, 128], Format::R8G8B8A8Unorm).unwrap(),
)
.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 view = ImageView::new(
AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
let res = Framebuffer::with_intersecting_dimensions(render_pass)
.add(view)
.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 = ImageView::new(
AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
)
.unwrap();
let b = ImageView::new(
AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
)
.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 = Arc::new(RenderPass::empty_single_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 = Arc::new(RenderPass::empty_single_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 = Arc::new(RenderPass::empty_single_pass(device).unwrap());
let res = Framebuffer::with_intersecting_dimensions(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),
_ => panic!(),
}
}
}