use std::error;
use std::fmt;
use format::Format;
use framebuffer::RenderPassDesc;
use image::ImageViewAccess;
pub fn ensure_image_view_compatible<Rp, I>(render_pass: &Rp, attachment_num: usize, image: &I)
-> Result<(), IncompatibleRenderPassAttachmentError>
where Rp: ?Sized + RenderPassDesc,
I: ?Sized + ImageViewAccess
{
let attachment_desc = render_pass.attachment_desc(attachment_num)
.expect("Attachment num out of range");
if image.format() != attachment_desc.format {
return Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
expected: attachment_desc.format,
obtained: image.format(),
});
}
if image.samples() != attachment_desc.samples {
return Err(IncompatibleRenderPassAttachmentError::SamplesMismatch {
expected: attachment_desc.samples,
obtained: image.samples(),
});
}
if !image.identity_swizzle() {
return Err(IncompatibleRenderPassAttachmentError::NotIdentitySwizzled);
}
for subpass_num in 0 .. render_pass.num_subpasses() {
let subpass = render_pass.subpass_desc(subpass_num).expect("Subpass num out of range ; \
wrong RenderPassDesc trait impl");
if subpass.color_attachments.iter().any(|&(n, _)| n == attachment_num) {
debug_assert!(image.parent().has_color()); if !image.parent().inner().usage_color_attachment() {
return Err(IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage);
}
}
if let Some((ds, _)) = subpass.depth_stencil {
if ds == attachment_num {
debug_assert!(image.parent().has_depth() || image.parent().has_stencil());
if !image.parent().inner().usage_depth_stencil_attachment() {
return Err(IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage);
}
}
}
if subpass.input_attachments.iter().any(|&(n, _)| n == attachment_num) {
if !image.parent().inner().usage_input_attachment() {
return Err(IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage);
}
}
}
Ok(())
}
#[derive(Copy, Clone, Debug)]
pub enum IncompatibleRenderPassAttachmentError {
FormatMismatch {
expected: Format,
obtained: Format,
},
SamplesMismatch {
expected: u32,
obtained: u32,
},
NotIdentitySwizzled,
MissingColorAttachmentUsage,
MissingDepthStencilAttachmentUsage,
MissingInputAttachmentUsage,
}
impl error::Error for IncompatibleRenderPassAttachmentError {
#[inline]
fn description(&self) -> &str {
match *self {
IncompatibleRenderPassAttachmentError::FormatMismatch { .. } => {
"mismatch between the format expected by the render pass and the actual format"
},
IncompatibleRenderPassAttachmentError::SamplesMismatch { .. } => {
"mismatch between the number of samples expected by the render pass and the actual \
number of samples"
},
IncompatibleRenderPassAttachmentError::NotIdentitySwizzled => {
"the image view does not use identity swizzling"
},
IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage => {
"the image is used as a color attachment but is missing the color attachment usage"
},
IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage => {
"the image is used as a depth/stencil attachment but is missing the depth-stencil \
attachment usage"
},
IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage => {
"the image is used as an input attachment but is missing the input \
attachment usage"
},
}
}
}
impl fmt::Display for IncompatibleRenderPassAttachmentError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
#[cfg(test)]
mod tests {
use format::Format;
use framebuffer::EmptySinglePassRenderPassDesc;
use image::AttachmentImage;
use image::ImageView;
use super::ensure_image_view_compatible;
use super::IncompatibleRenderPassAttachmentError;
#[test]
fn basic_ok() {
let (device, _) = gfx_dev_and_queue!();
let rp = single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: Store,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap();
let img = AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap();
ensure_image_view_compatible(&rp, 0, &img.access()).unwrap();
}
#[test]
fn format_mismatch() {
let (device, _) = gfx_dev_and_queue!();
let rp = single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: Store,
format: Format::R16G16Sfloat,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap();
let img = AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap();
match ensure_image_view_compatible(&rp, 0, &img.access()) {
Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
expected: Format::R16G16Sfloat, obtained: Format::R8G8B8A8Unorm }) => (),
e => panic!("{:?}", e)
}
}
#[test]
#[should_panic(expected = "Attachment num out of range")]
fn attachment_out_of_range() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc;
let img = AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap();
let _ = ensure_image_view_compatible(&rp, 0, &img.access());
}
}