mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Align the validation of Device::create_texture with the WebGPU spec (#2759)
This commit is contained in:
parent
048a420d82
commit
629ccaf4e0
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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> {
|
||||
|
Loading…
Reference in New Issue
Block a user