Align the validation of Device::create_texture with the WebGPU spec (#2759)

This commit is contained in:
Nicolas Silva 2022-06-10 22:02:49 +02:00 committed by GitHub
parent 048a420d82
commit 629ccaf4e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 49 deletions

View File

@ -116,14 +116,7 @@ pub fn check_texture_dimension_size(
use wgt::TextureDimension::*;
let (extent_limits, sample_limit) = match dimension {
D1 => (
[
limits.max_texture_dimension_1d,
1,
limits.max_texture_array_layers,
],
1,
),
D1 => ([limits.max_texture_dimension_1d, 1, 1], 1),
D2 => (
[
limits.max_texture_dimension_2d,

View File

@ -678,47 +678,10 @@ impl<A: HalApi> Device<A> {
adapter: &crate::instance::Adapter<A>,
desc: &resource::TextureDescriptor,
) -> Result<resource::Texture<A>, resource::CreateTextureError> {
let format_desc = desc.format.describe();
if desc.dimension != wgt::TextureDimension::D2 {
// Depth textures can only be 2D
if format_desc.sample_type == wgt::TextureSampleType::Depth {
return Err(resource::CreateTextureError::InvalidDepthDimension(
desc.dimension,
desc.format,
));
}
// Renderable textures can only be 2D
if desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
return Err(resource::CreateTextureError::InvalidDimensionUsages(
wgt::TextureUsages::RENDER_ATTACHMENT,
desc.dimension,
));
}
// Compressed textures can only be 2D
if format_desc.is_compressed() {
return Err(resource::CreateTextureError::InvalidCompressedDimension(
desc.dimension,
desc.format,
));
}
}
let format_features = self
.describe_format_features(adapter, desc.format)
.map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?;
use resource::{CreateTextureError, TextureDimensionError};
if desc.usage.is_empty() {
return Err(resource::CreateTextureError::EmptyUsage);
}
let missing_allowed_usages = desc.usage - format_features.allowed_usages;
if !missing_allowed_usages.is_empty() {
return Err(resource::CreateTextureError::InvalidFormatUsages(
missing_allowed_usages,
desc.format,
));
return Err(CreateTextureError::EmptyUsage);
}
conv::check_texture_dimension_size(
@ -728,15 +691,114 @@ impl<A: HalApi> Device<A> {
&self.limits,
)?;
let format_desc = desc.format.describe();
if desc.dimension != wgt::TextureDimension::D2 {
// Depth textures can only be 2D
if format_desc.sample_type == wgt::TextureSampleType::Depth {
return Err(CreateTextureError::InvalidDepthDimension(
desc.dimension,
desc.format,
));
}
// Renderable textures can only be 2D
if desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
return Err(CreateTextureError::InvalidDimensionUsages(
wgt::TextureUsages::RENDER_ATTACHMENT,
desc.dimension,
));
}
// Compressed textures can only be 2D
if format_desc.is_compressed() {
return Err(CreateTextureError::InvalidCompressedDimension(
desc.dimension,
desc.format,
));
}
}
if format_desc.is_compressed() {
let block_width = format_desc.block_dimensions.0 as u32;
let block_height = format_desc.block_dimensions.1 as u32;
if desc.size.width % block_width != 0 {
return Err(CreateTextureError::InvalidDimension(
TextureDimensionError::NotMultipleOfBlockWidth {
width: desc.size.width,
block_width,
format: desc.format,
},
));
}
if desc.size.height % block_height != 0 {
return Err(CreateTextureError::InvalidDimension(
TextureDimensionError::NotMultipleOfBlockHeight {
height: desc.size.height,
block_height,
format: desc.format,
},
));
}
}
if desc.sample_count > 1 {
if desc.mip_level_count != 1 {
return Err(CreateTextureError::InvalidMipLevelCount {
requested: desc.mip_level_count,
maximum: 1,
});
}
if desc.size.depth_or_array_layers != 1 {
return Err(CreateTextureError::InvalidDimension(
TextureDimensionError::MultisampledDepthOrArrayLayer(
desc.size.depth_or_array_layers,
),
));
}
if desc.usage.contains(wgt::TextureUsages::STORAGE_BINDING) {
return Err(CreateTextureError::InvalidMultisampledStorageBinding);
}
if !desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
return Err(CreateTextureError::MultisampledNotRenderAttachment);
}
if !format_desc
.guaranteed_format_features
.flags
.contains(wgt::TextureFormatFeatureFlags::MULTISAMPLE)
{
return Err(CreateTextureError::InvalidMultisampledFormat(desc.format));
}
}
let mips = desc.mip_level_count;
let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS);
if mips == 0 || mips > max_levels_allowed {
return Err(resource::CreateTextureError::InvalidMipLevelCount {
return Err(CreateTextureError::InvalidMipLevelCount {
requested: mips,
maximum: max_levels_allowed,
});
}
let format_features = self
.describe_format_features(adapter, desc.format)
.map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
let missing_allowed_usages = desc.usage - format_features.allowed_usages;
if !missing_allowed_usages.is_empty() {
return Err(CreateTextureError::InvalidFormatUsages(
missing_allowed_usages,
desc.format,
));
}
// TODO: validate missing TextureDescriptor::view_formats.
// Enforce having COPY_DST/DEPTH_STENCIL_WRIT/COLOR_TARGET otherwise we wouldn't be able to initialize the texture.
let hal_usage = conv::map_texture_usage(desc.usage, desc.format.into())
| if format_desc.sample_type == wgt::TextureSampleType::Depth {

View File

@ -336,8 +336,22 @@ pub enum TextureDimensionError {
given: u32,
limit: u32,
},
#[error("sample count {0} is invalid")]
#[error("Sample count {0} is invalid")]
InvalidSampleCount(u32),
#[error("Width {width} is not a multiple of {format:?}'s block width ({block_width})")]
NotMultipleOfBlockWidth {
width: u32,
block_width: u32,
format: wgt::TextureFormat,
},
#[error("Height {height} is not a multiple of {format:?}'s block height ({block_height})")]
NotMultipleOfBlockHeight {
height: u32,
block_height: u32,
format: wgt::TextureFormat,
},
#[error("Multisampled texture depth or array layers must be 1, got {0}")]
MultisampledDepthOrArrayLayer(u32),
}
#[derive(Clone, Debug, Error)]
@ -360,6 +374,12 @@ pub enum CreateTextureError {
InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat),
#[error("Texture usages {0:?} are not allowed on a texture of dimensions {1:?}")]
InvalidDimensionUsages(wgt::TextureUsages, wgt::TextureDimension),
#[error("Texture usage STORAGE_BINDING is not allowed for multisampled textures")]
InvalidMultisampledStorageBinding,
#[error("Format {0:?} does not support multisampling")]
InvalidMultisampledFormat(wgt::TextureFormat),
#[error("Multisampled textures must have RENDER_ATTACHMENT usage")]
MultisampledNotRenderAttachment,
#[error("Texture format {0:?} can't be used due to missing features.")]
MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures),
}

View File

@ -3306,6 +3306,7 @@ pub struct TextureDescriptor<L> {
pub format: TextureFormat,
/// Allowed usages of the texture. If used in other ways, the operation will panic.
pub usage: TextureUsages,
// TODO: missing view_formats https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-viewformats
}
impl<L> TextureDescriptor<L> {