From 8a3bf4d191c36a486d0c81acce93b546537e0737 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 22 Jul 2017 11:08:52 -0700 Subject: [PATCH 1/3] Refactor ImmutableImage for convenient, safe initialization --- examples/src/bin/debug.rs | 8 +- examples/src/bin/image.rs | 30 ++--- vulkano/Cargo.toml | 1 + vulkano/src/format.rs | 94 +++++++++++++- vulkano/src/image/immutable.rs | 229 ++++++++++++++++++++++++--------- vulkano/src/image/mod.rs | 5 + vulkano/src/lib.rs | 1 + 7 files changed, 285 insertions(+), 83 deletions(-) diff --git a/examples/src/bin/debug.rs b/examples/src/bin/debug.rs index ae39aa9a3..e372f2dc6 100644 --- a/examples/src/bin/debug.rs +++ b/examples/src/bin/debug.rs @@ -11,7 +11,7 @@ extern crate vulkano; use vulkano::device::{Device, DeviceExtensions}; use vulkano::format::Format; -use vulkano::image::ImmutableImage; +use vulkano::image::{ImmutableImage, ImageUsage, ImageLayout}; use vulkano::image::Dimensions; use vulkano::instance; use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice}; @@ -98,8 +98,12 @@ fn main() { // Create an image in order to generate some additional logging: let pixel_format = Format::R8G8B8A8Uint; + let usage = ImageUsage { sampled: true, ..ImageUsage::none() }; + let layout = ImageLayout::ShaderReadOnlyOptimal; let dimensions = Dimensions::Dim2d { width: 4096, height: 4096 }; - ImmutableImage::new(device.clone(), dimensions, pixel_format, Some(queue.family())).unwrap(); + const data: [[u8; 4]; 4096*4096] = [[0; 4]; 4096 * 4096]; + let (image, _) = ImmutableImage::from_iter(data.iter().cloned(), dimensions, pixel_format, + usage, layout, Some(queue.family()), queue.clone()).unwrap(); // (At this point you should see a bunch of messages printed to the terminal window - have fun debugging!) } diff --git a/examples/src/bin/image.rs b/examples/src/bin/image.rs index f360ef13c..1c0a30218 100644 --- a/examples/src/bin/image.rs +++ b/examples/src/bin/image.rs @@ -24,7 +24,6 @@ use vulkano_win::VkSurfaceBuild; use vulkano::sync::GpuFuture; use std::sync::Arc; -use std::time::Duration; fn main() { // The start of this example is exactly the same as `triangle`. You should read the @@ -102,22 +101,19 @@ fn main() { ).unwrap() ); - let texture = vulkano::image::immutable::ImmutableImage::new(device.clone(), vulkano::image::Dimensions::Dim2d { width: 93, height: 93 }, - vulkano::format::R8G8B8A8Srgb, Some(queue.family())).unwrap(); - - - let pixel_buffer = { + let (texture, tex_future) = { let image = image::load_from_memory_with_format(include_bytes!("image_img.png"), image::ImageFormat::PNG).unwrap().to_rgba(); let image_data = image.into_raw().clone(); - let image_data_chunks = image_data.chunks(4).map(|c| [c[0], c[1], c[2], c[3]]); - - // TODO: staging buffer instead - vulkano::buffer::cpu_access::CpuAccessibleBuffer::<[[u8; 4]]> - ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), - Some(queue.family()), image_data_chunks) - .expect("failed to create buffer") + vulkano::image::immutable::ImmutableImage::from_iter( + image_data.iter().cloned(), + vulkano::image::Dimensions::Dim2d { width: 93, height: 93 }, + vulkano::format::R8G8B8A8Srgb, + vulkano::image::ImageUsage { sampled: true, ..vulkano::image::ImageUsage::none() }, + vulkano::image::ImageLayout::ShaderReadOnlyOptimal, + Some(queue.family()), + queue.clone()).unwrap() }; @@ -138,6 +134,7 @@ fn main() { dimensions: [images[0].dimensions()[0] as f32, images[0].dimensions()[1] as f32], })) .fragment_shader(fs.main_entry_point(), ()) + .blend_alpha_blending() .render_pass(vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap()) .build(device.clone()) .unwrap()); @@ -152,7 +149,7 @@ fn main() { .add(image.clone()).unwrap().build().unwrap()) }).collect::>(); - let mut previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box; + let mut previous_frame_end = Box::new(tex_future) as Box; loop { previous_frame_end.cleanup_finished(); @@ -161,12 +158,9 @@ fn main() { let cb = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()) .unwrap() - .copy_buffer_to_image(pixel_buffer.clone(), texture.clone()) - .unwrap() - //.clear_color_image(&texture, [0.0, 1.0, 0.0, 1.0]) .begin_render_pass( framebuffers[image_num].clone(), false, - vec![[0.0, 0.0, 1.0, 1.0].into()]).unwrap() + vec![[1.0, 1.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() diff --git a/vulkano/Cargo.toml b/vulkano/Cargo.toml index 069e54083..b369b7fc9 100644 --- a/vulkano/Cargo.toml +++ b/vulkano/Cargo.toml @@ -16,3 +16,4 @@ shared_library = "0.1.5" smallvec = "0.3.1" lazy_static = "0.2.2" vk-sys = { version = "0.3.0", path = "../vk-sys" } +half = "1" diff --git a/vulkano/src/format.rs b/vulkano/src/format.rs index ce0401106..fad581acf 100644 --- a/vulkano/src/format.rs +++ b/vulkano/src/format.rs @@ -103,6 +103,10 @@ //! use std::vec::IntoIter as VecIntoIter; +use std::{mem, error, fmt}; + +use half::f16; + use vk; // TODO: add enumerations for color, depth, stencil and depthstencil formats @@ -132,6 +136,39 @@ unsafe impl Data for u8 { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct IncompatiblePixelsType; + +impl error::Error for IncompatiblePixelsType { + #[inline] + fn description(&self) -> &str { "supplied pixels' type is incompatible with this format" } +} + +impl fmt::Display for IncompatiblePixelsType { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(fmt, "{}", error::Error::description(self)) + } +} + +pub unsafe trait AcceptsPixels { + /// Returns an error if `T` cannot be used as a source of pixels for `Self`. + fn ensure_accepts(&self) -> Result<(), IncompatiblePixelsType>; + + /// The number of `T`s which make up a single pixel. + /// + /// ``` + /// use vulkano::format::{AcceptsPixels, R8G8B8A8Srgb}; + /// assert_eq!(>::rate(&R8G8B8A8Srgb), 1); + /// assert_eq!(>::rate(&R8G8B8A8Srgb), 4); + /// ``` + /// + /// # Panics + /// + /// May panic if `ensure_accepts` would not return `Ok(())`. + fn rate(&self) -> u32 { 1 } +} + macro_rules! formats { ($($name:ident => $vk:ident [$sz:expr] [$($f_ty:tt)*] {$($d_ty:tt)*},)+) => ( /// An enumeration of all the possible formats. @@ -357,12 +394,26 @@ macro_rules! formats { (__inner_ty__ $name:ident compressed=$f:tt) => { FormatTy::Compressed }; + (__inner_strongstorage__ $name:ident [$ty:ty; $dim:expr]) => { + formats!(__inner_strongstorage_common__ $name [$ty; $dim]); + unsafe impl AcceptsPixels<$ty> for $name { + fn ensure_accepts(&self) -> Result<(), IncompatiblePixelsType> { Ok(()) } + fn rate(&self) -> u32 { $dim } + } + }; (__inner_strongstorage__ $name:ident $ty:ty) => { + formats!(__inner_strongstorage_common__ $name $ty); + }; + (__inner_strongstorage__ $name:ident ) => {}; + + (__inner_strongstorage_common__ $name:ident $ty:ty) => { unsafe impl StrongStorage for $name { type Pixel = $ty; } + unsafe impl AcceptsPixels<$ty> for $name { + fn ensure_accepts(&self) -> Result<(), IncompatiblePixelsType> { Ok(()) } + } }; - (__inner_strongstorage__ $name:ident ) => {}; } formats! { @@ -441,28 +492,28 @@ formats! { R16Sscaled => FORMAT_R16_SSCALED [Some(2)] [float=1] {i16}, R16Uint => FORMAT_R16_UINT [Some(2)] [uint=1] {u16}, R16Sint => FORMAT_R16_SINT [Some(2)] [sint=1] {i16}, - R16Sfloat => FORMAT_R16_SFLOAT [Some(2)] [float=1] {}, + R16Sfloat => FORMAT_R16_SFLOAT [Some(2)] [float=1] {f16}, R16G16Unorm => FORMAT_R16G16_UNORM [Some(4)] [float=2] {[u16; 2]}, R16G16Snorm => FORMAT_R16G16_SNORM [Some(4)] [float=2] {[i16; 2]}, R16G16Uscaled => FORMAT_R16G16_USCALED [Some(4)] [float=2] {[u16; 2]}, R16G16Sscaled => FORMAT_R16G16_SSCALED [Some(4)] [float=2] {[i16; 2]}, R16G16Uint => FORMAT_R16G16_UINT [Some(4)] [uint=2] {[u16; 2]}, R16G16Sint => FORMAT_R16G16_SINT [Some(4)] [sint=2] {[i16; 2]}, - R16G16Sfloat => FORMAT_R16G16_SFLOAT [Some(4)] [float=2] {}, + R16G16Sfloat => FORMAT_R16G16_SFLOAT [Some(4)] [float=2] {[f16; 2]}, R16G16B16Unorm => FORMAT_R16G16B16_UNORM [Some(6)] [float=3] {[u16; 3]}, R16G16B16Snorm => FORMAT_R16G16B16_SNORM [Some(6)] [float=3] {[i16; 3]}, R16G16B16Uscaled => FORMAT_R16G16B16_USCALED [Some(6)] [float=3] {[u16; 3]}, R16G16B16Sscaled => FORMAT_R16G16B16_SSCALED [Some(6)] [float=3] {[i16; 3]}, R16G16B16Uint => FORMAT_R16G16B16_UINT [Some(6)] [uint=3] {[u16; 3]}, R16G16B16Sint => FORMAT_R16G16B16_SINT [Some(6)] [sint=3] {[i16; 3]}, - R16G16B16Sfloat => FORMAT_R16G16B16_SFLOAT [Some(6)] [float=3] {}, + R16G16B16Sfloat => FORMAT_R16G16B16_SFLOAT [Some(6)] [float=3] {[f16; 3]}, R16G16B16A16Unorm => FORMAT_R16G16B16A16_UNORM [Some(8)] [float=4] {[u16; 4]}, R16G16B16A16Snorm => FORMAT_R16G16B16A16_SNORM [Some(8)] [float=4] {[i16; 4]}, R16G16B16A16Uscaled => FORMAT_R16G16B16A16_USCALED [Some(8)] [float=4] {[u16; 4]}, R16G16B16A16Sscaled => FORMAT_R16G16B16A16_SSCALED [Some(8)] [float=4] {[i16; 4]}, R16G16B16A16Uint => FORMAT_R16G16B16A16_UINT [Some(8)] [uint=4] {[u16; 4]}, R16G16B16A16Sint => FORMAT_R16G16B16A16_SINT [Some(8)] [sint=4] {[i16; 4]}, - R16G16B16A16Sfloat => FORMAT_R16G16B16A16_SFLOAT [Some(8)] [float=4] {}, + R16G16B16A16Sfloat => FORMAT_R16G16B16A16_SFLOAT [Some(8)] [float=4] {[f16; 4]}, R32Uint => FORMAT_R32_UINT [Some(4)] [uint=1] {u32}, R32Sint => FORMAT_R32_SINT [Some(4)] [sint=1] {i32}, R32Sfloat => FORMAT_R32_SFLOAT [Some(4)] [float=1] {f32}, @@ -674,6 +725,39 @@ unsafe impl PossibleFloatOrCompressedFormatDesc for Format { } } +macro_rules! impl_pixel { + {$($ty:ty;)+} => { + $(impl_pixel!(inner $ty);)* + $(impl_pixel!(inner [$ty; 1]);)* + $(impl_pixel!(inner [$ty; 2]);)* + $(impl_pixel!(inner [$ty; 3]);)* + $(impl_pixel!(inner [$ty; 4]);)* + $(impl_pixel!(inner ($ty,));)* + $(impl_pixel!(inner ($ty, $ty));)* + $(impl_pixel!(inner ($ty, $ty, $ty));)* + $(impl_pixel!(inner ($ty, $ty, $ty, $ty));)* + }; + (inner $ty:ty) => { + unsafe impl AcceptsPixels<$ty> for Format { + fn ensure_accepts(&self) -> Result<(), IncompatiblePixelsType> { + // TODO: Be more strict: accept only if the format has a matching AcceptsPixels impl. + if self.size().map_or(false, |x| x % mem::size_of::<$ty>() == 0) { + Ok(()) + } else { + Err(IncompatiblePixelsType) + } + } + fn rate(&self) -> u32 { + (self.size().expect("this format cannot accept pixels") / mem::size_of::<$ty>()) as u32 + } + } + } +} + +impl_pixel! { + u8; i8; u16; i16; u32; i32; u64; i64; f16; f32; f64; +} + pub unsafe trait StrongStorage: FormatDesc { type Pixel: Copy; } diff --git a/vulkano/src/image/immutable.rs b/vulkano/src/image/immutable.rs index ba4d5dc3e..e322dd917 100644 --- a/vulkano/src/image/immutable.rs +++ b/vulkano/src/image/immutable.rs @@ -9,9 +9,21 @@ use smallvec::SmallVec; use std::sync::Arc; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; +use std::iter; +use buffer::BufferAccess; +use buffer::BufferUsage; +use buffer::CpuAccessibleBuffer; +use buffer::TypedBufferAccess; +use command_buffer::AutoCommandBuffer; +use command_buffer::AutoCommandBufferBuilder; +use command_buffer::CommandBuffer; +use command_buffer::CommandBufferExecFuture; use device::Device; use device::Queue; +use format::AcceptsPixels; use format::FormatDesc; use image::Dimensions; use image::ImageInner; @@ -28,55 +40,42 @@ use instance::QueueFamily; use memory::pool::AllocLayout; use memory::pool::MemoryPool; use memory::pool::MemoryPoolAlloc; -use memory::pool::StdMemoryPool; +use memory::pool::StdMemoryPoolAlloc; use sync::AccessError; use sync::Sharing; +use sync::NowFuture; /// Image whose purpose is to be used for read-only purposes. You can write to the image once, -/// but then you must only ever read from it. TODO: clarify because of blit operations +/// but then you must only ever read from it. // TODO: type (2D, 3D, array, etc.) as template parameter #[derive(Debug)] -pub struct ImmutableImage> - where A: MemoryPool -{ +pub struct ImmutableImage { image: UnsafeImage, view: UnsafeImageView, dimensions: Dimensions, - memory: A::Alloc, + memory: A, format: F, + initialized: AtomicBool, + layout: ImageLayout, +} + +// Must not implement Clone, as that would lead to multiple `used` values. +pub struct ImmutableImageInitialization { + image: Arc>, + used: AtomicBool, } impl ImmutableImage { - /// Builds a new immutable image. - // TODO: one mipmap is probably not a great default - #[inline] - pub fn new<'a, I>(device: Arc, dimensions: Dimensions, format: F, queue_families: I) - -> Result>, ImageCreationError> - where F: FormatDesc, - I: IntoIterator> - { - ImmutableImage::with_mipmaps(device, - dimensions, - format, - MipmapsCount::One, - queue_families) - } - - /// Builds a new immutable image with the given number of mipmaps. - pub fn with_mipmaps<'a, I, M>(device: Arc, dimensions: Dimensions, format: F, - mipmaps: M, queue_families: I) - -> Result>, ImageCreationError> + /// Builds an uninitialized immutable image. + /// + /// Returns two things: the image, and a special access that should be used for the initial upload to the image. + pub fn uninitialized<'a, I, M>(device: Arc, dimensions: Dimensions, format: F, + mipmaps: M, usage: ImageUsage, layout: ImageLayout, queue_families: I) + -> Result<(Arc>, ImmutableImageInitialization), ImageCreationError> where F: FormatDesc, I: IntoIterator>, M: Into { - let usage = ImageUsage { - transfer_source: true, // for blits - transfer_destination: true, - sampled: true, - ..ImageUsage::none() - }; - let queue_families = queue_families .into_iter() .map(|f| f.id()) @@ -130,19 +129,84 @@ impl ImmutableImage { 0 .. image.dimensions().array_layers())? }; - Ok(Arc::new(ImmutableImage { - image: image, - view: view, - memory: mem, - dimensions: dimensions, - format: format, - })) + let image = Arc::new(ImmutableImage { + image: image, + view: view, + memory: mem, + dimensions: dimensions, + format: format, + initialized: AtomicBool::new(false), + layout: layout, + }); + + let init = ImmutableImageInitialization { + image: image.clone(), + used: AtomicBool::new(false), + }; + + Ok((image, init)) + } + + /// Construct an ImmutableImage from the contents of `iter`. + /// + /// TODO: Support mipmaps + #[inline] + pub fn from_iter<'a, P, I, J>(iter: I, dimensions: Dimensions, format: F, usage: ImageUsage, layout: ImageLayout, + queue_families: J, queue: Arc) + -> Result<(Arc, CommandBufferExecFuture), + ImageCreationError> + where P: Send + Sync + Clone + 'static, + F: FormatDesc + AcceptsPixels

+ 'static + Send + Sync, + I: ExactSizeIterator, + J: IntoIterator>, + { + let source = CpuAccessibleBuffer::from_iter(queue.device().clone(), + BufferUsage::transfer_source(), + iter::once(queue.family()), + iter)?; + ImmutableImage::from_buffer(source, dimensions, format, usage, layout, queue_families, queue) + } + + /// Construct an ImmutableImage containing a copy of the data in `source`. + /// + /// TODO: Support mipmaps + pub fn from_buffer<'a, B, P, I>(source: B, dimensions: Dimensions, format: F, usage: ImageUsage, layout: ImageLayout, queue_families: I, queue: Arc) + -> Result<(Arc, CommandBufferExecFuture), + ImageCreationError> + where B: BufferAccess + TypedBufferAccess + 'static + Clone + Send + Sync, + P: Send + Sync + Clone + 'static, + F: FormatDesc + AcceptsPixels

+ 'static + Send + Sync, + I: IntoIterator>, + { + let usage = ImageUsage { transfer_destination: true, ..usage }; // Ensure we can actually initialize the image + // TODO: The following panics should be removed in favor of propagating errors from copy_buffer_to_image. + format.ensure_accepts().unwrap(); + if source.len() % format.rate() as usize != 0 { + panic!("cannot divide {} datums into an image with {} channels", source.len(), format.rate()); + } + if dimensions.num_texels() as usize * format.rate() as usize != source.len() { + panic!("image with {} texels cannot be initialized with {}", dimensions.num_texels(), source.len() / format.rate() as usize); + } + + let (buffer, init) = ImmutableImage::uninitialized(source.device().clone(), + dimensions, format, + MipmapsCount::One, usage, layout, + queue_families)?; + + let cb = AutoCommandBufferBuilder::new(source.device().clone(), queue.family())? + .copy_buffer_to_image_dimensions(source, init, [0, 0, 0], dimensions.width_height_depth(), 0, dimensions.array_layers_with_cube(), 0).unwrap() + .build().unwrap(); + + let future = match cb.execute(queue) { + Ok(f) => f, + Err(_) => unreachable!(), + }; + + Ok((buffer, future)) } } -impl ImmutableImage - where A: MemoryPool -{ +impl ImmutableImage { /// Returns the dimensions of the image. #[inline] pub fn dimensions(&self) -> Dimensions { @@ -158,7 +222,6 @@ impl ImmutableImage unsafe impl ImageAccess for ImmutableImage where F: 'static + Send + Sync, - A: MemoryPool { #[inline] fn inner(&self) -> ImageInner { @@ -173,12 +236,12 @@ unsafe impl ImageAccess for ImmutableImage #[inline] fn initial_layout_requirement(&self) -> ImageLayout { - ImageLayout::ShaderReadOnlyOptimal // TODO: ? + self.layout } #[inline] fn final_layout_requirement(&self) -> ImageLayout { - ImageLayout::ShaderReadOnlyOptimal // TODO: ? + self.layout } #[inline] @@ -188,23 +251,26 @@ unsafe impl ImageAccess for ImmutableImage #[inline] fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> { - Ok(()) // FIXME: + if exclusive_access { + return Err(AccessError::ExclusiveDenied); + } + + if !self.initialized.load(Ordering::Relaxed) { + return Err(AccessError::BufferNotInitialized); + } + + Ok(()) } #[inline] - unsafe fn increase_gpu_lock(&self) { - // FIXME: - } + unsafe fn increase_gpu_lock(&self) {} #[inline] - unsafe fn unlock(&self) { - // TODO: - } + unsafe fn unlock(&self) {} } unsafe impl ImageContent

for ImmutableImage where F: 'static + Send + Sync, - A: MemoryPool { #[inline] fn matches_format(&self) -> bool { @@ -214,7 +280,6 @@ unsafe impl ImageContent

for ImmutableImage unsafe impl ImageViewAccess for ImmutableImage where F: 'static + Send + Sync, - A: MemoryPool { #[inline] fn parent(&self) -> &ImageAccess { @@ -233,22 +298,22 @@ unsafe impl ImageViewAccess for ImmutableImage #[inline] fn descriptor_set_storage_image_layout(&self) -> ImageLayout { - ImageLayout::ShaderReadOnlyOptimal + self.layout } #[inline] fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout { - ImageLayout::ShaderReadOnlyOptimal + self.layout } #[inline] fn descriptor_set_sampled_image_layout(&self) -> ImageLayout { - ImageLayout::ShaderReadOnlyOptimal + self.layout } #[inline] fn descriptor_set_input_attachment_layout(&self) -> ImageLayout { - ImageLayout::ShaderReadOnlyOptimal + self.layout } #[inline] @@ -256,3 +321,51 @@ unsafe impl ImageViewAccess for ImmutableImage true } } + +unsafe impl ImageAccess for ImmutableImageInitialization + where F: 'static + Send + Sync, +{ + #[inline] + fn inner(&self) -> ImageInner { + ImageAccess::inner(&self.image) + } + + #[inline] + fn initial_layout_requirement(&self) -> ImageLayout { + ImageLayout::Undefined + } + + #[inline] + fn final_layout_requirement(&self) -> ImageLayout { + self.image.layout + } + + #[inline] + fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 { + self.image.image.key() + } + + #[inline] + fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> { + if self.image.initialized.load(Ordering::Relaxed) { + return Err(AccessError::AlreadyInUse); + } + + // FIXME: Mipmapped textures require multiple writes to initialize + if !self.used.compare_and_swap(false, true, Ordering::Relaxed) { + Ok(()) + } else { + Err(AccessError::AlreadyInUse) + } + } + + #[inline] + unsafe fn increase_gpu_lock(&self) { + debug_assert!(self.used.load(Ordering::Relaxed)); + } + + #[inline] + unsafe fn unlock(&self) { + self.image.initialized.store(true, Ordering::Relaxed); + } +} diff --git a/vulkano/src/image/mod.rs b/vulkano/src/image/mod.rs index c9c606166..118606221 100644 --- a/vulkano/src/image/mod.rs +++ b/vulkano/src/image/mod.rs @@ -313,6 +313,11 @@ impl Dimensions { Dimensions::CubemapArray { .. } => ViewType::CubemapArray, } } + + #[inline] + pub fn num_texels(&self) -> u32 { + self.width() * self.height() * self.depth() * self.array_layers_with_cube() + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index fa3c4243b..e9221580d 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -68,6 +68,7 @@ extern crate lazy_static; extern crate shared_library; extern crate smallvec; extern crate vk_sys as vk; +pub extern crate half; #[macro_use] mod tests; From b1011816ce206252a925869f48494ac30b8a2bfc Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sun, 23 Jul 2017 23:53:10 -0700 Subject: [PATCH 2/3] Restore deprecated ImmutableImage constructors --- vulkano/src/image/immutable.rs | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/vulkano/src/image/immutable.rs b/vulkano/src/image/immutable.rs index e322dd917..464086313 100644 --- a/vulkano/src/image/immutable.rs +++ b/vulkano/src/image/immutable.rs @@ -66,6 +66,42 @@ pub struct ImmutableImageInitialization { } impl ImmutableImage { + #[deprecated(note = "use ImmutableImage::uninitialized instead")] + #[inline] + pub fn new<'a, I>(device: Arc, dimensions: Dimensions, format: F, queue_families: I) + -> Result>, ImageCreationError> + where F: FormatDesc, + I: IntoIterator> + { + #[allow(deprecated)] + ImmutableImage::with_mipmaps(device, + dimensions, + format, + MipmapsCount::One, + queue_families) + } + + #[deprecated(note = "use ImmutableImage::uninitialized instead")] + #[inline] + pub fn with_mipmaps<'a, I, M>(device: Arc, dimensions: Dimensions, format: F, + mipmaps: M, queue_families: I) + -> Result>, ImageCreationError> + where F: FormatDesc, + I: IntoIterator>, + M: Into + { + let usage = ImageUsage { + transfer_source: true, // for blits + transfer_destination: true, + sampled: true, + ..ImageUsage::none() + }; + + let (image, _) = ImmutableImage::uninitialized(device, dimensions, format, mipmaps, usage, ImageLayout::ShaderReadOnlyOptimal, queue_families)?; + image.initialized.store(true, Ordering::Relaxed); // Allow uninitialized access for backwards compatibility + Ok(image) + } + /// Builds an uninitialized immutable image. /// /// Returns two things: the image, and a special access that should be used for the initial upload to the image. From c085e193d9e2187ea399adf416859bbcfae731c0 Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Mon, 24 Jul 2017 00:21:58 -0700 Subject: [PATCH 3/3] Omit rarely-needed parameters from ImmutableImage convenience ctors --- examples/src/bin/debug.rs | 4 +--- examples/src/bin/image.rs | 2 -- vulkano/src/image/immutable.rs | 10 +++++----- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/src/bin/debug.rs b/examples/src/bin/debug.rs index e372f2dc6..5dc1cad97 100644 --- a/examples/src/bin/debug.rs +++ b/examples/src/bin/debug.rs @@ -98,12 +98,10 @@ fn main() { // Create an image in order to generate some additional logging: let pixel_format = Format::R8G8B8A8Uint; - let usage = ImageUsage { sampled: true, ..ImageUsage::none() }; - let layout = ImageLayout::ShaderReadOnlyOptimal; let dimensions = Dimensions::Dim2d { width: 4096, height: 4096 }; const data: [[u8; 4]; 4096*4096] = [[0; 4]; 4096 * 4096]; let (image, _) = ImmutableImage::from_iter(data.iter().cloned(), dimensions, pixel_format, - usage, layout, Some(queue.family()), queue.clone()).unwrap(); + Some(queue.family()), queue.clone()).unwrap(); // (At this point you should see a bunch of messages printed to the terminal window - have fun debugging!) } diff --git a/examples/src/bin/image.rs b/examples/src/bin/image.rs index 1c0a30218..485f7d6cb 100644 --- a/examples/src/bin/image.rs +++ b/examples/src/bin/image.rs @@ -110,8 +110,6 @@ fn main() { image_data.iter().cloned(), vulkano::image::Dimensions::Dim2d { width: 93, height: 93 }, vulkano::format::R8G8B8A8Srgb, - vulkano::image::ImageUsage { sampled: true, ..vulkano::image::ImageUsage::none() }, - vulkano::image::ImageLayout::ShaderReadOnlyOptimal, Some(queue.family()), queue.clone()).unwrap() }; diff --git a/vulkano/src/image/immutable.rs b/vulkano/src/image/immutable.rs index 464086313..185f56fad 100644 --- a/vulkano/src/image/immutable.rs +++ b/vulkano/src/image/immutable.rs @@ -187,8 +187,7 @@ impl ImmutableImage { /// /// TODO: Support mipmaps #[inline] - pub fn from_iter<'a, P, I, J>(iter: I, dimensions: Dimensions, format: F, usage: ImageUsage, layout: ImageLayout, - queue_families: J, queue: Arc) + pub fn from_iter<'a, P, I, J>(iter: I, dimensions: Dimensions, format: F, queue_families: J, queue: Arc) -> Result<(Arc, CommandBufferExecFuture), ImageCreationError> where P: Send + Sync + Clone + 'static, @@ -200,13 +199,13 @@ impl ImmutableImage { BufferUsage::transfer_source(), iter::once(queue.family()), iter)?; - ImmutableImage::from_buffer(source, dimensions, format, usage, layout, queue_families, queue) + ImmutableImage::from_buffer(source, dimensions, format, queue_families, queue) } /// Construct an ImmutableImage containing a copy of the data in `source`. /// /// TODO: Support mipmaps - pub fn from_buffer<'a, B, P, I>(source: B, dimensions: Dimensions, format: F, usage: ImageUsage, layout: ImageLayout, queue_families: I, queue: Arc) + pub fn from_buffer<'a, B, P, I>(source: B, dimensions: Dimensions, format: F, queue_families: I, queue: Arc) -> Result<(Arc, CommandBufferExecFuture), ImageCreationError> where B: BufferAccess + TypedBufferAccess + 'static + Clone + Send + Sync, @@ -214,7 +213,8 @@ impl ImmutableImage { F: FormatDesc + AcceptsPixels

+ 'static + Send + Sync, I: IntoIterator>, { - let usage = ImageUsage { transfer_destination: true, ..usage }; // Ensure we can actually initialize the image + let usage = ImageUsage { transfer_destination: true, sampled: true, ..ImageUsage::none() }; + let layout = ImageLayout::ShaderReadOnlyOptimal; // TODO: The following panics should be removed in favor of propagating errors from copy_buffer_to_image. format.ensure_accepts().unwrap(); if source.len() % format.rate() as usize != 0 {