Better error message when source is too small for ImmutableImage (#2022)

This commit is contained in:
Rua 2022-10-06 14:36:38 +02:00 committed by GitHub
parent f99c67929f
commit de920e4a3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 21 deletions

View File

@ -16,7 +16,7 @@ use crate::{
buffer::{BufferAccess, BufferContents, BufferUsage, CpuAccessibleBuffer},
command_buffer::{
allocator::CommandBufferAllocator, AutoCommandBufferBuilder, BlitImageInfo,
CommandBufferBeginError, CommandBufferExecFuture, CommandBufferUsage,
BufferImageCopy, CommandBufferBeginError, CommandBufferExecFuture, CommandBufferUsage,
CopyBufferToImageInfo, ImageBlit, PrimaryCommandBuffer,
},
device::{Device, DeviceOwned, Queue},
@ -31,9 +31,9 @@ use crate::{
},
sampler::Filter,
sync::{NowFuture, Sharing},
OomError,
DeviceSize, OomError,
};
use smallvec::SmallVec;
use smallvec::{smallvec, SmallVec};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
@ -218,6 +218,23 @@ impl ImmutableImage {
command_buffer_allocator: &impl CommandBufferAllocator,
queue: Arc<Queue>,
) -> Result<(Arc<Self>, CommandBufferExecFuture<NowFuture>), ImmutableImageCreationError> {
let region = BufferImageCopy {
image_subresource: ImageSubresourceLayers::from_parameters(
format,
dimensions.array_layers(),
),
image_extent: dimensions.width_height_depth(),
..Default::default()
};
let required_size = region.buffer_copy_size(format);
if source.size() < required_size {
return Err(ImmutableImageCreationError::SourceTooSmall {
source_size: source.size(),
required_size,
});
}
let need_to_generate_mipmaps = has_mipmaps(mip_levels);
let usage = ImageUsage {
transfer_dst: true,
@ -248,7 +265,10 @@ impl ImmutableImage {
queue.queue_family_index(),
CommandBufferUsage::MultipleSubmit,
)?;
cbb.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(source, initializer))
cbb.copy_buffer_to_image(CopyBufferToImageInfo {
regions: smallvec![region],
..CopyBufferToImageInfo::buffer_image(source, initializer)
})
.unwrap();
if need_to_generate_mipmaps {
@ -394,11 +414,19 @@ where
}
}
/// Error that can happen when creating an `ImmutableImage`.
#[derive(Clone, Debug)]
pub enum ImmutableImageCreationError {
ImageCreationError(ImageCreationError),
DeviceMemoryAllocationError(DeviceMemoryError),
CommandBufferBeginError(CommandBufferBeginError),
/// The size of the provided source data is less than the required size for an image with the
/// given format and dimensions.
SourceTooSmall {
source_size: DeviceSize,
required_size: DeviceSize,
},
}
impl Error for ImmutableImageCreationError {
@ -407,6 +435,7 @@ impl Error for ImmutableImageCreationError {
Self::ImageCreationError(err) => Some(err),
Self::DeviceMemoryAllocationError(err) => Some(err),
Self::CommandBufferBeginError(err) => Some(err),
_ => None,
}
}
}
@ -417,6 +446,15 @@ impl Display for ImmutableImageCreationError {
Self::ImageCreationError(err) => err.fmt(f),
Self::DeviceMemoryAllocationError(err) => err.fmt(f),
Self::CommandBufferBeginError(err) => err.fmt(f),
Self::SourceTooSmall {
source_size,
required_size,
} => write!(
f,
"the size of the provided source data ({} bytes) is less than the required size for an image of the given format and dimensions ({} bytes)",
source_size, required_size,
),
}
}
}

View File

@ -518,6 +518,31 @@ pub struct ImageSubresourceLayers {
pub array_layers: Range<u32>,
}
impl ImageSubresourceLayers {
/// Returns an `ImageSubresourceLayers` from the given image parameters, 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 from_parameters(format: Format, array_layers: u32) -> Self {
Self {
aspects: {
let aspects = format.aspects();
if aspects.plane0 {
ImageAspects {
plane0: true,
..ImageAspects::empty()
}
} else {
aspects
}
},
mip_level: 0,
array_layers: 0..array_layers,
}
}
}
impl From<ImageSubresourceLayers> for ash::vk::ImageSubresourceLayers {
#[inline]
fn from(val: ImageSubresourceLayers) -> Self {
@ -550,6 +575,24 @@ pub struct ImageSubresourceRange {
pub array_layers: Range<u32>,
}
impl ImageSubresourceRange {
/// Returns an `ImageSubresourceRange` from the given image parameters, covering the whole
/// image. If the image is multi-planar, only the `color` aspect is selected.
#[inline]
pub fn from_parameters(format: Format, mip_levels: u32, array_layers: u32) -> Self {
Self {
aspects: ImageAspects {
plane0: false,
plane1: false,
plane2: false,
..format.aspects()
},
mip_levels: 0..mip_levels,
array_layers: 0..array_layers,
}
}
}
impl From<ImageSubresourceRange> for ash::vk::ImageSubresourceRange {
#[inline]
fn from(val: ImageSubresourceRange) -> Self {

View File

@ -107,22 +107,7 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
/// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
fn subresource_layers(&self) -> ImageSubresourceLayers {
ImageSubresourceLayers {
aspects: {
let aspects = self.format().aspects();
if aspects.plane0 {
ImageAspects {
plane0: true,
..ImageAspects::empty()
}
} else {
aspects
}
},
mip_level: 0,
array_layers: 0..self.dimensions().array_layers(),
}
ImageSubresourceLayers::from_parameters(self.format(), self.dimensions().array_layers())
}
/// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,