Rewrite copy commands (#1873)

* Allow `SyncCommandBufferBuilder` commands to specify the access range

* Allow `SyncCommandBufferBuilder` commands to specify the access range

* Better handling of image initialization

* Small fix

* Rewrite copy commands

* Better handling of maintenance1

* Small leftovers

* Remove conflict_key
This commit is contained in:
Rua 2022-04-16 15:02:42 +02:00 committed by GitHub
parent 44e30574d9
commit 201e21d3e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 6513 additions and 3606 deletions

View File

@ -17,7 +17,7 @@
use std::{fs::File, io::BufWriter, path::Path};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, CopyImageToBufferInfo},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -230,7 +230,10 @@ fn main() {
1,
])
.unwrap()
.copy_image_to_buffer(image.clone(), buf.clone())
.copy_image_to_buffer(CopyImageToBufferInfo::image_buffer(
image.clone(),
buf.clone(),
))
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -99,8 +99,8 @@ mod linux {
Format::R16G16B16A16_UNORM,
ImageUsage {
sampled: true,
transfer_source: true,
transfer_destination: true,
transfer_src: true,
transfer_dst: true,
..ImageUsage::none()
},
ImageCreateFlags {

View File

@ -12,16 +12,19 @@ use std::{io::Cursor, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
AutoCommandBufferBuilder, BlitImageInfo, BufferImageCopy, ClearColorImageInfo,
CommandBufferUsage, CopyBufferToImageInfo, CopyImageInfo, ImageBlit, ImageCopy,
PrimaryCommandBuffer, SubpassContents,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
},
format::{ClearValue, Format},
format::Format,
image::{
view::ImageView, ImageAccess, ImageDimensions, ImageUsage, StorageImage, SwapchainImage,
view::ImageView, ImageAccess, ImageDimensions, ImageLayout, ImageUsage, StorageImage,
SwapchainImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo},
@ -207,7 +210,7 @@ fn main() {
let buffer = CpuAccessibleBuffer::from_iter(
device.clone(),
BufferUsage::transfer_source(),
BufferUsage::transfer_src(),
false,
image_data,
)
@ -222,49 +225,60 @@ fn main() {
// here, we perform image copying and blitting on the same image
builder
// clear the image buffer
.clear_color_image(image.clone(), ClearValue::Float([0.0, 0.0, 0.0, 0.0]))
.clear_color_image(ClearColorImageInfo::image(image.clone()))
.unwrap()
// put our image in the top left corner
.copy_buffer_to_image_dimensions(
buffer,
image.clone(),
[0, 0, 0],
[img_size[0], img_size[1], 1],
0,
1,
0,
)
.copy_buffer_to_image(CopyBufferToImageInfo {
regions: [BufferImageCopy {
image_subresource: image.subresource_layers(),
image_extent: [img_size[0], img_size[1], 1],
..Default::default()
}]
.into(),
..CopyBufferToImageInfo::buffer_image(buffer, image.clone())
})
.unwrap()
// copy from the top left corner to the bottom right corner
.copy_image(
image.clone(),
[0, 0, 0],
0,
0,
image.clone(),
[img_size[0] as i32, img_size[1] as i32, 0],
0,
0,
[img_size[0], img_size[1], 1],
1,
)
.copy_image(CopyImageInfo {
// Copying within the same image requires the General layout if the source and
// destination subresources overlap.
src_image_layout: ImageLayout::General,
dst_image_layout: ImageLayout::General,
regions: [ImageCopy {
src_subresource: image.subresource_layers(),
src_offset: [0, 0, 0],
dst_subresource: image.subresource_layers(),
dst_offset: [img_size[0], img_size[1], 0],
extent: [img_size[0], img_size[1], 1],
..Default::default()
}]
.into(),
..CopyImageInfo::images(image.clone(), image.clone())
})
.unwrap()
// blit from the bottom right corner to the top right corner (flipped)
.blit_image(
image.clone(),
[img_size[0] as i32, img_size[1] as i32, 0],
[img_size[0] as i32 * 2, img_size[1] as i32 * 2, 1],
0,
0,
image.clone(),
// flipping the top_left and bottom_right corners results in flipped image
[img_size[0] as i32 * 2 - 1, img_size[1] as i32 - 1, 0],
[img_size[0] as i32, 0, 1],
0,
0,
1,
Filter::Nearest,
)
.blit_image(BlitImageInfo {
// Same for blitting.
src_image_layout: ImageLayout::General,
dst_image_layout: ImageLayout::General,
regions: [ImageBlit {
src_subresource: image.subresource_layers(),
src_offsets: [
[img_size[0], img_size[1], 0],
[img_size[0] * 2, img_size[1] * 2, 1],
],
dst_subresource: image.subresource_layers(),
// swapping the two corners results in flipped image
dst_offsets: [
[img_size[0] * 2 - 1, img_size[1] - 1, 0],
[img_size[0], 0, 1],
],
..Default::default()
}]
.into(),
filter: Filter::Nearest,
..BlitImageInfo::images(image.clone(), image.clone())
})
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -130,7 +130,7 @@ void main() {
// We can use copy_buffer(), fill_buffer() and some other functions that copies data to
// buffer also.
builder
.update_buffer(immutable_data_buffer_init, &3u32)
.update_buffer(&3u32, immutable_data_buffer_init, 0)
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -69,7 +69,8 @@ use std::{fs::File, io::BufWriter, path::Path};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
AutoCommandBufferBuilder, CommandBufferUsage, CopyImageToBufferInfo, PrimaryCommandBuffer,
SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -317,7 +318,10 @@ fn main() {
.unwrap()
.end_render_pass()
.unwrap()
.copy_image_to_buffer(image.clone(), buf.clone())
.copy_image_to_buffer(CopyImageToBufferInfo::image_buffer(
image.clone(),
buf.clone(),
))
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -290,7 +290,7 @@ pub fn create_device_image(queue: Arc<Queue>, size: [u32; 2], format: Format) ->
sampled: true,
storage: true,
color_attachment: true,
transfer_destination: true,
transfer_dst: true,
..ImageUsage::none()
},
flags,

View File

@ -17,15 +17,18 @@ use bytemuck::{Pod, Zeroable};
use std::{fs::File, io::BufWriter, path::Path, sync::Arc};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
command_buffer::{
AutoCommandBufferBuilder, BufferImageCopy, CommandBufferUsage, CopyImageToBufferInfo,
SubpassContents,
},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo,
},
format::Format,
image::{
view::ImageView, ImageAccess, ImageCreateFlags, ImageDimensions, ImageLayout, ImageUsage,
SampleCount, StorageImage,
view::ImageView, ImageAccess, ImageCreateFlags, ImageDimensions, ImageLayout,
ImageSubresourceLayers, ImageUsage, SampleCount, StorageImage,
},
impl_vertex,
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
@ -125,7 +128,7 @@ fn main() {
},
Format::B8G8R8A8_SRGB,
ImageUsage {
transfer_source: true,
transfer_src: true,
color_attachment: true,
..ImageUsage::none()
},
@ -293,25 +296,31 @@ fn main() {
// copy the image layers to different buffers to save them as individual images to disk
builder
.copy_image_to_buffer_dimensions(
image.clone(),
buffer1.clone(),
[0, 0, 0],
image.dimensions().width_height_depth(),
0,
1,
0,
)
.copy_image_to_buffer(CopyImageToBufferInfo {
regions: [BufferImageCopy {
image_subresource: ImageSubresourceLayers {
array_layers: 0..1,
..image.subresource_layers()
},
image_extent: image.dimensions().width_height_depth(),
..Default::default()
}]
.into(),
..CopyImageToBufferInfo::image_buffer(image.clone(), buffer1.clone())
})
.unwrap()
.copy_image_to_buffer_dimensions(
image.clone(),
buffer2.clone(),
[0, 0, 0],
image.dimensions().width_height_depth(),
1,
1,
0,
)
.copy_image_to_buffer(CopyImageToBufferInfo {
regions: [BufferImageCopy {
image_subresource: ImageSubresourceLayers {
array_layers: 1..2,
..image.subresource_layers()
},
image_extent: image.dimensions().width_height_depth(),
..Default::default()
}]
.into(),
..CopyImageToBufferInfo::image_buffer(image.clone(), buffer2.clone())
})
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -12,7 +12,9 @@
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage},
command_buffer::{
AutoCommandBufferBuilder, BufferCopy, CommandBufferUsage, CopyBufferInfoTyped,
},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
@ -104,8 +106,8 @@ fn main() {
device.clone(),
BufferUsage {
storage_buffer: true,
transfer_source: true,
transfer_destination: true,
transfer_src: true,
transfer_dst: true,
..BufferUsage::none()
},
false,
@ -129,13 +131,16 @@ fn main() {
.unwrap();
builder
// copy from the first half to the second half (inside the same buffer) before we run the computation
.copy_buffer_dimensions(
data_buffer.clone(),
0,
data_buffer.clone(),
65536 / 2,
65536 / 2,
)
.copy_buffer(CopyBufferInfoTyped {
regions: [BufferCopy {
src_offset: 0,
dst_offset: 65536 / 2,
size: 65536 / 2,
..Default::default()
}]
.into(),
..CopyBufferInfoTyped::buffers(data_buffer.clone(), data_buffer.clone())
})
.unwrap()
.bind_pipeline_compute(pipeline.clone())
.bind_descriptor_sets(

View File

@ -409,11 +409,6 @@ where
fn size(&self) -> DeviceSize {
self.inner.size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(self.inner.key(), 0)
}
}
impl<T, A> BufferAccessObject for Arc<CpuAccessibleBuffer<T, A>>

View File

@ -81,7 +81,7 @@ use std::{
/// .unwrap()
/// // For the sake of the example we just call `update_buffer` on the buffer, even though
/// // it is pointless to do that.
/// .update_buffer(sub_buffer.clone(), &[0.2, 0.3, 0.4, 0.5])
/// .update_buffer(&[0.2, 0.3, 0.4, 0.5], sub_buffer.clone(), 0)
/// .unwrap()
/// .build().unwrap()
/// .execute(queue.clone())
@ -217,7 +217,7 @@ where
/// - Panics if `T` has zero size.
#[inline]
pub fn upload(device: Arc<Device>) -> CpuBufferPool<T> {
CpuBufferPool::new(device, BufferUsage::transfer_source())
CpuBufferPool::new(device, BufferUsage::transfer_src())
}
/// Builds a `CpuBufferPool` meant for simple downloads.
@ -230,7 +230,7 @@ where
/// - Panics if `T` has zero size.
#[inline]
pub fn download(device: Arc<Device>) -> CpuBufferPool<T> {
CpuBufferPool::new(device, BufferUsage::transfer_destination())
CpuBufferPool::new(device, BufferUsage::transfer_dst())
}
/// Builds a `CpuBufferPool` meant for usage as a uniform buffer.
@ -675,19 +675,6 @@ where
fn size(&self) -> DeviceSize {
self.requested_len * size_of::<T>() as DeviceSize
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(
self.buffer.inner.key(),
// ensure the special cased empty buffers don't collide with a regular buffer starting at 0
if self.requested_len == 0 {
u64::MAX
} else {
self.index
},
)
}
}
impl<T, A> BufferAccessObject for Arc<CpuBufferPoolChunk<T, A>>
@ -807,11 +794,6 @@ where
fn size(&self) -> DeviceSize {
self.chunk.size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
self.chunk.conflict_key()
}
}
impl<T, A> BufferAccessObject for Arc<CpuBufferPoolSubbuffer<T, A>>

View File

@ -319,11 +319,6 @@ where
fn size(&self) -> DeviceSize {
self.inner.size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(self.inner.key(), 0)
}
}
impl<T, A> BufferAccessObject for Arc<DeviceLocalBuffer<T, A>>

View File

@ -25,7 +25,7 @@ use super::{
use crate::{
buffer::{sys::UnsafeBufferCreateInfo, BufferCreationError, TypedBufferAccess},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferUsage,
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferUsage, CopyBufferInfo,
PrimaryAutoCommandBuffer, PrimaryCommandBuffer,
},
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
@ -91,9 +91,9 @@ where
B: TypedBufferAccess<Content = T> + 'static,
{
unsafe {
// We automatically set `transfer_destination` to true in order to avoid annoying errors.
// We automatically set `transfer_dst` to true in order to avoid annoying errors.
let actual_usage = BufferUsage {
transfer_destination: true,
transfer_dst: true,
..usage
};
@ -109,7 +109,8 @@ where
queue.family(),
CommandBufferUsage::MultipleSubmit,
)?;
cbb.copy_buffer(source, init).unwrap(); // TODO: return error?
cbb.copy_buffer(CopyBufferInfo::buffers(source, init))
.unwrap(); // TODO: return error?
let cb = cbb.build().unwrap(); // TODO: return OomError
let future = match cb.execute(queue) {
@ -150,7 +151,7 @@ where
> {
let source = CpuAccessibleBuffer::from_data(
queue.device().clone(),
BufferUsage::transfer_source(),
BufferUsage::transfer_src(),
false,
data,
)?;
@ -218,7 +219,7 @@ where
{
let source = CpuAccessibleBuffer::from_iter(
queue.device().clone(),
BufferUsage::transfer_source(),
BufferUsage::transfer_src(),
false,
data,
)?;
@ -417,11 +418,6 @@ where
fn size(&self) -> DeviceSize {
self.inner.size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(self.inner.key(), 0)
}
}
impl<T, A> BufferAccessObject for Arc<ImmutableBuffer<T, A>>
@ -506,11 +502,6 @@ where
fn size(&self) -> DeviceSize {
self.buffer.size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(self.buffer.inner.key(), 0)
}
}
impl<T, A> BufferAccessObject for Arc<ImmutableBufferInitialization<T, A>>
@ -586,12 +577,7 @@ where
#[cfg(test)]
mod tests {
use crate::buffer::cpu_access::CpuAccessibleBuffer;
use crate::buffer::immutable::ImmutableBuffer;
use crate::buffer::BufferUsage;
use crate::command_buffer::AutoCommandBufferBuilder;
use crate::command_buffer::CommandBufferUsage;
use crate::command_buffer::PrimaryCommandBuffer;
use super::*;
use crate::sync::GpuFuture;
#[test]
@ -610,7 +596,8 @@ mod tests {
CommandBufferUsage::MultipleSubmit,
)
.unwrap();
cbb.copy_buffer(buffer, destination.clone()).unwrap();
cbb.copy_buffer(CopyBufferInfo::buffers(buffer, destination.clone()))
.unwrap();
let _ = cbb
.build()
.unwrap()
@ -648,7 +635,8 @@ mod tests {
CommandBufferUsage::MultipleSubmit,
)
.unwrap();
cbb.copy_buffer(buffer, destination.clone()).unwrap();
cbb.copy_buffer(CopyBufferInfo::buffers(buffer, destination.clone()))
.unwrap();
let _ = cbb
.build()
.unwrap()
@ -680,9 +668,9 @@ mod tests {
CommandBufferUsage::MultipleSubmit,
)
.unwrap();
cbb.copy_buffer(source.clone(), init)
cbb.copy_buffer(CopyBufferInfo::buffers(source.clone(), init))
.unwrap()
.copy_buffer(buffer, source.clone())
.copy_buffer(CopyBufferInfo::buffers(buffer, source.clone()))
.unwrap();
let _ = cbb
.build()
@ -711,7 +699,8 @@ mod tests {
CommandBufferUsage::MultipleSubmit,
)
.unwrap();
cbb.copy_buffer(source.clone(), init).unwrap();
cbb.copy_buffer(CopyBufferInfo::buffers(source.clone(), init))
.unwrap();
let cb1 = cbb.build().unwrap();
let mut cbb = AutoCommandBufferBuilder::primary(
@ -720,7 +709,8 @@ mod tests {
CommandBufferUsage::MultipleSubmit,
)
.unwrap();
cbb.copy_buffer(buffer, source.clone()).unwrap();
cbb.copy_buffer(CopyBufferInfo::buffers(buffer, source.clone()))
.unwrap();
let cb2 = cbb.build().unwrap();
let _ = cb1

View File

@ -225,11 +225,6 @@ where
fn size(&self) -> DeviceSize {
self.size
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
self.resource.conflict_key()
}
}
impl<T, B> BufferAccessObject for Arc<BufferSlice<T, B>>

View File

@ -331,10 +331,10 @@ impl UnsafeBuffer {
self.size
}
/// Returns the buffer the image was created with.
/// Returns the usage the buffer was created with.
#[inline]
pub fn usage(&self) -> BufferUsage {
self.usage
pub fn usage(&self) -> &BufferUsage {
&self.usage
}
/// Returns a key unique to each `UnsafeBuffer`. Can be used for the `conflicts_key` method.

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{sys::UnsafeBuffer, BufferContents, BufferSlice};
use super::{sys::UnsafeBuffer, BufferContents, BufferSlice, BufferUsage};
use crate::{device::DeviceOwned, DeviceSize, SafeDeref, VulkanObject};
use std::{
error, fmt,
@ -28,6 +28,12 @@ pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
/// Returns the size of the buffer in bytes.
fn size(&self) -> DeviceSize;
/// Returns the usage the buffer was created with.
#[inline]
fn usage(&self) -> &BufferUsage {
self.inner().buffer.usage()
}
/// Returns a `BufferSlice` covering the whole buffer.
#[inline]
fn into_buffer_slice(self: &Arc<Self>) -> Arc<BufferSlice<Self::Content, Self>>
@ -62,18 +68,6 @@ pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
BufferSlice::index(&self.into_buffer_slice(), index)
}
/// Returns a key that uniquely identifies the buffer. Two buffers or images that potentially
/// overlap in memory must return the same key.
///
/// The key is shared amongst all buffers and images, which means that you can make several
/// different buffer objects share the same memory, or make some buffer objects share memory
/// with images, as long as they return the same key.
///
/// Since it is possible to accidentally return the same key for memory ranges that don't
/// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
/// verify whether they actually overlap.
fn conflict_key(&self) -> (u64, u64);
/// Gets the device address for this buffer.
///
/// # Safety
@ -148,11 +142,6 @@ where
fn size(&self) -> DeviceSize {
(**self).size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(**self).conflict_key()
}
}
/// Extension trait for `BufferAccess`. Indicates the type of the content of the buffer.
@ -177,6 +166,14 @@ where
type Content = <T::Target as TypedBufferAccess>::Content;
}
impl fmt::Debug for dyn BufferAccess {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("dyn BufferAccess")
.field("inner", &self.inner())
.finish()
}
}
impl PartialEq for dyn BufferAccess {
#[inline]
fn eq(&self, other: &Self) -> bool {

View File

@ -17,8 +17,8 @@ use std::ops::BitOr;
/// there is no restriction in the combination of BufferUsages that can be enabled.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct BufferUsage {
pub transfer_source: bool,
pub transfer_destination: bool,
pub transfer_src: bool,
pub transfer_dst: bool,
pub uniform_texel_buffer: bool,
pub storage_texel_buffer: bool,
pub uniform_buffer: bool,
@ -35,8 +35,8 @@ impl BufferUsage {
#[inline]
pub const fn none() -> BufferUsage {
BufferUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
uniform_texel_buffer: false,
storage_texel_buffer: false,
uniform_buffer: false,
@ -53,8 +53,8 @@ impl BufferUsage {
#[inline]
pub const fn all() -> BufferUsage {
BufferUsage {
transfer_source: true,
transfer_destination: true,
transfer_src: true,
transfer_dst: true,
uniform_texel_buffer: true,
storage_texel_buffer: true,
uniform_buffer: true,
@ -67,20 +67,20 @@ impl BufferUsage {
}
}
/// Builds a `BufferUsage` with `transfer_source` set to true and the rest to false.
/// Builds a `BufferUsage` with `transfer_src` set to true and the rest to false.
#[inline]
pub const fn transfer_source() -> BufferUsage {
pub const fn transfer_src() -> BufferUsage {
BufferUsage {
transfer_source: true,
transfer_src: true,
..BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `transfer_destination` set to true and the rest to false.
/// Builds a `BufferUsage` with `transfer_dst` set to true and the rest to false.
#[inline]
pub const fn transfer_destination() -> BufferUsage {
pub const fn transfer_dst() -> BufferUsage {
BufferUsage {
transfer_destination: true,
transfer_dst: true,
..BufferUsage::none()
}
}
@ -94,13 +94,13 @@ impl BufferUsage {
}
}
/// Builds a `BufferUsage` with `vertex_buffer` and `transfer_destination` set to true and the rest
/// Builds a `BufferUsage` with `vertex_buffer` and `transfer_dst` set to true and the rest
/// to false.
#[inline]
pub const fn vertex_buffer_transfer_destination() -> BufferUsage {
pub const fn vertex_buffer_transfer_dst() -> BufferUsage {
BufferUsage {
vertex_buffer: true,
transfer_destination: true,
transfer_dst: true,
..BufferUsage::none()
}
}
@ -114,12 +114,12 @@ impl BufferUsage {
}
}
/// Builds a `BufferUsage` with `index_buffer` and `transfer_destination` set to true and the rest to false.
/// Builds a `BufferUsage` with `index_buffer` and `transfer_dst` set to true and the rest to false.
#[inline]
pub const fn index_buffer_transfer_destination() -> BufferUsage {
pub const fn index_buffer_transfer_dst() -> BufferUsage {
BufferUsage {
index_buffer: true,
transfer_destination: true,
transfer_dst: true,
..BufferUsage::none()
}
}
@ -142,13 +142,13 @@ impl BufferUsage {
}
}
/// Builds a `BufferUsage` with `uniform_buffer` and `transfer_destination` set to true and the rest
/// Builds a `BufferUsage` with `uniform_buffer` and `transfer_dst` set to true and the rest
/// to false.
#[inline]
pub const fn uniform_buffer_transfer_destination() -> BufferUsage {
pub const fn uniform_buffer_transfer_dst() -> BufferUsage {
BufferUsage {
uniform_buffer: true,
transfer_destination: true,
transfer_dst: true,
..BufferUsage::none()
}
}
@ -162,13 +162,13 @@ impl BufferUsage {
}
}
/// Builds a `BufferUsage` with `indirect_buffer` and `transfer_destination` set to true and the rest
/// Builds a `BufferUsage` with `indirect_buffer` and `transfer_dst` set to true and the rest
/// to false.
#[inline]
pub const fn indirect_buffer_transfer_destination() -> BufferUsage {
pub const fn indirect_buffer_transfer_dst() -> BufferUsage {
BufferUsage {
indirect_buffer: true,
transfer_destination: true,
transfer_dst: true,
..BufferUsage::none()
}
}
@ -186,10 +186,10 @@ impl BufferUsage {
impl From<BufferUsage> for ash::vk::BufferUsageFlags {
fn from(val: BufferUsage) -> Self {
let mut result = ash::vk::BufferUsageFlags::empty();
if val.transfer_source {
if val.transfer_src {
result |= ash::vk::BufferUsageFlags::TRANSFER_SRC;
}
if val.transfer_destination {
if val.transfer_dst {
result |= ash::vk::BufferUsageFlags::TRANSFER_DST;
}
if val.uniform_texel_buffer {
@ -226,8 +226,8 @@ impl BitOr for BufferUsage {
#[inline]
fn bitor(self, rhs: Self) -> Self {
BufferUsage {
transfer_source: self.transfer_source || rhs.transfer_source,
transfer_destination: self.transfer_destination || rhs.transfer_destination,
transfer_src: self.transfer_src || rhs.transfer_src,
transfer_dst: self.transfer_dst || rhs.transfer_dst,
uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
uniform_buffer: self.uniform_buffer || rhs.uniform_buffer,

View File

@ -9,7 +9,6 @@
use super::{
commands::{
image::{CheckBlitImageError, CheckClearColorImageError, CheckClearDepthStencilImageError},
pipeline::{
CheckDescriptorSetsValidityError, CheckDispatchError, CheckDynamicStateValidityError,
CheckIndexBufferError, CheckIndirectBufferError, CheckPipelineError,
@ -19,10 +18,6 @@ use super::{
CheckBeginQueryError, CheckCopyQueryPoolResultsError, CheckEndQueryError,
CheckResetQueryPoolError, CheckWriteTimestampError,
},
transfer::{
CheckCopyBufferError, CheckCopyBufferImageError, CheckCopyImageError,
CheckFillBufferError, CheckUpdateBufferError,
},
},
pool::{
standard::{StandardCommandPoolAlloc, StandardCommandPoolBuilder},
@ -787,54 +782,12 @@ err_gen!(BeginRenderPassError {
SyncCommandBufferBuilderError,
});
err_gen!(CopyImageError {
AutoCommandBufferBuilderContextError,
CheckCopyImageError,
SyncCommandBufferBuilderError,
});
err_gen!(BlitImageError {
AutoCommandBufferBuilderContextError,
CheckBlitImageError,
SyncCommandBufferBuilderError,
});
err_gen!(ClearColorImageError {
AutoCommandBufferBuilderContextError,
CheckClearColorImageError,
SyncCommandBufferBuilderError,
});
err_gen!(ClearDepthStencilImageError {
AutoCommandBufferBuilderContextError,
CheckClearDepthStencilImageError,
SyncCommandBufferBuilderError,
});
err_gen!(CopyBufferError {
AutoCommandBufferBuilderContextError,
CheckCopyBufferError,
SyncCommandBufferBuilderError,
});
err_gen!(CopyBufferImageError {
AutoCommandBufferBuilderContextError,
CheckCopyBufferImageError,
SyncCommandBufferBuilderError,
});
err_gen!(CopyQueryPoolResultsError {
AutoCommandBufferBuilderContextError,
CheckCopyQueryPoolResultsError,
SyncCommandBufferBuilderError,
});
err_gen!(FillBufferError {
AutoCommandBufferBuilderContextError,
CheckFillBufferError,
SyncCommandBufferBuilderError,
});
err_gen!(DispatchError {
AutoCommandBufferBuilderContextError,
CheckPipelineError,
@ -923,12 +876,6 @@ err_gen!(ResetQueryPoolError {
CheckResetQueryPoolError,
});
err_gen!(UpdateBufferError {
AutoCommandBufferBuilderContextError,
CheckUpdateBufferError,
SyncCommandBufferBuilderError,
});
/// Errors that can happen when calling [`clear_attachments`](AutoCommandBufferBuilder::clear_attachments)
#[derive(Debug, Copy, Clone)]
pub enum ClearAttachmentsError {
@ -1097,6 +1044,7 @@ mod tests {
use super::*;
use crate::{
buffer::{BufferUsage, CpuAccessibleBuffer},
command_buffer::{BufferCopy, CopyBufferInfoTyped, CopyError},
device::{physical::PhysicalDevice, DeviceCreateInfo, QueueCreateInfo},
};
@ -1148,8 +1096,17 @@ mod tests {
)
.unwrap();
cbb.copy_buffer_dimensions(source.clone(), 0, destination.clone(), 1, 2)
.unwrap();
cbb.copy_buffer(CopyBufferInfoTyped {
regions: [BufferCopy {
src_offset: 0,
dst_offset: 1,
size: 2,
..Default::default()
}]
.into(),
..CopyBufferInfoTyped::buffers(source.clone(), destination.clone())
})
.unwrap();
let cb = cbb.build().unwrap();
@ -1256,7 +1213,16 @@ mod tests {
.unwrap();
builder
.copy_buffer_dimensions(source.clone(), 0, source.clone(), 2, 2)
.copy_buffer(CopyBufferInfoTyped {
regions: [BufferCopy {
src_offset: 0,
dst_offset: 2,
size: 2,
..Default::default()
}]
.into(),
..CopyBufferInfoTyped::buffers(source.clone(), source.clone())
})
.unwrap();
let cb = builder.build().unwrap();
@ -1293,10 +1259,20 @@ mod tests {
.unwrap();
assert!(matches!(
builder.copy_buffer_dimensions(source.clone(), 0, source.clone(), 1, 2),
Err(CopyBufferError::CheckCopyBufferError(
CheckCopyBufferError::OverlappingRanges
))
builder.copy_buffer(CopyBufferInfoTyped {
regions: [BufferCopy {
src_offset: 0,
dst_offset: 1,
size: 2,
..Default::default()
}]
.into(),
..CopyBufferInfoTyped::buffers(source.clone(), source.clone())
}),
Err(CopyError::OverlappingRegions {
src_region_index: 0,
dst_region_index: 0,
})
));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -17,3 +17,586 @@ pub(super) mod render_pass;
pub(super) mod secondary;
pub(super) mod sync;
pub(super) mod transfer;
use super::synced::SyncCommandBufferBuilderError;
use crate::{
format::Format,
image::{ImageAspects, ImageLayout, SampleCount, SampleCounts},
DeviceSize,
};
use std::{error, fmt};
/// Error that can happen when recording a copy command.
#[derive(Clone, Debug)]
pub enum CopyError {
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
/// Operation forbidden inside of a render pass.
ForbiddenInsideRenderPass,
/// The queue family doesn't allow this operation.
NotSupportedByQueueFamily,
/// The array layer counts of the source and destination subresource ranges of a region do not
/// match.
ArrayLayerCountMismatch {
region_index: usize,
src_layer_count: u32,
dst_layer_count: u32,
},
/// The end of the range of accessed array layers of the subresource range of a region is
/// greater than the number of array layers in the image.
ArrayLayersOutOfRange {
resource: CopyErrorResource,
region_index: usize,
array_layers_range_end: u32,
image_array_layers: u32,
},
/// The aspects of the source and destination subresource ranges of a region do not match.
AspectsMismatch {
region_index: usize,
src_aspects: ImageAspects,
dst_aspects: ImageAspects,
},
/// The aspects of the subresource range of a region contain aspects that are not present
/// in the image, or that are not allowed.
AspectsNotAllowed {
resource: CopyErrorResource,
region_index: usize,
aspects: ImageAspects,
allowed_aspects: ImageAspects,
},
/// The buffer image height of a region is not a multiple of the required buffer alignment.
BufferImageHeightNotAligned {
resource: CopyErrorResource,
region_index: usize,
image_height: u32,
required_alignment: u32,
},
/// The buffer image height of a region is smaller than the image extent height.
BufferImageHeightTooSmall {
resource: CopyErrorResource,
region_index: usize,
image_height: u32,
min: u32,
},
/// The buffer row length of a region is not a multiple of the required buffer alignment.
BufferRowLengthNotAligned {
resource: CopyErrorResource,
region_index: usize,
row_length: u32,
required_alignment: u32,
},
/// The buffer row length of a region specifies a row of texels that is greater than 0x7FFFFFFF
/// bytes in size.
BufferRowLengthTooLarge {
resource: CopyErrorResource,
region_index: usize,
buffer_row_length: u32,
},
/// The buffer row length of a region is smaller than the image extent width.
BufferRowLengthTooSmall {
resource: CopyErrorResource,
region_index: usize,
row_length: u32,
min: u32,
},
/// The provided data has a size larger than the maximum allowed.
DataTooLarge {
size: DeviceSize,
max: DeviceSize,
},
/// Depth/stencil images are not supported by the queue family of this command buffer; a graphics queue family is required.
DepthStencilNotSupportedByQueueFamily,
/// The image extent of a region is not a multiple of the required image alignment.
ExtentNotAlignedForImage {
resource: CopyErrorResource,
region_index: usize,
extent: [u32; 3],
required_alignment: [u32; 3],
},
/// The chosen filter type does not support the dimensionality of the source image.
FilterNotSupportedForImageType,
/// The chosen filter type does not support the format of the source image.
FilterNotSupportedByFormat,
/// The format of an image is not supported for this operation.
FormatNotSupported {
resource: CopyErrorResource,
format: Format,
},
/// The format of the source image does not match the format of the destination image.
FormatsMismatch {
src_format: Format,
dst_format: Format,
},
/// The format of the source image subresource is not compatible with the format of the
/// destination image subresource.
FormatsNotCompatible {
src_format: Format,
dst_format: Format,
},
/// A specified image layout is not valid for this operation.
ImageLayoutInvalid {
resource: CopyErrorResource,
image_layout: ImageLayout,
},
/// The end of the range of accessed mip levels of the subresource range of a region is greater
/// than the number of mip levels in the image.
MipLevelsOutOfRange {
resource: CopyErrorResource,
region_index: usize,
mip_levels_range_end: u32,
image_mip_levels: u32,
},
/// An image does not have a required format feature.
MissingFormatFeature {
resource: CopyErrorResource,
format_feature: &'static str,
},
/// A resource did not have a required usage enabled.
MissingUsage {
resource: CopyErrorResource,
usage: &'static str,
},
/// A subresource range of a region specifies multiple aspects, but only one aspect can be
/// selected for the image.
MultipleAspectsNotAllowed {
resource: CopyErrorResource,
region_index: usize,
aspects: ImageAspects,
},
/// The buffer offset of a region is not a multiple of the required buffer alignment.
OffsetNotAlignedForBuffer {
resource: CopyErrorResource,
region_index: usize,
offset: DeviceSize,
required_alignment: DeviceSize,
},
/// The image offset of a region is not a multiple of the required image alignment.
OffsetNotAlignedForImage {
resource: CopyErrorResource,
region_index: usize,
offset: [u32; 3],
required_alignment: [u32; 3],
},
/// The image offsets of a region are not the values required for that axis ([0, 1]) for the
/// type of the image.
OffsetsInvalidForImageType {
resource: CopyErrorResource,
region_index: usize,
offsets: [u32; 2],
},
/// The source bounds of a region overlap with the destination bounds of a region.
OverlappingRegions {
src_region_index: usize,
dst_region_index: usize,
},
/// The source subresources of a region overlap with the destination subresources of a region,
/// but the source image layout does not equal the destination image layout.
OverlappingSubresourcesLayoutMismatch {
src_region_index: usize,
dst_region_index: usize,
src_image_layout: ImageLayout,
dst_image_layout: ImageLayout,
},
/// The end of the range of accessed byte offsets of a region is greater than the size of the
/// buffer.
RegionOutOfBufferBounds {
resource: CopyErrorResource,
region_index: usize,
offset_range_end: DeviceSize,
buffer_size: DeviceSize,
},
/// The end of the range of accessed texel offsets of a region is greater than the extent of
/// the selected subresource of the image.
RegionOutOfImageBounds {
resource: CopyErrorResource,
region_index: usize,
offset_range_end: [u32; 3],
subresource_extent: [u32; 3],
},
/// An image has a sample count that is not valid for this operation.
SampleCountInvalid {
resource: CopyErrorResource,
sample_count: SampleCount,
allowed_sample_counts: SampleCounts,
},
/// The source image has a different sample count than the destination image.
SampleCountMismatch {
src_sample_count: SampleCount,
dst_sample_count: SampleCount,
},
/// The buffer size of a region is not a multiple of the required buffer alignment.
SizeNotAlignedForBuffer {
resource: CopyErrorResource,
region_index: usize,
size: DeviceSize,
required_alignment: DeviceSize,
},
}
impl error::Error for CopyError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::SyncCommandBufferBuilderError(err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for CopyError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
Self::ExtensionNotEnabled { extension, reason } => write!(
f,
"the extension {} must be enabled: {}",
extension, reason
),
Self::ForbiddenInsideRenderPass => {
write!(f, "operation forbidden inside of a render pass")
}
Self::NotSupportedByQueueFamily => {
write!(f, "the queue family doesn't allow this operation")
}
Self::ArrayLayerCountMismatch {
region_index,
src_layer_count,
dst_layer_count,
} => write!(
f,
"the array layer counts of the source and destination subresource ranges of region {} do not match (source: {}; destination: {})",
region_index, src_layer_count, dst_layer_count,
),
Self::ArrayLayersOutOfRange {
resource,
region_index,
array_layers_range_end,
image_array_layers,
} => write!(
f,
"the end of the range of accessed array layers ({}) of the {} subresource range of region {} is greater than the number of array layers in the {} image ({})",
array_layers_range_end, resource, region_index, resource, image_array_layers,
),
Self::AspectsMismatch {
region_index,
src_aspects,
dst_aspects,
} => write!(
f,
"the aspects of the source and destination subresource ranges of region {} do not match (source: {:?}; destination: {:?})",
region_index, src_aspects, dst_aspects,
),
Self::AspectsNotAllowed {
resource,
region_index,
aspects,
allowed_aspects,
} => write!(
f,
"the aspects ({:?}) of the {} subresource range of region {} contain aspects that are not present in the {} image, or that are not allowed ({:?})",
aspects, resource, region_index, resource, allowed_aspects,
),
Self::BufferImageHeightNotAligned {
resource,
region_index,
image_height,
required_alignment,
} => write!(
f,
"the {} buffer image height ({}) of region {} is not a multiple of the required {} buffer alignment ({})",
resource, image_height, region_index, resource, required_alignment,
),
Self::BufferRowLengthTooLarge {
resource,
region_index,
buffer_row_length,
} => write!(
f,
"the {} buffer row length ({}) of region {} specifies a row of texels that is greater than 0x7FFFFFFF bytes in size",
resource, buffer_row_length, region_index,
),
Self::BufferImageHeightTooSmall {
resource,
region_index,
image_height,
min,
} => write!(
f,
"the {} buffer image height ({}) of region {} is smaller than the {} image extent height ({})",
resource, image_height, region_index, resource, min,
),
Self::BufferRowLengthNotAligned {
resource,
region_index,
row_length,
required_alignment,
} => write!(
f,
"the {} buffer row length ({}) of region {} is not a multiple of the required {} buffer alignment ({})",
resource, row_length, region_index, resource, required_alignment,
),
Self::BufferRowLengthTooSmall {
resource,
region_index,
row_length,
min,
} => write!(
f,
"the {} buffer row length length ({}) of region {} is smaller than the {} image extent width ({})",
resource, row_length, region_index, resource, min,
),
Self::DataTooLarge {
size,
max,
} => write!(
f,
"the provided data has a size ({}) greater than the maximum allowed ({})",
size, max,
),
Self::DepthStencilNotSupportedByQueueFamily => write!(
f,
"depth/stencil images are not supported by the queue family of this command buffer; a graphics queue family is required",
),
Self::ExtentNotAlignedForImage {
resource,
region_index,
extent,
required_alignment,
} => write!(
f,
"the {} image extent ({:?}) of region {} is not a multiple of the required {} image alignment ({:?})",
resource, extent, region_index, resource, required_alignment,
),
Self::FilterNotSupportedForImageType => write!(
f,
"the chosen filter is not supported for the source image type"
),
Self::FilterNotSupportedByFormat => write!(
f,
"the chosen filter is not supported by the format of the source image"
),
Self::FormatNotSupported {
resource,
format,
} => write!(
f,
"the format of the {} image ({:?}) is not supported for this operation",
resource, format,
),
Self::FormatsMismatch {
src_format,
dst_format,
} => write!(
f,
"the format of the source image ({:?}) does not match the format of the destination image ({:?})",
src_format, dst_format,
),
Self::FormatsNotCompatible {
src_format,
dst_format,
} => write!(
f,
"the format of the source image subresource ({:?}) is not compatible with the format of the destination image subresource ({:?})",
src_format, dst_format,
),
Self::ImageLayoutInvalid {
resource,
image_layout,
} => write!(
f,
"the specified {} image layout {:?} is not valid for this operation",
resource, image_layout,
),
Self::MipLevelsOutOfRange {
resource,
region_index,
mip_levels_range_end,
image_mip_levels,
} => write!(
f,
"the end of the range of accessed mip levels ({}) of the {} subresource range of region {} is not less than the number of mip levels in the {} image ({})",
mip_levels_range_end, resource, region_index, resource, image_mip_levels,
),
Self::MissingFormatFeature {
resource,
format_feature,
} => write!(
f,
"the {} image does not have the required format feature {}",
resource, format_feature,
),
Self::MissingUsage { resource, usage } => write!(
f,
"the {} resource did not have the required usage {} enabled",
resource, usage,
),
Self::MultipleAspectsNotAllowed {
resource,
region_index,
aspects,
} => write!(
f,
"the {} subresource range of region {} specifies multiple aspects ({:?}), but only one aspect can be selected for the {} image",
resource, region_index, aspects, resource,
),
Self::OffsetNotAlignedForBuffer {
resource,
region_index,
offset,
required_alignment,
} => write!(
f,
"the {} buffer offset ({}) of region {} is not a multiple of the required {} buffer alignment ({})",
resource, offset, region_index, resource, required_alignment,
),
Self::OffsetNotAlignedForImage {
resource,
region_index,
offset,
required_alignment,
} => write!(
f,
"the {} image offset ({:?}) of region {} is not a multiple of the required {} image alignment ({:?})",
resource, offset, region_index, resource, required_alignment,
),
Self::OffsetsInvalidForImageType {
resource,
region_index,
offsets,
} => write!(
f,
"the {} image offsets ({:?}) of region {} are not the values required for that axis ([0, 1]) for the type of the {} image",
resource, offsets, region_index, resource,
),
Self::OverlappingRegions {
src_region_index,
dst_region_index,
} => write!(
f,
"the source bounds of region {} overlap with the destination bounds of region {}",
src_region_index, dst_region_index,
),
Self::OverlappingSubresourcesLayoutMismatch {
src_region_index,
dst_region_index,
src_image_layout,
dst_image_layout,
} => write!(
f,
"the source subresources of region {} overlap with the destination subresources of region {}, but the source image layout ({:?}) does not equal the destination image layout ({:?})",
src_region_index, dst_region_index, src_image_layout, dst_image_layout,
),
Self::RegionOutOfBufferBounds {
resource,
region_index,
offset_range_end,
buffer_size,
} => write!(
f,
"the end of the range of accessed {} byte offsets ({}) of region {} is greater than the size of the {} buffer ({})",
resource, offset_range_end, region_index, resource, buffer_size,
),
Self::RegionOutOfImageBounds {
resource,
region_index,
offset_range_end,
subresource_extent,
} => write!(
f,
"the end of the range of accessed {} texel offsets ({:?}) of region {} is greater than the extent of the selected subresource of the {} image ({:?})",
resource, offset_range_end, region_index, resource, subresource_extent,
),
Self::SampleCountInvalid {
resource,
sample_count,
allowed_sample_counts,
} => write!(
f,
"the {} image has a sample count ({:?}) that is not valid for this operation ({:?})",
resource, sample_count, allowed_sample_counts,
),
Self::SampleCountMismatch {
src_sample_count,
dst_sample_count,
} => write!(
f,
"the source image has a different sample count ({:?}) than the destination image ({:?})",
src_sample_count, dst_sample_count,
),
Self::SizeNotAlignedForBuffer {
resource,
region_index,
size,
required_alignment,
} => write!(
f,
"the {} buffer size ({}) of region {} is not a multiple of the required {} buffer alignment ({})",
resource, size, region_index, resource, required_alignment,
),
}
}
}
impl From<SyncCommandBufferBuilderError> for CopyError {
#[inline]
fn from(err: SyncCommandBufferBuilderError) -> Self {
Self::SyncCommandBufferBuilderError(err)
}
}
/// Indicates which resource a `CopyError` applies to.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CopyErrorResource {
Source,
Destination,
}
impl fmt::Display for CopyErrorResource {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
Self::Source => write!(f, "source"),
Self::Destination => write!(f, "destination"),
}
}
}

View File

@ -453,7 +453,7 @@ where
query_pool.device().internal_object(),
);
if !buffer_inner.buffer.usage().transfer_destination {
if !buffer_inner.buffer.usage().transfer_dst {
return Err(CheckCopyQueryPoolResultsError::DestinationMissingTransferUsage);
}
@ -816,7 +816,7 @@ impl UnsafeCommandBufferBuilder {
let destination = destination.inner();
let range = queries.range();
debug_assert!(destination.offset < destination.buffer.size());
debug_assert!(destination.buffer.usage().transfer_destination);
debug_assert!(destination.buffer.usage().transfer_dst);
debug_assert!(destination.offset % size_of::<T>() as DeviceSize == 0);
debug_assert!(stride % size_of::<T>() as DeviceSize == 0);

File diff suppressed because it is too large Load Diff

View File

@ -78,7 +78,10 @@
pub use self::commands::{
debug::DebugUtilsError,
image::{CheckBlitImageError, CheckClearColorImageError, CheckClearDepthStencilImageError},
image::{
BlitImageInfo, ClearColorImageInfo, ClearDepthStencilImageInfo, ImageBlit, ImageResolve,
ResolveImageInfo,
},
pipeline::{
CheckDescriptorSetsValidityError, CheckDispatchError, CheckDynamicStateValidityError,
CheckIndexBufferError, CheckIndirectBufferError, CheckPipelineError,
@ -89,19 +92,19 @@ pub use self::commands::{
CheckResetQueryPoolError, CheckWriteTimestampError,
},
transfer::{
CheckCopyBufferError, CheckCopyBufferImageError, CheckCopyImageError, CheckFillBufferError,
CheckUpdateBufferError,
BufferCopy, BufferImageCopy, CopyBufferInfo, CopyBufferInfoTyped, CopyBufferToImageInfo,
CopyImageInfo, CopyImageToBufferInfo, FillBufferInfo, ImageCopy,
},
CopyError, CopyErrorResource,
};
pub use self::{
auto::{
AutoCommandBufferBuilder, AutoCommandBufferBuilderContextError, BeginError,
BeginQueryError, BeginRenderPassError, BlitImageError, BuildError, ClearColorImageError,
CopyBufferError, CopyBufferImageError, CopyImageError, CopyQueryPoolResultsError,
BeginQueryError, BeginRenderPassError, BuildError, CopyQueryPoolResultsError,
DispatchError, DispatchIndirectError, DrawError, DrawIndexedError,
DrawIndexedIndirectError, DrawIndirectError, EndQueryError, ExecuteCommandsError,
FillBufferError, PrimaryAutoCommandBuffer, ResetQueryPoolError, SecondaryAutoCommandBuffer,
UpdateBufferError, WriteTimestampError,
PrimaryAutoCommandBuffer, ResetQueryPoolError, SecondaryAutoCommandBuffer,
WriteTimestampError,
},
traits::{
CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBuffer,

View File

@ -508,31 +508,25 @@ impl std::fmt::Debug for dyn Command {
#[cfg(test)]
mod tests {
use super::SyncCommandBufferBuilder;
use crate::buffer::BufferUsage;
use crate::buffer::CpuAccessibleBuffer;
use crate::buffer::ImmutableBuffer;
use crate::command_buffer::pool::CommandPool;
use crate::command_buffer::pool::CommandPoolBuilderAlloc;
use crate::command_buffer::sys::CommandBufferBeginInfo;
use crate::command_buffer::AutoCommandBufferBuilder;
use crate::command_buffer::CommandBufferLevel;
use crate::command_buffer::CommandBufferUsage;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorSetLayoutBinding;
use crate::descriptor_set::layout::DescriptorSetLayoutCreateInfo;
use crate::descriptor_set::layout::DescriptorType;
use crate::descriptor_set::PersistentDescriptorSet;
use crate::descriptor_set::WriteDescriptorSet;
use crate::device::Device;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::layout::PipelineLayoutCreateInfo;
use crate::pipeline::PipelineBindPoint;
use crate::sampler::Sampler;
use crate::sampler::SamplerCreateInfo;
use crate::shader::ShaderStages;
use crate::sync::GpuFuture;
use std::sync::Arc;
use super::*;
use crate::{
buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer},
command_buffer::{
pool::{CommandPool, CommandPoolBuilderAlloc},
sys::CommandBufferBeginInfo,
AutoCommandBufferBuilder, CommandBufferLevel, CommandBufferUsage, FillBufferInfo,
},
descriptor_set::{
layout::{
DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo,
DescriptorType,
},
PersistentDescriptorSet, WriteDescriptorSet,
},
pipeline::{layout::PipelineLayoutCreateInfo, PipelineBindPoint, PipelineLayout},
sampler::{Sampler, SamplerCreateInfo},
shader::ShaderStages,
};
#[test]
fn basic_creation() {
@ -563,12 +557,9 @@ mod tests {
let (device, queue) = gfx_dev_and_queue!();
// Create a tiny test buffer
let (buf, future) = ImmutableBuffer::from_data(
0u32,
BufferUsage::transfer_destination(),
queue.clone(),
)
.unwrap();
let (buf, future) =
ImmutableBuffer::from_data(0u32, BufferUsage::transfer_dst(), queue.clone())
.unwrap();
future
.then_signal_fence_and_flush()
.unwrap()
@ -584,7 +575,12 @@ mod tests {
CommandBufferUsage::SimultaneousUse,
)
.unwrap();
builder.fill_buffer(buf.clone(), 42u32).unwrap();
builder
.fill_buffer(FillBufferInfo {
data: 42u32,
..FillBufferInfo::dst_buffer(buf.clone())
})
.unwrap();
Arc::new(builder.build().unwrap())
})
.collect::<Vec<_>>();

View File

@ -8,14 +8,8 @@
// according to those terms.
pub use super::commands::{
bind_push::UnsafeCommandBufferBuilderBindVertexBuffer,
image::{
UnsafeCommandBufferBuilderColorImageClear,
UnsafeCommandBufferBuilderDepthStencilImageClear, UnsafeCommandBufferBuilderImageBlit,
},
render_pass::RenderPassBeginInfo,
bind_push::UnsafeCommandBufferBuilderBindVertexBuffer, render_pass::RenderPassBeginInfo,
secondary::UnsafeCommandBufferBuilderExecuteCommands,
transfer::{UnsafeCommandBufferBuilderBufferImageCopy, UnsafeCommandBufferBuilderImageCopy},
};
use super::{
pool::UnsafeCommandPoolAlloc, CommandBufferInheritanceInfo, CommandBufferLevel,

View File

@ -95,7 +95,7 @@
use crate::{
device::physical::PhysicalDevice, image::ImageAspects, shader::spirv::ImageFormat, DeviceSize,
};
use std::{ops::BitOr, vec::IntoIter as VecIntoIter};
use std::ops::BitOr;
// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/formats.rs"));
@ -283,6 +283,25 @@ pub enum ChromaSampling {
Mode420,
}
impl ChromaSampling {
pub fn subsampled_extent(&self, mut extent: [u32; 3]) -> [u32; 3] {
match self {
ChromaSampling::Mode444 => (),
ChromaSampling::Mode422 => {
debug_assert!(extent[0] % 2 == 0);
extent[0] /= 2;
}
ChromaSampling::Mode420 => {
debug_assert!(extent[0] % 2 == 0 && extent[1] % 2 == 0);
extent[0] /= 2;
extent[1] /= 2;
}
}
extent
}
}
/// The numeric type that represents data of a format in memory.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum NumericType {
@ -421,152 +440,259 @@ pub enum ClearValue {
DepthStencil((f32, u32)),
}
// TODO: remove all these From implementations once they are no longer needed
impl From<[f32; 1]> for ClearValue {
#[inline]
fn from(val: [f32; 1]) -> ClearValue {
ClearValue::Float([val[0], 0.0, 0.0, 1.0])
fn from(val: [f32; 1]) -> Self {
Self::Float([val[0], 0.0, 0.0, 1.0])
}
}
impl From<[f32; 2]> for ClearValue {
#[inline]
fn from(val: [f32; 2]) -> ClearValue {
ClearValue::Float([val[0], val[1], 0.0, 1.0])
fn from(val: [f32; 2]) -> Self {
Self::Float([val[0], val[1], 0.0, 1.0])
}
}
impl From<[f32; 3]> for ClearValue {
#[inline]
fn from(val: [f32; 3]) -> ClearValue {
ClearValue::Float([val[0], val[1], val[2], 1.0])
fn from(val: [f32; 3]) -> Self {
Self::Float([val[0], val[1], val[2], 1.0])
}
}
impl From<[f32; 4]> for ClearValue {
#[inline]
fn from(val: [f32; 4]) -> ClearValue {
ClearValue::Float(val)
fn from(val: [f32; 4]) -> Self {
Self::Float(val)
}
}
impl From<[u32; 1]> for ClearValue {
#[inline]
fn from(val: [u32; 1]) -> ClearValue {
ClearValue::Uint([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
fn from(val: [u32; 1]) -> Self {
Self::Uint([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[u32; 2]> for ClearValue {
#[inline]
fn from(val: [u32; 2]) -> ClearValue {
ClearValue::Uint([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
fn from(val: [u32; 2]) -> Self {
Self::Uint([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[u32; 3]> for ClearValue {
#[inline]
fn from(val: [u32; 3]) -> ClearValue {
ClearValue::Uint([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
fn from(val: [u32; 3]) -> Self {
Self::Uint([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[u32; 4]> for ClearValue {
#[inline]
fn from(val: [u32; 4]) -> ClearValue {
ClearValue::Uint(val)
fn from(val: [u32; 4]) -> Self {
Self::Uint(val)
}
}
impl From<[i32; 1]> for ClearValue {
#[inline]
fn from(val: [i32; 1]) -> ClearValue {
ClearValue::Int([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
fn from(val: [i32; 1]) -> Self {
Self::Int([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[i32; 2]> for ClearValue {
#[inline]
fn from(val: [i32; 2]) -> ClearValue {
ClearValue::Int([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
fn from(val: [i32; 2]) -> Self {
Self::Int([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[i32; 3]> for ClearValue {
#[inline]
fn from(val: [i32; 3]) -> ClearValue {
ClearValue::Int([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
fn from(val: [i32; 3]) -> Self {
Self::Int([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[i32; 4]> for ClearValue {
#[inline]
fn from(val: [i32; 4]) -> ClearValue {
ClearValue::Int(val)
fn from(val: [i32; 4]) -> Self {
Self::Int(val)
}
}
impl From<f32> for ClearValue {
#[inline]
fn from(val: f32) -> ClearValue {
ClearValue::Depth(val)
fn from(val: f32) -> Self {
Self::Depth(val)
}
}
impl From<u32> for ClearValue {
#[inline]
fn from(val: u32) -> ClearValue {
ClearValue::Stencil(val)
fn from(val: u32) -> Self {
Self::Stencil(val)
}
}
impl From<(f32, u32)> for ClearValue {
#[inline]
fn from(val: (f32, u32)) -> ClearValue {
ClearValue::DepthStencil(val)
fn from(val: (f32, u32)) -> Self {
Self::DepthStencil(val)
}
}
// TODO: remove once no longer needed
pub unsafe trait ClearValuesTuple {
type Iter: Iterator<Item = ClearValue>;
fn iter(self) -> Self::Iter;
/// A value that will be used to clear a color image.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ClearColorValue {
/// Value for formats with a numeric type that is not `SINT` or `UINT`.
Float([f32; 4]),
/// Value for formats with a numeric type of `SINT`.
Int([i32; 4]),
/// Value for formats with a numeric type of `UINT`.
Uint([u32; 4]),
}
macro_rules! impl_clear_values_tuple {
($first:ident $($others:ident)+) => (
#[allow(non_snake_case)]
unsafe impl<$first $(, $others)*> ClearValuesTuple for ($first, $($others,)+)
where $first: Into<ClearValue> $(, $others: Into<ClearValue>)*
{
type Iter = VecIntoIter<ClearValue>;
#[inline]
fn iter(self) -> VecIntoIter<ClearValue> {
let ($first, $($others,)+) = self;
vec![
$first.into() $(, $others.into())+
].into_iter()
}
impl From<ClearColorValue> for ash::vk::ClearColorValue {
#[inline]
fn from(val: ClearColorValue) -> Self {
match val {
ClearColorValue::Float(float32) => Self { float32 },
ClearColorValue::Int(int32) => Self { int32 },
ClearColorValue::Uint(uint32) => Self { uint32 },
}
impl_clear_values_tuple!($($others)*);
);
($first:ident) => (
unsafe impl<$first> ClearValuesTuple for ($first,)
where $first: Into<ClearValue>
{
type Iter = VecIntoIter<ClearValue>;
#[inline]
fn iter(self) -> VecIntoIter<ClearValue> {
vec![self.0.into()].into_iter()
}
}
);
}
}
impl_clear_values_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
impl From<[f32; 1]> for ClearColorValue {
#[inline]
fn from(val: [f32; 1]) -> Self {
Self::Float([val[0], 0.0, 0.0, 1.0])
}
}
impl From<[f32; 2]> for ClearColorValue {
#[inline]
fn from(val: [f32; 2]) -> Self {
Self::Float([val[0], val[1], 0.0, 1.0])
}
}
impl From<[f32; 3]> for ClearColorValue {
#[inline]
fn from(val: [f32; 3]) -> Self {
Self::Float([val[0], val[1], val[2], 1.0])
}
}
impl From<[f32; 4]> for ClearColorValue {
#[inline]
fn from(val: [f32; 4]) -> Self {
Self::Float(val)
}
}
impl From<[i32; 1]> for ClearColorValue {
#[inline]
fn from(val: [i32; 1]) -> Self {
Self::Int([val[0], 0, 0, 1])
}
}
impl From<[i32; 2]> for ClearColorValue {
#[inline]
fn from(val: [i32; 2]) -> Self {
Self::Int([val[0], val[1], 0, 1])
}
}
impl From<[i32; 3]> for ClearColorValue {
#[inline]
fn from(val: [i32; 3]) -> Self {
Self::Int([val[0], val[1], val[2], 1])
}
}
impl From<[i32; 4]> for ClearColorValue {
#[inline]
fn from(val: [i32; 4]) -> Self {
Self::Int(val)
}
}
impl From<[u32; 1]> for ClearColorValue {
#[inline]
fn from(val: [u32; 1]) -> Self {
Self::Uint([val[0], 0, 0, 1])
}
}
impl From<[u32; 2]> for ClearColorValue {
#[inline]
fn from(val: [u32; 2]) -> Self {
Self::Uint([val[0], val[1], 0, 1])
}
}
impl From<[u32; 3]> for ClearColorValue {
#[inline]
fn from(val: [u32; 3]) -> Self {
Self::Uint([val[0], val[1], val[2], 1])
}
}
impl From<[u32; 4]> for ClearColorValue {
#[inline]
fn from(val: [u32; 4]) -> Self {
Self::Uint(val)
}
}
/// A value that will be used to clear a depth/stencil image.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct ClearDepthStencilValue {
/// Value for the depth component.
pub depth: f32,
/// Value for the stencil component.
pub stencil: u32,
}
impl From<ClearDepthStencilValue> for ash::vk::ClearDepthStencilValue {
#[inline]
fn from(val: ClearDepthStencilValue) -> Self {
Self {
depth: val.depth,
stencil: val.stencil,
}
}
}
impl From<f32> for ClearDepthStencilValue {
#[inline]
fn from(depth: f32) -> Self {
Self { depth, stencil: 0 }
}
}
impl From<u32> for ClearDepthStencilValue {
#[inline]
fn from(stencil: u32) -> Self {
Self {
depth: 0.0,
stencil,
}
}
}
impl From<(f32, u32)> for ClearDepthStencilValue {
#[inline]
fn from((depth, stencil): (f32, u32)) -> Self {
Self { depth, stencil }
}
}
/// The properties of a format that are supported by a physical device.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]

View File

@ -14,7 +14,7 @@ use super::{
SampleCount,
};
use crate::{
device::Device,
device::{Device, DeviceOwned},
format::{ClearValue, Format},
image::{sys::UnsafeImageCreateInfo, ImageDimensions},
memory::{
@ -561,7 +561,7 @@ where
ImageInner {
image: &self.image,
first_layer: 0,
num_layers: self.image.dimensions().array_layers() as usize,
num_layers: self.image.dimensions().array_layers(),
first_mipmap_level: 0,
num_mipmap_levels: 1,
}
@ -587,11 +587,6 @@ where
})
}
#[inline]
fn conflict_key(&self) -> u64 {
self.image.key()
}
#[inline]
unsafe fn layout_initialized(&self) {
self.initialized.store(true, Ordering::SeqCst);
@ -613,6 +608,12 @@ where
}
}
unsafe impl<A> DeviceOwned for AttachmentImage<A> {
fn device(&self) -> &Arc<Device> {
self.image.device()
}
}
unsafe impl<A> ImageClearValue<ClearValue> for AttachmentImage<A>
where
A: MemoryPoolAlloc,

View File

@ -9,15 +9,16 @@
use super::{
sys::UnsafeImage, traits::ImageContent, ImageAccess, ImageCreateFlags, ImageCreationError,
ImageDescriptorLayouts, ImageDimensions, ImageInner, ImageLayout, ImageUsage, MipmapsCount,
ImageDescriptorLayouts, ImageDimensions, ImageInner, ImageLayout, ImageSubresourceLayers,
ImageUsage, MipmapsCount,
};
use crate::{
buffer::{BufferAccess, BufferContents, BufferUsage, CpuAccessibleBuffer},
command_buffer::{
AutoCommandBufferBuilder, CommandBufferExecFuture, CommandBufferUsage,
PrimaryAutoCommandBuffer, PrimaryCommandBuffer,
AutoCommandBufferBuilder, BlitImageInfo, CommandBufferExecFuture, CommandBufferUsage,
CopyBufferToImageInfo, ImageBlit, PrimaryAutoCommandBuffer, PrimaryCommandBuffer,
},
device::{physical::QueueFamily, Device, Queue},
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
format::Format,
image::sys::UnsafeImageCreateInfo,
memory::{
@ -49,53 +50,6 @@ pub struct ImmutableImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
layout: ImageLayout,
}
/// Image whose purpose is to access only a part of one image, for any kind of access
/// We define a part of one image here by a level of mipmap, or a layer of an array
/// The image attribute must be an implementation of ImageAccess
/// The mip_levels_access must be a range showing which mipmaps will be accessed
/// The array_layers_access must be a range showing which layers will be accessed
/// The layout must be the layout of the image at the beginning and at the end of the command buffer
pub struct SubImage {
image: Arc<dyn ImageAccess>,
mip_levels_access: Range<u32>,
array_layers_access: Range<u32>,
layout: ImageLayout,
}
impl SubImage {
pub fn new(
image: Arc<dyn ImageAccess>,
mip_level: u32,
mip_level_count: u32,
layer_level: u32,
layer_level_count: u32,
layout: ImageLayout,
) -> Arc<SubImage> {
debug_assert!(mip_level + mip_level_count <= image.mip_levels());
debug_assert!(layer_level + layer_level_count <= image.dimensions().array_layers());
let last_level = mip_level + mip_level_count;
let mip_levels_access = mip_level..last_level;
let last_level = layer_level + layer_level_count;
let array_layers_access = layer_level..last_level;
Arc::new(SubImage {
image,
mip_levels_access,
array_layers_access,
layout,
})
}
}
// Must not implement Clone, as that would lead to multiple `used` values.
pub struct ImmutableImageInitialization<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
image: Arc<ImmutableImage<A>>,
mip_levels_access: Range<u32>,
array_layers_access: Range<u32>,
}
fn has_mipmaps(mipmaps: MipmapsCount) -> bool {
match mipmaps {
MipmapsCount::One => false,
@ -111,36 +65,34 @@ fn generate_mipmaps<L>(
layout: ImageLayout,
) {
for level in 1..image.mip_levels() {
for layer in 0..image.dimensions().array_layers() {
let [xs, ys, ds] = dimensions
.mip_level_dimensions(level - 1)
.unwrap()
.width_height_depth();
let [xd, yd, dd] = dimensions
.mip_level_dimensions(level)
.unwrap()
.width_height_depth();
let src_size = dimensions
.mip_level_dimensions(level - 1)
.unwrap()
.width_height_depth();
let dst_size = dimensions
.mip_level_dimensions(level)
.unwrap()
.width_height_depth();
let src = SubImage::new(image.clone(), level - 1, 1, layer, 1, layout);
let dst = SubImage::new(image.clone(), level, 1, layer, 1, layout);
cbb.blit_image(
src, //source
[0, 0, 0], //source_top_left
[xs as i32, ys as i32, ds as i32], //source_bottom_right
layer, //source_base_array_layer
level - 1, //source_mip_level
dst, //destination
[0, 0, 0], //destination_top_left
[xd as i32, yd as i32, dd as i32], //destination_bottom_right
layer, //destination_base_array_layer
level, //destination_mip_level
1, //layer_count
Filter::Linear, //filter
)
.expect("failed to blit a mip map to image!");
}
cbb.blit_image(BlitImageInfo {
regions: [ImageBlit {
src_subresource: ImageSubresourceLayers {
mip_level: level - 1,
..image.subresource_layers()
},
src_offsets: [[0; 3], src_size],
dst_subresource: ImageSubresourceLayers {
mip_level: level,
..image.subresource_layers()
},
dst_offsets: [[0; 3], dst_size],
..Default::default()
}]
.into(),
filter: Filter::Linear,
..BlitImageInfo::images(image.clone(), image.clone())
})
.expect("failed to blit a mip map to image!");
}
}
@ -180,8 +132,8 @@ impl ImmutableImage {
M: Into<MipmapsCount>,
{
let usage = ImageUsage {
transfer_source: true, // for blits
transfer_destination: true,
transfer_src: true, // for blits
transfer_dst: true,
sampled: true,
..ImageUsage::none()
};
@ -306,7 +258,7 @@ impl ImmutableImage {
{
let source = CpuAccessibleBuffer::from_iter(
queue.device().clone(),
BufferUsage::transfer_source(),
BufferUsage::transfer_src(),
false,
iter,
)?;
@ -329,8 +281,8 @@ impl ImmutableImage {
> {
let need_to_generate_mipmaps = has_mipmaps(mip_levels);
let usage = ImageUsage {
transfer_destination: true,
transfer_source: need_to_generate_mipmaps,
transfer_dst: true,
transfer_src: need_to_generate_mipmaps,
sampled: true,
..ImageUsage::none()
};
@ -348,23 +300,13 @@ impl ImmutableImage {
source.device().active_queue_families(),
)?;
let init = SubImage::new(initializer, 0, 1, 0, 1, ImageLayout::ShaderReadOnlyOptimal);
let mut cbb = AutoCommandBufferBuilder::primary(
source.device().clone(),
queue.family(),
CommandBufferUsage::MultipleSubmit,
)?;
cbb.copy_buffer_to_image_dimensions(
source,
init,
[0, 0, 0],
dimensions.width_height_depth(),
0,
dimensions.array_layers(),
0,
)
.unwrap();
cbb.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(source, initializer))
.unwrap();
if need_to_generate_mipmaps {
generate_mipmaps(
@ -386,6 +328,12 @@ impl ImmutableImage {
}
}
unsafe impl<A> DeviceOwned for ImmutableImage<A> {
fn device(&self) -> &Arc<Device> {
self.image.device()
}
}
unsafe impl<A> ImageAccess for ImmutableImage<A>
where
A: MemoryPoolAlloc,
@ -395,9 +343,9 @@ where
ImageInner {
image: &self.image,
first_layer: 0,
num_layers: self.image.dimensions().array_layers() as usize,
num_layers: self.image.dimensions().array_layers(),
first_mipmap_level: 0,
num_mipmap_levels: self.image.mip_levels() as usize,
num_mipmap_levels: self.image.mip_levels(),
}
}
@ -426,11 +374,6 @@ where
})
}
#[inline]
fn conflict_key(&self) -> u64 {
self.image.key()
}
#[inline]
fn current_mip_levels_access(&self) -> Range<u32> {
0..self.mip_levels()
@ -452,41 +395,6 @@ where
}
}
unsafe impl ImageAccess for SubImage {
#[inline]
fn inner(&self) -> ImageInner {
self.image.inner()
}
#[inline]
fn initial_layout_requirement(&self) -> ImageLayout {
self.image.initial_layout_requirement()
}
#[inline]
fn final_layout_requirement(&self) -> ImageLayout {
self.image.final_layout_requirement()
}
#[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
None
}
fn current_mip_levels_access(&self) -> Range<u32> {
self.mip_levels_access.clone()
}
fn current_array_layers_access(&self) -> Range<u32> {
self.array_layers_access.clone()
}
#[inline]
fn conflict_key(&self) -> u64 {
self.image.conflict_key()
}
}
impl<A> PartialEq for ImmutableImage<A>
where
A: MemoryPoolAlloc,
@ -509,6 +417,19 @@ where
}
}
// Must not implement Clone, as that would lead to multiple `used` values.
pub struct ImmutableImageInitialization<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
image: Arc<ImmutableImage<A>>,
mip_levels_access: Range<u32>,
array_layers_access: Range<u32>,
}
unsafe impl<A> DeviceOwned for ImmutableImageInitialization<A> {
fn device(&self) -> &Arc<Device> {
self.image.device()
}
}
unsafe impl<A> ImageAccess for ImmutableImageInitialization<A>
where
A: MemoryPoolAlloc,
@ -533,11 +454,6 @@ where
None
}
#[inline]
fn conflict_key(&self) -> u64 {
self.image.image.key()
}
#[inline]
fn current_mip_levels_access(&self) -> Range<u32> {
self.mip_levels_access.clone()

View File

@ -555,6 +555,36 @@ impl ImageDimensions {
}
}
/// One or more subresources of an image, spanning a single mip level, that should be accessed by a
/// command.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImageSubresourceLayers {
/// Selects the aspects that will be included.
///
/// The value must not be empty, and must not include any of the `memory_plane` aspects.
/// The `color` aspect cannot be selected together any of with the `plane` aspects.
pub aspects: ImageAspects,
/// Selects mip level that will be included.
pub mip_level: u32,
/// Selects the range of array layers that will be included.
///
/// The range must not be empty.
pub array_layers: Range<u32>,
}
impl From<ImageSubresourceLayers> for ash::vk::ImageSubresourceLayers {
fn from(val: ImageSubresourceLayers) -> Self {
Self {
aspect_mask: val.aspects.into(),
mip_level: val.mip_level,
base_array_layer: val.array_layers.start,
layer_count: val.array_layers.end - val.array_layers.start,
}
}
}
/// One or more subresources of an image that should be accessed by a command.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImageSubresourceRange {
@ -576,6 +606,7 @@ pub struct ImageSubresourceRange {
}
impl From<ImageSubresourceRange> for ash::vk::ImageSubresourceRange {
#[inline]
fn from(val: ImageSubresourceRange) -> Self {
Self {
aspect_mask: val.aspects.into(),
@ -587,6 +618,17 @@ impl From<ImageSubresourceRange> for ash::vk::ImageSubresourceRange {
}
}
impl From<ImageSubresourceLayers> for ImageSubresourceRange {
#[inline]
fn from(val: ImageSubresourceLayers) -> Self {
Self {
aspects: val.aspects,
mip_levels: val.mip_level..val.mip_level + 1,
array_layers: val.array_layers,
}
}
}
/// The image configuration to query in
/// [`PhysicalDevice::image_format_properties`](crate::device::physical::PhysicalDevice::image_format_properties).
#[derive(Clone, Debug)]

View File

@ -14,7 +14,7 @@ use super::{
ImageInner, ImageLayout, ImageUsage,
};
use crate::{
device::{physical::QueueFamily, Device},
device::{physical::QueueFamily, Device, DeviceOwned},
format::{ClearValue, Format},
image::sys::UnsafeImageCreateInfo,
memory::{
@ -79,8 +79,8 @@ impl StorageImage {
}
let usage = ImageUsage {
transfer_source: true,
transfer_destination: true,
transfer_src: true,
transfer_dst: true,
sampled: true,
storage: true,
color_attachment: !is_depth,
@ -240,6 +240,15 @@ impl StorageImage {
}
}
unsafe impl<A> DeviceOwned for StorageImage<A>
where
A: MemoryPool,
{
fn device(&self) -> &Arc<Device> {
self.image.device()
}
}
unsafe impl<A> ImageAccess for StorageImage<A>
where
A: MemoryPool,
@ -249,7 +258,7 @@ where
ImageInner {
image: &self.image,
first_layer: 0,
num_layers: self.dimensions.array_layers() as usize,
num_layers: self.dimensions.array_layers(),
first_mipmap_level: 0,
num_mipmap_levels: 1,
}
@ -275,11 +284,6 @@ where
})
}
#[inline]
fn conflict_key(&self) -> u64 {
self.image.key()
}
#[inline]
fn current_mip_levels_access(&self) -> Range<u32> {
0..self.mip_levels()

View File

@ -11,7 +11,12 @@ use super::{
traits::{ImageClearValue, ImageContent},
ImageAccess, ImageDescriptorLayouts, ImageInner, ImageLayout,
};
use crate::{format::ClearValue, swapchain::Swapchain, OomError};
use crate::{
device::{Device, DeviceOwned},
format::ClearValue,
swapchain::Swapchain,
OomError,
};
use std::{
hash::{Hash, Hasher},
ops::Range,
@ -76,6 +81,12 @@ impl<W> SwapchainImage<W> {
}
}
unsafe impl<W> DeviceOwned for SwapchainImage<W> {
fn device(&self) -> &Arc<Device> {
self.swapchain.device()
}
}
unsafe impl<W> ImageAccess for SwapchainImage<W>
where
W: Send + Sync,
@ -105,11 +116,6 @@ where
})
}
#[inline]
fn conflict_key(&self) -> u64 {
self.my_image().image.key()
}
#[inline]
unsafe fn layout_initialized(&self) {
self.layout_initialized();

View File

@ -14,8 +14,9 @@
//! that you create must wrap around the types in this module.
use super::{
ImageAspect, ImageCreateFlags, ImageDimensions, ImageLayout, ImageSubresourceRange,
ImageTiling, ImageUsage, SampleCount, SampleCounts,
ImageAspect, ImageAspects, ImageCreateFlags, ImageDimensions, ImageLayout,
ImageSubresourceLayers, ImageSubresourceRange, ImageTiling, ImageUsage, SampleCount,
SampleCounts,
};
use crate::{
buffer::cpu_access::{ReadLockError, WriteLockError},
@ -397,14 +398,14 @@ impl UnsafeImage {
// These flags only exist in later versions, ignore them otherwise
if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
if usage.transfer_source && !format_features.transfer_src {
if usage.transfer_src && !format_features.transfer_src {
return Err(ImageCreationError::FormatUsageNotSupported {
usage: "transfer_source",
usage: "transfer_src",
});
}
if usage.transfer_destination && !format_features.transfer_dst {
if usage.transfer_dst && !format_features.transfer_dst {
return Err(ImageCreationError::FormatUsageNotSupported {
usage: "transfer_destination",
usage: "transfer_dst",
});
}
}
@ -632,8 +633,8 @@ impl UnsafeImage {
// VUID-VkImageCreateInfo-samples-02257 already states that multisampling+linear
// is invalid so no need to check for that here.
&& ImageUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
..usage.clone()
} == ImageUsage::none())
} else {
@ -1167,6 +1168,44 @@ impl UnsafeImage {
self.block_texel_view_compatible
}
/// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects
/// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
pub fn subresource_layers(&self) -> ImageSubresourceLayers {
ImageSubresourceLayers {
aspects: {
let aspects = self.format.unwrap().aspects();
if aspects.plane0 {
ImageAspects {
plane0: true,
..ImageAspects::none()
}
} else {
aspects
}
},
mip_level: 0,
array_layers: 0..self.dimensions.array_layers(),
}
}
/// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
/// only the `color` aspect is selected.
#[inline]
pub fn subresource_range(&self) -> ImageSubresourceRange {
ImageSubresourceRange {
aspects: ImageAspects {
plane0: false,
plane1: false,
plane2: false,
..self.format.unwrap().aspects()
},
mip_levels: 0..self.mip_levels,
array_layers: 0..self.dimensions.array_layers(),
}
}
/// Returns a key unique to each `UnsafeImage`. Can be used for the `conflicts_key` method.
#[inline]
pub fn key(&self) -> u64 {

View File

@ -7,28 +7,46 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{sys::UnsafeImage, ImageDescriptorLayouts, ImageDimensions, ImageLayout, SampleCount};
use super::{
sys::UnsafeImage, ImageDescriptorLayouts, ImageDimensions, ImageLayout, ImageSubresourceLayers,
ImageSubresourceRange, ImageUsage, SampleCount,
};
use crate::{
device::{Device, DeviceOwned},
format::{ClearValue, Format, FormatFeatures},
SafeDeref,
};
use std::{
fmt,
hash::{Hash, Hasher},
ops::Range,
sync::Arc,
};
/// Trait for types that represent the way a GPU can access an image.
pub unsafe trait ImageAccess: Send + Sync {
pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
/// Returns the inner unsafe image object used by this image.
fn inner(&self) -> ImageInner;
/// Returns the dimensions of the image.
#[inline]
fn dimensions(&self) -> ImageDimensions {
// TODO: not necessarily correct because of the new inner() design?
self.inner().image.dimensions()
}
/// Returns the format of this image.
#[inline]
fn format(&self) -> Format {
self.inner().image.format().unwrap()
}
/// Returns the features supported by the image's format.
#[inline]
fn format_features(&self) -> &FormatFeatures {
self.inner().image.format_features()
}
/// Returns the number of mipmap levels of this image.
#[inline]
fn mip_levels(&self) -> u32 {
@ -42,17 +60,24 @@ pub unsafe trait ImageAccess: Send + Sync {
self.inner().image.samples()
}
/// Returns the dimensions of the image.
/// Returns the usage the image was created with.
#[inline]
fn dimensions(&self) -> ImageDimensions {
// TODO: not necessarily correct because of the new inner() design?
self.inner().image.dimensions()
fn usage(&self) -> &ImageUsage {
self.inner().image.usage()
}
/// Returns the features supported by the image's format.
/// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects
/// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
fn format_features(&self) -> &FormatFeatures {
self.inner().image.format_features()
fn subresource_layers(&self) -> ImageSubresourceLayers {
self.inner().image.subresource_layers()
}
/// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
/// only the `color` aspect is selected.
#[inline]
fn subresource_range(&self) -> ImageSubresourceRange {
self.inner().image.subresource_range()
}
/// When images are created their memory layout is initially `Undefined` or `Preinitialized`.
@ -120,18 +145,6 @@ pub unsafe trait ImageAccess: Send + Sync {
/// This must return `Some` if the image is to be used to create an image view.
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>;
/// Returns a key that uniquely identifies the memory content of the image.
/// Two ranges that potentially overlap in memory must return the same key.
///
/// The key is shared amongst all buffers and images, which means that you can make several
/// different image objects share the same memory, or make some image objects share memory
/// with buffers, as long as they return the same key.
///
/// Since it is possible to accidentally return the same key for memory ranges that don't
/// overlap, the `conflicts_image` or `conflicts_buffer` function should always be called to
/// verify whether they actually overlap.
fn conflict_key(&self) -> u64;
/// Returns the current mip level that is accessed by the gpu
fn current_mip_levels_access(&self) -> Range<u32>;
@ -146,16 +159,24 @@ pub struct ImageInner<'a> {
pub image: &'a Arc<UnsafeImage>,
/// The first layer of `image` to consider.
pub first_layer: usize,
pub first_layer: u32,
/// The number of layers of `image` to consider.
pub num_layers: usize,
pub num_layers: u32,
/// The first mipmap level of `image` to consider.
pub first_mipmap_level: usize,
pub first_mipmap_level: u32,
/// The number of mipmap levels of `image` to consider.
pub num_mipmap_levels: usize,
pub num_mipmap_levels: u32,
}
impl fmt::Debug for dyn ImageAccess {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("dyn ImageAccess")
.field("inner", &self.inner())
.finish()
}
}
impl PartialEq for dyn ImageAccess {
@ -182,6 +203,15 @@ pub struct ImageAccessFromUndefinedLayout<I> {
preinitialized: bool,
}
unsafe impl<I> DeviceOwned for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
fn device(&self) -> &Arc<Device> {
self.image.device()
}
}
unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
@ -210,11 +240,6 @@ where
self.image.descriptor_layouts()
}
#[inline]
fn conflict_key(&self) -> u64 {
self.image.conflict_key()
}
fn current_mip_levels_access(&self) -> Range<u32> {
self.image.current_mip_levels_access()
}
@ -283,11 +308,6 @@ where
(**self).descriptor_layouts()
}
#[inline]
fn conflict_key(&self) -> u64 {
(**self).conflict_key()
}
#[inline]
unsafe fn layout_initialized(&self) {
(**self).layout_initialized();

View File

@ -19,10 +19,10 @@ use std::ops::BitOr;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ImageUsage {
/// Can be used as a source for transfers. Includes blits.
pub transfer_source: bool,
pub transfer_src: bool,
/// Can be used as a destination for transfers. Includes blits.
pub transfer_destination: bool,
pub transfer_dst: bool,
/// Can be sampled from a shader.
pub sampled: bool,
@ -54,8 +54,8 @@ impl ImageUsage {
#[inline]
pub fn all() -> ImageUsage {
ImageUsage {
transfer_source: true,
transfer_destination: true,
transfer_src: true,
transfer_dst: true,
sampled: true,
storage: true,
color_attachment: true,
@ -73,7 +73,7 @@ impl ImageUsage {
/// use vulkano::image::ImageUsage as ImageUsage;
///
/// let _usage = ImageUsage {
/// transfer_destination: true,
/// transfer_dst: true,
/// sampled: true,
/// .. ImageUsage::none()
/// };
@ -81,8 +81,8 @@ impl ImageUsage {
#[inline]
pub fn none() -> ImageUsage {
ImageUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
sampled: false,
storage: false,
color_attachment: false,
@ -96,8 +96,8 @@ impl ImageUsage {
#[inline]
pub fn color_attachment() -> ImageUsage {
ImageUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
sampled: false,
storage: false,
color_attachment: true,
@ -111,8 +111,8 @@ impl ImageUsage {
#[inline]
pub fn depth_stencil_attachment() -> ImageUsage {
ImageUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
sampled: false,
storage: false,
color_attachment: false,
@ -126,8 +126,8 @@ impl ImageUsage {
#[inline]
pub fn transient_color_attachment() -> ImageUsage {
ImageUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
sampled: false,
storage: false,
color_attachment: true,
@ -141,8 +141,8 @@ impl ImageUsage {
#[inline]
pub fn transient_depth_stencil_attachment() -> ImageUsage {
ImageUsage {
transfer_source: false,
transfer_destination: false,
transfer_src: false,
transfer_dst: false,
sampled: false,
storage: false,
color_attachment: false,
@ -157,10 +157,10 @@ impl From<ImageUsage> for ash::vk::ImageUsageFlags {
#[inline]
fn from(val: ImageUsage) -> Self {
let mut result = ash::vk::ImageUsageFlags::empty();
if val.transfer_source {
if val.transfer_src {
result |= ash::vk::ImageUsageFlags::TRANSFER_SRC;
}
if val.transfer_destination {
if val.transfer_dst {
result |= ash::vk::ImageUsageFlags::TRANSFER_DST;
}
if val.sampled {
@ -189,8 +189,8 @@ impl From<ash::vk::ImageUsageFlags> for ImageUsage {
#[inline]
fn from(val: ash::vk::ImageUsageFlags) -> ImageUsage {
ImageUsage {
transfer_source: !(val & ash::vk::ImageUsageFlags::TRANSFER_SRC).is_empty(),
transfer_destination: !(val & ash::vk::ImageUsageFlags::TRANSFER_DST).is_empty(),
transfer_src: !(val & ash::vk::ImageUsageFlags::TRANSFER_SRC).is_empty(),
transfer_dst: !(val & ash::vk::ImageUsageFlags::TRANSFER_DST).is_empty(),
sampled: !(val & ash::vk::ImageUsageFlags::SAMPLED).is_empty(),
storage: !(val & ash::vk::ImageUsageFlags::STORAGE).is_empty(),
color_attachment: !(val & ash::vk::ImageUsageFlags::COLOR_ATTACHMENT).is_empty(),
@ -209,8 +209,8 @@ impl BitOr for ImageUsage {
#[inline]
fn bitor(self, rhs: Self) -> Self {
ImageUsage {
transfer_source: self.transfer_source || rhs.transfer_source,
transfer_destination: self.transfer_destination || rhs.transfer_destination,
transfer_src: self.transfer_src || rhs.transfer_src,
transfer_dst: self.transfer_dst || rhs.transfer_dst,
sampled: self.sampled || rhs.sampled,
storage: self.storage || rhs.storage,
color_attachment: self.color_attachment || rhs.color_attachment,

View File

@ -101,10 +101,6 @@ mod tests {
fn size(&self) -> DeviceSize {
unimplemented!()
}
fn conflict_key(&self) -> (u64, u64) {
unimplemented!()
}
}
unsafe impl DeviceOwned for DummyBufferA {
@ -127,10 +123,6 @@ mod tests {
fn size(&self) -> DeviceSize {
unimplemented!()
}
fn conflict_key(&self) -> (u64, u64) {
unimplemented!()
}
}
unsafe impl DeviceOwned for DummyBufferB {

View File

@ -688,7 +688,7 @@ impl<W> Swapchain<W> {
self.images.get(offset).map(|i| ImageInner {
image: &i.image,
first_layer: 0,
num_layers: self.image_array_layers as usize,
num_layers: self.image_array_layers,
first_mipmap_level: 0,
num_mipmap_levels: 1,
})