use std::iter::Empty;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use device::Device;
use device::Queue;
use format::ClearValue;
use format::Format;
use format::FormatDesc;
use format::FormatTy;
use image::Dimensions;
use image::ImageDimensions;
use image::ViewType;
use image::sys::ImageCreationError;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageViewAccess;
use image::traits::Image;
use image::traits::ImageView;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPoolAlloc;
use sync::AccessError;
use sync::Sharing;
#[derive(Debug)]
pub struct AttachmentImage<F = Format, A = StdMemoryPoolAlloc> {
image: UnsafeImage,
view: UnsafeImageView,
memory: A,
format: F,
attachment_layout: ImageLayout,
gpu_lock: AtomicUsize,
}
impl<F> AttachmentImage<F> {
#[inline]
pub fn new(device: Arc<Device>, dimensions: [u32; 2], format: F)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
AttachmentImage::new_impl(device, dimensions, format, ImageUsage::none(), 1)
}
#[inline]
pub fn multisampled(device: Arc<Device>, dimensions: [u32; 2], samples: u32, format: F)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
AttachmentImage::new_impl(device, dimensions, format, ImageUsage::none(), samples)
}
#[inline]
pub fn with_usage(device: Arc<Device>, dimensions: [u32; 2], format: F, usage: ImageUsage)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
AttachmentImage::new_impl(device, dimensions, format, usage, 1)
}
#[inline]
pub fn multisampled_with_usage(device: Arc<Device>, dimensions: [u32; 2], samples: u32,
format: F, usage: ImageUsage)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
AttachmentImage::new_impl(device, dimensions, format, usage, samples)
}
#[inline]
pub fn transient(device: Arc<Device>, dimensions: [u32; 2], format: F)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
let base_usage = ImageUsage {
transient_attachment: true,
.. ImageUsage::none()
};
AttachmentImage::new_impl(device, dimensions, format, base_usage, 1)
}
#[inline]
pub fn transient_multisampled(device: Arc<Device>, dimensions: [u32; 2], samples: u32, format: F)
-> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
let base_usage = ImageUsage {
transient_attachment: true,
.. ImageUsage::none()
};
AttachmentImage::new_impl(device, dimensions, format, base_usage, samples)
}
fn new_impl(device: Arc<Device>, dimensions: [u32; 2], format: F, base_usage: ImageUsage,
samples: u32) -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
where F: FormatDesc
{
let is_depth = match format.format().ty() {
FormatTy::Depth => true,
FormatTy::DepthStencil => true,
FormatTy::Stencil => true,
FormatTy::Compressed => panic!(),
_ => false
};
let usage = ImageUsage {
color_attachment: !is_depth,
depth_stencil_attachment: is_depth,
.. base_usage
};
let (image, mem_reqs) = unsafe {
let dims = ImageDimensions::Dim2d {
width: dimensions[0],
height: dimensions[1],
array_layers: 1,
cubemap_compatible: false
};
try!(UnsafeImage::new(device.clone(), usage, format.format(), dims,
samples, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
};
let mem_ty = {
let device_local = device.physical_device().memory_types()
.filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
.filter(|t| t.is_device_local());
let any = device.physical_device().memory_types()
.filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
device_local.chain(any).next().unwrap()
};
let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }
let view = unsafe {
try!(UnsafeImageView::raw(&image, ViewType::Dim2d, 0 .. 1, 0 .. 1))
};
Ok(Arc::new(AttachmentImage {
image: image,
view: view,
memory: mem,
format: format,
attachment_layout: if is_depth { ImageLayout::DepthStencilAttachmentOptimal }
else { ImageLayout::ColorAttachmentOptimal },
gpu_lock: AtomicUsize::new(0),
}))
}
}
impl<F, A> AttachmentImage<F, A> {
#[inline]
pub fn dimensions(&self) -> [u32; 2] {
let dims = self.image.dimensions();
[dims.width(), dims.height()]
}
}
pub struct AttachmentImageAccess<F, A> {
img: Arc<AttachmentImage<F, A>>,
already_locked: AtomicBool,
}
impl<F, A> Clone for AttachmentImageAccess<F, A> {
#[inline]
fn clone(&self) -> AttachmentImageAccess<F, A> {
AttachmentImageAccess {
img: self.img.clone(),
already_locked: AtomicBool::new(self.already_locked.load(Ordering::SeqCst))
}
}
}
unsafe impl<F, A> ImageAccess for AttachmentImageAccess<F, A>
where F: 'static + Send + Sync
{
#[inline]
fn inner(&self) -> &UnsafeImage {
&self.img.image
}
#[inline]
fn initial_layout_requirement(&self) -> ImageLayout {
self.img.attachment_layout
}
#[inline]
fn final_layout_requirement(&self) -> ImageLayout {
self.img.attachment_layout
}
#[inline]
fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
self.img.image.key()
}
#[inline]
fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
Ok(())
}
#[inline]
unsafe fn increase_gpu_lock(&self) {
}
}
impl<F, A> Drop for AttachmentImageAccess<F, A> {
fn drop(&mut self) {
if self.already_locked.load(Ordering::SeqCst) {
let prev_val = self.img.gpu_lock.fetch_sub(1, Ordering::SeqCst);
debug_assert!(prev_val >= 1);
}
}
}
unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImageAccess<F, A>
where F: FormatDesc + 'static + Send + Sync
{
#[inline]
fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
Some(self.img.format.decode_clear_value(value))
}
}
unsafe impl<P, F, A> ImageContent<P> for AttachmentImageAccess<F, A>
where F: 'static + Send + Sync
{
#[inline]
fn matches_format(&self) -> bool {
true }
}
unsafe impl<F, A> Image for Arc<AttachmentImage<F, A>>
where F: 'static + Send + Sync
{
type Access = AttachmentImageAccess<F, A>;
#[inline]
fn access(self) -> AttachmentImageAccess<F, A> {
AttachmentImageAccess {
img: self,
already_locked: AtomicBool::new(false),
}
}
#[inline]
fn format(&self) -> Format {
self.image.format()
}
#[inline]
fn samples(&self) -> u32 {
self.image.samples()
}
#[inline]
fn dimensions(&self) -> ImageDimensions {
self.image.dimensions()
}
}
unsafe impl<F, A> ImageView for Arc<AttachmentImage<F, A>>
where F: 'static + Send + Sync
{
type Access = AttachmentImageAccess<F, A>;
#[inline]
fn access(self) -> AttachmentImageAccess<F, A> {
AttachmentImageAccess {
img: self,
already_locked: AtomicBool::new(false),
}
}
}
unsafe impl<F, A> ImageViewAccess for AttachmentImageAccess<F, A>
where F: 'static + Send + Sync
{
#[inline]
fn parent(&self) -> &ImageAccess {
self
}
#[inline]
fn dimensions(&self) -> Dimensions {
let dims = self.img.image.dimensions();
Dimensions::Dim2d { width: dims.width(), height: dims.height() }
}
#[inline]
fn inner(&self) -> &UnsafeImageView {
&self.img.view
}
#[inline]
fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
ImageLayout::ShaderReadOnlyOptimal
}
#[inline]
fn identity_swizzle(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::AttachmentImage;
use format::Format;
#[test]
fn create_regular() {
let (device, _) = gfx_dev_and_queue!();
let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
}
#[test]
fn create_transient() {
let (device, _) = gfx_dev_and_queue!();
let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
}
#[test]
fn d16_unorm_always_supported() {
let (device, _) = gfx_dev_and_queue!();
let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap();
}
}