mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Merge pull request #680 from Ralith/immutable-image
ImmutableImage refactor
This commit is contained in:
commit
bfc30a5f37
@ -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};
|
||||
@ -99,7 +99,9 @@ fn main() {
|
||||
// Create an image in order to generate some additional logging:
|
||||
let pixel_format = Format::R8G8B8A8Uint;
|
||||
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,
|
||||
Some(queue.family()), queue.clone()).unwrap();
|
||||
|
||||
// (At this point you should see a bunch of messages printed to the terminal window - have fun debugging!)
|
||||
}
|
||||
|
@ -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,17 @@ 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,
|
||||
Some(queue.family()),
|
||||
queue.clone()).unwrap()
|
||||
};
|
||||
|
||||
|
||||
@ -138,6 +132,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 +147,7 @@ fn main() {
|
||||
.add(image.clone()).unwrap().build().unwrap())
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let mut previous_frame_end = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
|
||||
let mut previous_frame_end = Box::new(tex_future) as Box<GpuFuture>;
|
||||
|
||||
loop {
|
||||
previous_frame_end.cleanup_finished();
|
||||
@ -161,12 +156,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()
|
||||
|
@ -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"
|
||||
|
@ -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<T> {
|
||||
/// 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!(<R8G8B8A8Srgb as AcceptsPixels<[u8; 4]>>::rate(&R8G8B8A8Srgb), 1);
|
||||
/// assert_eq!(<R8G8B8A8Srgb as AcceptsPixels<u8>>::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;
|
||||
}
|
||||
|
@ -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,33 +40,40 @@ 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<F, A = Arc<StdMemoryPool>>
|
||||
where A: MemoryPool
|
||||
{
|
||||
pub struct ImmutableImage<F, A = StdMemoryPoolAlloc> {
|
||||
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<F, A = StdMemoryPoolAlloc> {
|
||||
image: Arc<ImmutableImage<F, A>>,
|
||||
used: AtomicBool,
|
||||
}
|
||||
|
||||
impl<F> ImmutableImage<F> {
|
||||
/// Builds a new immutable image.
|
||||
// TODO: one mipmap is probably not a great default
|
||||
#[deprecated(note = "use ImmutableImage::uninitialized instead")]
|
||||
#[inline]
|
||||
pub fn new<'a, I>(device: Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
|
||||
-> Result<Arc<ImmutableImage<F>>, ImageCreationError>
|
||||
where F: FormatDesc,
|
||||
I: IntoIterator<Item = QueueFamily<'a>>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
ImmutableImage::with_mipmaps(device,
|
||||
dimensions,
|
||||
format,
|
||||
@ -62,13 +81,14 @@ impl<F> ImmutableImage<F> {
|
||||
queue_families)
|
||||
}
|
||||
|
||||
/// Builds a new immutable image with the given number of mipmaps.
|
||||
#[deprecated(note = "use ImmutableImage::uninitialized instead")]
|
||||
#[inline]
|
||||
pub fn with_mipmaps<'a, I, M>(device: Arc<Device>, dimensions: Dimensions, format: F,
|
||||
mipmaps: M, queue_families: I)
|
||||
-> Result<Arc<ImmutableImage<F>>, ImageCreationError>
|
||||
where F: FormatDesc,
|
||||
I: IntoIterator<Item = QueueFamily<'a>>,
|
||||
M: Into<MipmapsCount>
|
||||
where F: FormatDesc,
|
||||
I: IntoIterator<Item = QueueFamily<'a>>,
|
||||
M: Into<MipmapsCount>
|
||||
{
|
||||
let usage = ImageUsage {
|
||||
transfer_source: true, // for blits
|
||||
@ -77,6 +97,21 @@ impl<F> ImmutableImage<F> {
|
||||
..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.
|
||||
pub fn uninitialized<'a, I, M>(device: Arc<Device>, dimensions: Dimensions, format: F,
|
||||
mipmaps: M, usage: ImageUsage, layout: ImageLayout, queue_families: I)
|
||||
-> Result<(Arc<ImmutableImage<F>>, ImmutableImageInitialization<F>), ImageCreationError>
|
||||
where F: FormatDesc,
|
||||
I: IntoIterator<Item = QueueFamily<'a>>,
|
||||
M: Into<MipmapsCount>
|
||||
{
|
||||
let queue_families = queue_families
|
||||
.into_iter()
|
||||
.map(|f| f.id())
|
||||
@ -130,19 +165,84 @@ impl<F> ImmutableImage<F> {
|
||||
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, queue_families: J, queue: Arc<Queue>)
|
||||
-> Result<(Arc<Self>, CommandBufferExecFuture<NowFuture, AutoCommandBuffer>),
|
||||
ImageCreationError>
|
||||
where P: Send + Sync + Clone + 'static,
|
||||
F: FormatDesc + AcceptsPixels<P> + 'static + Send + Sync,
|
||||
I: ExactSizeIterator<Item = P>,
|
||||
J: IntoIterator<Item = QueueFamily<'a>>,
|
||||
{
|
||||
let source = CpuAccessibleBuffer::from_iter(queue.device().clone(),
|
||||
BufferUsage::transfer_source(),
|
||||
iter::once(queue.family()),
|
||||
iter)?;
|
||||
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, queue_families: I, queue: Arc<Queue>)
|
||||
-> Result<(Arc<Self>, CommandBufferExecFuture<NowFuture, AutoCommandBuffer>),
|
||||
ImageCreationError>
|
||||
where B: BufferAccess + TypedBufferAccess<Content = [P]> + 'static + Clone + Send + Sync,
|
||||
P: Send + Sync + Clone + 'static,
|
||||
F: FormatDesc + AcceptsPixels<P> + 'static + Send + Sync,
|
||||
I: IntoIterator<Item = QueueFamily<'a>>,
|
||||
{
|
||||
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 {
|
||||
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<F, A> ImmutableImage<F, A>
|
||||
where A: MemoryPool
|
||||
{
|
||||
impl<F, A> ImmutableImage<F, A> {
|
||||
/// Returns the dimensions of the image.
|
||||
#[inline]
|
||||
pub fn dimensions(&self) -> Dimensions {
|
||||
@ -158,7 +258,6 @@ impl<F, A> ImmutableImage<F, A>
|
||||
|
||||
unsafe impl<F, A> ImageAccess for ImmutableImage<F, A>
|
||||
where F: 'static + Send + Sync,
|
||||
A: MemoryPool
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> ImageInner {
|
||||
@ -173,12 +272,12 @@ unsafe impl<F, A> ImageAccess for ImmutableImage<F, A>
|
||||
|
||||
#[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 +287,26 @@ unsafe impl<F, A> ImageAccess for ImmutableImage<F, A>
|
||||
|
||||
#[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<P, F, A> ImageContent<P> for ImmutableImage<F, A>
|
||||
where F: 'static + Send + Sync,
|
||||
A: MemoryPool
|
||||
{
|
||||
#[inline]
|
||||
fn matches_format(&self) -> bool {
|
||||
@ -214,7 +316,6 @@ unsafe impl<P, F, A> ImageContent<P> for ImmutableImage<F, A>
|
||||
|
||||
unsafe impl<F: 'static, A> ImageViewAccess for ImmutableImage<F, A>
|
||||
where F: 'static + Send + Sync,
|
||||
A: MemoryPool
|
||||
{
|
||||
#[inline]
|
||||
fn parent(&self) -> &ImageAccess {
|
||||
@ -233,22 +334,22 @@ unsafe impl<F: 'static, A> ImageViewAccess for ImmutableImage<F, A>
|
||||
|
||||
#[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 +357,51 @@ unsafe impl<F: 'static, A> ImageViewAccess for ImmutableImage<F, A>
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<F, A> ImageAccess for ImmutableImageInitialization<F, A>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user