diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 10126a9b97..0961f850e7 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -96,6 +96,8 @@ pub enum CreateBindGroupError { WrongSamplerComparison, #[error("bound texture views can not have both depth and stencil aspects enabled")] DepthStencilAspect, + #[error("the adapter does not support simultaneous read + write storage texture access for the format {0:?}")] + StorageReadWriteNotSupported(wgt::TextureFormat), } #[derive(Clone, Debug, Error)] diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 80d7ea3502..d6651f1a0b 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -516,15 +516,16 @@ impl Device { fn create_texture( &self, self_id: id::DeviceId, + adapter: &crate::instance::Adapter, desc: &resource::TextureDescriptor, ) -> Result, resource::CreateTextureError> { debug_assert_eq!(self_id.backend(), B::VARIANT); let format_desc = desc.format.describe(); - let features = format_desc.features; - if !self.features.contains(features) { + let required_features = format_desc.required_features; + if !self.features.contains(required_features) { return Err(resource::CreateTextureError::MissingFeature( - features, + required_features, desc.format, )); } @@ -546,10 +547,19 @@ impl Device { return Err(resource::CreateTextureError::EmptyUsage); } - let missing_features = desc.usage - format_desc.allowed_usages; - if !missing_features.is_empty() { + let format_features = if self + .features + .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) + { + adapter.get_texture_format_features(desc.format) + } else { + format_desc.guaranteed_format_features + }; + + let missing_allowed_usages = desc.usage - format_features.allowed_usages; + if !missing_allowed_usages.is_empty() { return Err(resource::CreateTextureError::InvalidUsages( - missing_features, + missing_allowed_usages, desc.format, )); } @@ -618,6 +628,7 @@ impl Device { dimension: desc.dimension, kind, format: desc.format, + format_features, full_range: TextureSelector { levels: 0..desc.mip_level_count as hal::image::Level, layers: 0..kind.num_layers(), @@ -774,6 +785,7 @@ impl Device { }, aspects, format: texture.format, + format_features: texture.format_features, extent: texture.kind.extent().at_level(desc.base_mip_level as _), samples: texture.kind.num_samples(), selector, @@ -1301,17 +1313,33 @@ impl Device { wgt::BindingType::Texture { .. } => { (wgt::TextureUsage::SAMPLED, resource::TextureUse::SAMPLED) } - wgt::BindingType::StorageTexture { access, .. } => ( - wgt::TextureUsage::STORAGE, - match access { + wgt::BindingType::StorageTexture { access, .. } => { + let internal_use = match access { wgt::StorageTextureAccess::ReadOnly => { resource::TextureUse::STORAGE_LOAD } wgt::StorageTextureAccess::WriteOnly => { resource::TextureUse::STORAGE_STORE } - }, - ), + wgt::StorageTextureAccess::ReadWrite => { + if !view.format_features.flags.contains( + wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE, + ) { + return Err(if self.features.contains( + wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, + ) { + Error::StorageReadWriteNotSupported(view.format) + } else { + Error::MissingFeatures(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) + }); + } + + resource::TextureUse::STORAGE_STORE + | resource::TextureUse::STORAGE_LOAD + } + }; + (wgt::TextureUsage::STORAGE, internal_use) + } _ => return Err(Error::WrongBindingType { binding, actual: decl.ty.clone(), @@ -2692,13 +2720,15 @@ impl Global { let hub = B::hub(self); let mut token = Token::root(); + let (adapter_guard, mut token) = hub.adapters.read(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token); let error = loop { let device = match device_guard.get(device_id) { Ok(device) => device, Err(_) => break DeviceError::Invalid.into(), }; - let texture = match device.create_texture(device_id, desc) { + let adapter = &adapter_guard[device.adapter_id.value]; + let texture = match device.create_texture(device_id, adapter, desc) { Ok(texture) => texture, Err(error) => break error, }; diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index b57c1f0716..c4813bdf38 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -120,6 +120,7 @@ impl crate::hub::Resource for Surface { pub struct Adapter { pub(crate) raw: hal::adapter::Adapter, features: wgt::Features, + private_features: PrivateFeatures, limits: wgt::Limits, life_guard: LifeGuard, } @@ -132,7 +133,8 @@ impl Adapter { let mut features = wgt::Features::default() | wgt::Features::MAPPABLE_PRIMARY_BUFFERS - | wgt::Features::PUSH_CONSTANTS; + | wgt::Features::PUSH_CONSTANTS + | wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES; features.set( wgt::Features::DEPTH_CLAMPING, adapter_features.contains(hal::Features::DEPTH_CLAMP), @@ -181,6 +183,20 @@ impl Adapter { //TODO: https://github.com/gfx-rs/gfx/issues/3346 features.set(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true); + let private_features = PrivateFeatures { + anisotropic_filtering: adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY), + texture_d24: raw + .physical_device + .format_properties(Some(hal::format::Format::X8D24Unorm)) + .optimal_tiling + .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT), + texture_d24_s8: raw + .physical_device + .format_properties(Some(hal::format::Format::D24UnormS8Uint)) + .optimal_tiling + .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT), + }; + let adapter_limits = raw.physical_device.limits(); let default_limits = wgt::Limits::default(); @@ -228,11 +244,60 @@ impl Adapter { Self { raw, features, + private_features, limits, life_guard: LifeGuard::new(""), } } + pub(crate) fn get_texture_format_features( + &self, + format: wgt::TextureFormat, + ) -> wgt::TextureFormatFeatures { + let texture_format_properties = self + .raw + .physical_device + .format_properties(Some(conv::map_texture_format( + format, + self.private_features, + ))) + .optimal_tiling; + + let mut allowed_usages = wgt::TextureUsage::empty(); + if texture_format_properties.contains(hal::format::ImageFeature::SAMPLED) { + allowed_usages |= wgt::TextureUsage::SAMPLED; + } + if texture_format_properties.contains(hal::format::ImageFeature::STORAGE) { + allowed_usages |= wgt::TextureUsage::STORAGE; + } + if texture_format_properties.contains(hal::format::ImageFeature::COLOR_ATTACHMENT) { + allowed_usages |= wgt::TextureUsage::RENDER_ATTACHMENT; + } + if texture_format_properties.contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT) { + allowed_usages |= wgt::TextureUsage::RENDER_ATTACHMENT; + } + if texture_format_properties.contains(hal::format::ImageFeature::BLIT_SRC) { + allowed_usages |= wgt::TextureUsage::COPY_SRC; + } + if texture_format_properties.contains(hal::format::ImageFeature::BLIT_DST) { + allowed_usages |= wgt::TextureUsage::COPY_DST; + } + + let mut flags = wgt::TextureFormatFeatureFlags::empty(); + if texture_format_properties.contains(hal::format::ImageFeature::STORAGE_ATOMIC) { + flags |= wgt::TextureFormatFeatureFlags::STORAGE_ATOMICS; + } + // TODO: Hal update required. This in turn is blocked by https://github.com/zakarumych/gpu-alloc/issues/33 + //if texture_format_properties.contains(hal::format::ImageFeature::STORAGE_READ_WRITE) { + // flags |= wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE; + //} + + wgt::TextureFormatFeatures { + allowed_usages, + flags, + } + } + fn create_device( &self, self_id: AdapterId, @@ -364,17 +429,6 @@ impl Adapter { } let mem_props = phd.memory_properties(); - let private_features = PrivateFeatures { - anisotropic_filtering: enabled_features.contains(hal::Features::SAMPLER_ANISOTROPY), - texture_d24: phd - .format_properties(Some(hal::format::Format::X8D24Unorm)) - .optimal_tiling - .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT), - texture_d24_s8: phd - .format_properties(Some(hal::format::Format::D24UnormS8Uint)) - .optimal_tiling - .contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT), - }; Device::new( gpu.device, @@ -385,7 +439,7 @@ impl Adapter { gpu.queue_groups.swap_remove(0), mem_props, limits, - private_features, + self.private_features, desc, trace_path, ) @@ -708,6 +762,22 @@ impl Global { .map_err(|_| InvalidAdapter) } + pub fn adapter_get_texture_format_features( + &self, + adapter_id: AdapterId, + format: wgt::TextureFormat, + ) -> Result { + span!(_guard, INFO, "Adapter::get_texture_format_features"); + + let hub = B::hub(self); + let mut token = Token::root(); + let (adapter_guard, _) = hub.adapters.read(&mut token); + adapter_guard + .get(adapter_id) + .map(|adapter| adapter.get_texture_format_features(format)) + .map_err(|_| InvalidAdapter) + } + pub fn adapter_features( &self, adapter_id: AdapterId, diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 039ba15b4f..c4ecf7161f 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -205,6 +205,7 @@ pub struct Texture { pub(crate) dimension: wgt::TextureDimension, pub(crate) kind: hal::image::Kind, pub(crate) format: wgt::TextureFormat, + pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) full_range: TextureSelector, pub(crate) life_guard: LifeGuard, } @@ -305,6 +306,7 @@ pub struct TextureView { //TODO: store device_id for quick access? pub(crate) aspects: hal::format::Aspects, pub(crate) format: wgt::TextureFormat, + pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) extent: hal::image::Extent, pub(crate) samples: hal::image::NumSamples, pub(crate) selector: TextureSelector, diff --git a/wgpu-core/src/swap_chain.rs b/wgpu-core/src/swap_chain.rs index e2ece136f6..9336858df4 100644 --- a/wgpu-core/src/swap_chain.rs +++ b/wgpu-core/src/swap_chain.rs @@ -182,6 +182,10 @@ impl Global { }, aspects: hal::format::Aspects::COLOR, format: sc.desc.format, + format_features: wgt::TextureFormatFeatures { + allowed_usages: wgt::TextureUsage::RENDER_ATTACHMENT, + flags: wgt::TextureFormatFeatureFlags::empty(), + }, extent: hal::image::Extent { width: sc.desc.width, height: sc.desc.height, diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 48f2dfb9ae..cf960d9b31 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -418,6 +418,7 @@ impl Resource { let usage = match access { wgt::StorageTextureAccess::ReadOnly => naga::GlobalUse::LOAD, wgt::StorageTextureAccess::WriteOnly => naga::GlobalUse::STORE, + wgt::StorageTextureAccess::ReadWrite => naga::GlobalUse::all(), }; (naga::ImageClass::Storage(naga_format), usage) } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 3790af9011..1a7a497624 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -162,6 +162,9 @@ bitflags::bitflags! { /// Compressed textures sacrifice some quality in exchange for significantly reduced /// bandwidth usage. /// + /// Support for this feature guarantees availability of [`TextureUsage::COPY_SRC | TextureUsage::COPY_DST | TextureUsage::SAMPLED`] for BCn formats. + /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages. + /// /// Supported Platforms: /// - desktops /// @@ -312,6 +315,9 @@ bitflags::bitflags! { /// Compressed textures sacrifice some quality in exchange for significantly reduced /// bandwidth usage. /// + /// Support for this feature guarantees availability of [`TextureUsage::COPY_SRC | TextureUsage::COPY_DST | TextureUsage::SAMPLED`] for ETC2 formats. + /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages. + /// /// Supported Platforms: /// - Intel/Vulkan /// - Mobile (some) @@ -324,12 +330,27 @@ bitflags::bitflags! { /// Compressed textures sacrifice some quality in exchange for significantly reduced /// bandwidth usage. /// + /// Support for this feature guarantees availability of [`TextureUsage::COPY_SRC | TextureUsage::COPY_DST | TextureUsage::SAMPLED`] for ASTC formats. + /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] may enable additional usages. + /// /// Supported Platforms: /// - Intel/Vulkan /// - Mobile (some) /// /// This is a native-only feature. const TEXTURE_COMPRESSION_ASTC_LDR = 0x0000_0000_0800_0000; + /// Enables device specific texture format features. + /// + /// See `TextureFormatFeatures` for a listing of the features in question. + /// + /// By default only texture format properties as defined by the WebGPU specification are allowed. + /// Enabling this feature flag extends the features of each format to the ones supported by the current device. + /// Note that without this flag, read/write storage access is not allowed at all. + /// + /// This extension does not enable additional formats. + /// + /// This is a native-only feature. + const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 0x0000_0000_1000_0000; /// Features which are part of the upstream WebGPU standard. const ALL_WEBGPU = 0x0000_0000_0000_FFFF; /// Features that are only available when targeting native (not web). @@ -754,11 +775,33 @@ pub struct RasterizationStateDescriptor { pub depth_bias_clamp: f32, } +bitflags::bitflags! { + /// Feature flags for a texture format. + #[repr(transparent)] + #[cfg_attr(feature = "trace", derive(Serialize))] + #[cfg_attr(feature = "replay", derive(Deserialize))] + pub struct TextureFormatFeatureFlags: u32 { + /// When used as a STORAGE texture, then a texture with this format can be bound with `StorageTextureAccess::ReadWrite`. + const STORAGE_READ_WRITE = 1; + /// When used as a STORAGE texture, then a texture with this format can be written to with atomics. TODO: No access flag exposed as of writing + const STORAGE_ATOMICS = 2; + } +} + +/// Features supported by a given texture format +/// +/// Features are defined by WebGPU specification unless `Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES` is enabled. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct TextureFormatFeatures { + pub allowed_usages: TextureUsage, + pub flags: TextureFormatFeatureFlags, +} + /// Information about a texture format. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct TextureFormatInfo { /// Features required (if any) to use the texture. - pub features: Features, + pub required_features: Features, /// Type of sampling that is valid for the texture. pub sample_type: TextureSampleType, /// Dimension of a "block" of texels. This is always (1, 1) on uncompressed textures. @@ -767,8 +810,8 @@ pub struct TextureFormatInfo { pub block_size: u8, /// Format will have colors be converted from srgb to linear on read and from linear to srgb on write. pub srgb: bool, - /// Allowed usage flags for the format. - pub allowed_usages: TextureUsage, + /// Format features guaranteed by the WebGPU spec. Additional features are available if `Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES` is enabled. + pub guaranteed_format_features: TextureFormatFeatures, } /// Underlying texture data format. @@ -1185,126 +1228,129 @@ impl TextureFormat { let all_flags = TextureUsage::all(); // See https://gpuweb.github.io/gpuweb/#texture-format-caps for reference - let (features, sample_type, srgb, block_dimensions, block_size, allowed_usages) = match self - { - // Normal 8 bit textures - Self::R8Unorm => (native, float, linear, (1, 1), 1, attachment), - Self::R8Snorm => (native, float, linear, (1, 1), 1, basic), - Self::R8Uint => (native, uint, linear, (1, 1), 1, attachment), - Self::R8Sint => (native, sint, linear, (1, 1), 1, attachment), - - // Normal 16 bit textures - Self::R16Uint => (native, uint, linear, (1, 1), 2, attachment), - Self::R16Sint => (native, sint, linear, (1, 1), 2, attachment), - Self::R16Float => (native, float, linear, (1, 1), 2, attachment), - Self::Rg8Unorm => (native, float, linear, (1, 1), 2, attachment), - Self::Rg8Snorm => (native, float, linear, (1, 1), 2, attachment), - Self::Rg8Uint => (native, uint, linear, (1, 1), 2, attachment), - Self::Rg8Sint => (native, sint, linear, (1, 1), 2, basic), - - // Normal 32 bit textures - Self::R32Uint => (native, uint, linear, (1, 1), 4, all_flags), - Self::R32Sint => (native, sint, linear, (1, 1), 4, all_flags), - Self::R32Float => (native, nearest, linear, (1, 1), 4, all_flags), - Self::Rg16Uint => (native, uint, linear, (1, 1), 4, attachment), - Self::Rg16Sint => (native, sint, linear, (1, 1), 4, attachment), - Self::Rg16Float => (native, float, linear, (1, 1), 4, attachment), - Self::Rgba8Unorm => (native, float, linear, (1, 1), 4, all_flags), - Self::Rgba8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment), - Self::Rgba8Snorm => (native, float, linear, (1, 1), 4, storage), - Self::Rgba8Uint => (native, uint, linear, (1, 1), 4, all_flags), - Self::Rgba8Sint => (native, sint, linear, (1, 1), 4, all_flags), - Self::Bgra8Unorm => (native, float, linear, (1, 1), 4, attachment), - Self::Bgra8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment), - - // Packed 32 bit textures - Self::Rgb10a2Unorm => (native, float, linear, (1, 1), 4, attachment), - Self::Rg11b10Float => (native, float, linear, (1, 1), 4, basic), - - // Packed 32 bit textures - Self::Rg32Uint => (native, uint, linear, (1, 1), 8, all_flags), - Self::Rg32Sint => (native, sint, linear, (1, 1), 8, all_flags), - Self::Rg32Float => (native, nearest, linear, (1, 1), 8, all_flags), - Self::Rgba16Uint => (native, uint, linear, (1, 1), 8, all_flags), - Self::Rgba16Sint => (native, sint, linear, (1, 1), 8, all_flags), - Self::Rgba16Float => (native, float, linear, (1, 1), 8, all_flags), - - // Packed 32 bit textures - Self::Rgba32Uint => (native, uint, linear, (1, 1), 16, all_flags), - Self::Rgba32Sint => (native, sint, linear, (1, 1), 16, all_flags), - Self::Rgba32Float => (native, nearest, linear, (1, 1), 16, all_flags), - - // Depth-stencil textures - Self::Depth32Float => (native, depth, linear, (1, 1), 4, attachment), - Self::Depth24Plus => (native, depth, linear, (1, 1), 4, attachment), - Self::Depth24PlusStencil8 => (native, depth, linear, (1, 1), 4, attachment), - - // BCn compressed textures - Self::Bc1RgbaUnorm => (bc, float, linear, (4, 4), 8, basic), - Self::Bc1RgbaUnormSrgb => (bc, float, srgb, (4, 4), 8, basic), - Self::Bc2RgbaUnorm => (bc, float, linear, (4, 4), 16, basic), - Self::Bc2RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic), - Self::Bc3RgbaUnorm => (bc, float, linear, (4, 4), 16, basic), - Self::Bc3RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic), - Self::Bc4RUnorm => (bc, float, linear, (4, 4), 8, basic), - Self::Bc4RSnorm => (bc, float, linear, (4, 4), 8, basic), - Self::Bc5RgUnorm => (bc, float, linear, (4, 4), 16, basic), - Self::Bc5RgSnorm => (bc, float, linear, (4, 4), 16, basic), - Self::Bc6hRgbUfloat => (bc, float, linear, (4, 4), 16, basic), - Self::Bc6hRgbSfloat => (bc, float, linear, (4, 4), 16, basic), - Self::Bc7RgbaUnorm => (bc, float, linear, (4, 4), 16, basic), - Self::Bc7RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic), - - // ETC compressed textures - Self::Etc2RgbUnorm => (etc2, float, linear, (4, 4), 8, basic), - Self::Etc2RgbUnormSrgb => (etc2, float, srgb, (4, 4), 8, basic), - Self::Etc2RgbA1Unorm => (etc2, float, linear, (4, 4), 8, basic), - Self::Etc2RgbA1UnormSrgb => (etc2, float, srgb, (4, 4), 8, basic), - Self::Etc2RgbA8Unorm => (etc2, float, linear, (4, 4), 16, basic), - Self::Etc2RgbA8UnormSrgb => (etc2, float, srgb, (4, 4), 16, basic), - Self::EacRUnorm => (etc2, float, linear, (4, 4), 8, basic), - Self::EacRSnorm => (etc2, float, linear, (4, 4), 8, basic), - Self::EtcRgUnorm => (etc2, float, linear, (4, 4), 16, basic), - Self::EtcRgSnorm => (etc2, float, linear, (4, 4), 16, basic), - - // ASTC compressed textures - Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, (4, 4), 16, basic), - Self::Astc4x4RgbaUnormSrgb => (astc_ldr, float, srgb, (4, 4), 16, basic), - Self::Astc5x4RgbaUnorm => (astc_ldr, float, linear, (5, 4), 16, basic), - Self::Astc5x4RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 4), 16, basic), - Self::Astc5x5RgbaUnorm => (astc_ldr, float, linear, (5, 5), 16, basic), - Self::Astc5x5RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 5), 16, basic), - Self::Astc6x5RgbaUnorm => (astc_ldr, float, linear, (6, 5), 16, basic), - Self::Astc6x5RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 5), 16, basic), - Self::Astc6x6RgbaUnorm => (astc_ldr, float, linear, (6, 6), 16, basic), - Self::Astc6x6RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 6), 16, basic), - Self::Astc8x5RgbaUnorm => (astc_ldr, float, linear, (8, 5), 16, basic), - Self::Astc8x5RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 5), 16, basic), - Self::Astc8x6RgbaUnorm => (astc_ldr, float, linear, (8, 6), 16, basic), - Self::Astc8x6RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 6), 16, basic), - Self::Astc10x5RgbaUnorm => (astc_ldr, float, linear, (10, 5), 16, basic), - Self::Astc10x5RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 5), 16, basic), - Self::Astc10x6RgbaUnorm => (astc_ldr, float, linear, (10, 6), 16, basic), - Self::Astc10x6RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 6), 16, basic), - Self::Astc8x8RgbaUnorm => (astc_ldr, float, linear, (8, 8), 16, basic), - Self::Astc8x8RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 8), 16, basic), - Self::Astc10x8RgbaUnorm => (astc_ldr, float, linear, (10, 8), 16, basic), - Self::Astc10x8RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 8), 16, basic), - Self::Astc10x10RgbaUnorm => (astc_ldr, float, linear, (10, 10), 16, basic), - Self::Astc10x10RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 10), 16, basic), - Self::Astc12x10RgbaUnorm => (astc_ldr, float, linear, (12, 10), 16, basic), - Self::Astc12x10RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 10), 16, basic), - Self::Astc12x12RgbaUnorm => (astc_ldr, float, linear, (12, 12), 16, basic), - Self::Astc12x12RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 12), 16, basic), - }; + let (required_features, sample_type, srgb, block_dimensions, block_size, allowed_usages) = + match self { + // Normal 8 bit textures + Self::R8Unorm => (native, float, linear, (1, 1), 1, attachment), + Self::R8Snorm => (native, float, linear, (1, 1), 1, basic), + Self::R8Uint => (native, uint, linear, (1, 1), 1, attachment), + Self::R8Sint => (native, sint, linear, (1, 1), 1, attachment), + + // Normal 16 bit textures + Self::R16Uint => (native, uint, linear, (1, 1), 2, attachment), + Self::R16Sint => (native, sint, linear, (1, 1), 2, attachment), + Self::R16Float => (native, float, linear, (1, 1), 2, attachment), + Self::Rg8Unorm => (native, float, linear, (1, 1), 2, attachment), + Self::Rg8Snorm => (native, float, linear, (1, 1), 2, attachment), + Self::Rg8Uint => (native, uint, linear, (1, 1), 2, attachment), + Self::Rg8Sint => (native, sint, linear, (1, 1), 2, basic), + + // Normal 32 bit textures + Self::R32Uint => (native, uint, linear, (1, 1), 4, all_flags), + Self::R32Sint => (native, sint, linear, (1, 1), 4, all_flags), + Self::R32Float => (native, nearest, linear, (1, 1), 4, all_flags), + Self::Rg16Uint => (native, uint, linear, (1, 1), 4, attachment), + Self::Rg16Sint => (native, sint, linear, (1, 1), 4, attachment), + Self::Rg16Float => (native, float, linear, (1, 1), 4, attachment), + Self::Rgba8Unorm => (native, float, linear, (1, 1), 4, all_flags), + Self::Rgba8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment), + Self::Rgba8Snorm => (native, float, linear, (1, 1), 4, storage), + Self::Rgba8Uint => (native, uint, linear, (1, 1), 4, all_flags), + Self::Rgba8Sint => (native, sint, linear, (1, 1), 4, all_flags), + Self::Bgra8Unorm => (native, float, linear, (1, 1), 4, attachment), + Self::Bgra8UnormSrgb => (native, float, srgb, (1, 1), 4, attachment), + + // Packed 32 bit textures + Self::Rgb10a2Unorm => (native, float, linear, (1, 1), 4, attachment), + Self::Rg11b10Float => (native, float, linear, (1, 1), 4, basic), + + // Packed 32 bit textures + Self::Rg32Uint => (native, uint, linear, (1, 1), 8, all_flags), + Self::Rg32Sint => (native, sint, linear, (1, 1), 8, all_flags), + Self::Rg32Float => (native, nearest, linear, (1, 1), 8, all_flags), + Self::Rgba16Uint => (native, uint, linear, (1, 1), 8, all_flags), + Self::Rgba16Sint => (native, sint, linear, (1, 1), 8, all_flags), + Self::Rgba16Float => (native, float, linear, (1, 1), 8, all_flags), + + // Packed 32 bit textures + Self::Rgba32Uint => (native, uint, linear, (1, 1), 16, all_flags), + Self::Rgba32Sint => (native, sint, linear, (1, 1), 16, all_flags), + Self::Rgba32Float => (native, nearest, linear, (1, 1), 16, all_flags), + + // Depth-stencil textures + Self::Depth32Float => (native, depth, linear, (1, 1), 4, attachment), + Self::Depth24Plus => (native, depth, linear, (1, 1), 4, attachment), + Self::Depth24PlusStencil8 => (native, depth, linear, (1, 1), 4, attachment), + + // BCn compressed textures + Self::Bc1RgbaUnorm => (bc, float, linear, (4, 4), 8, basic), + Self::Bc1RgbaUnormSrgb => (bc, float, srgb, (4, 4), 8, basic), + Self::Bc2RgbaUnorm => (bc, float, linear, (4, 4), 16, basic), + Self::Bc2RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic), + Self::Bc3RgbaUnorm => (bc, float, linear, (4, 4), 16, basic), + Self::Bc3RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic), + Self::Bc4RUnorm => (bc, float, linear, (4, 4), 8, basic), + Self::Bc4RSnorm => (bc, float, linear, (4, 4), 8, basic), + Self::Bc5RgUnorm => (bc, float, linear, (4, 4), 16, basic), + Self::Bc5RgSnorm => (bc, float, linear, (4, 4), 16, basic), + Self::Bc6hRgbUfloat => (bc, float, linear, (4, 4), 16, basic), + Self::Bc6hRgbSfloat => (bc, float, linear, (4, 4), 16, basic), + Self::Bc7RgbaUnorm => (bc, float, linear, (4, 4), 16, basic), + Self::Bc7RgbaUnormSrgb => (bc, float, srgb, (4, 4), 16, basic), + + // ETC compressed textures + Self::Etc2RgbUnorm => (etc2, float, linear, (4, 4), 8, basic), + Self::Etc2RgbUnormSrgb => (etc2, float, srgb, (4, 4), 8, basic), + Self::Etc2RgbA1Unorm => (etc2, float, linear, (4, 4), 8, basic), + Self::Etc2RgbA1UnormSrgb => (etc2, float, srgb, (4, 4), 8, basic), + Self::Etc2RgbA8Unorm => (etc2, float, linear, (4, 4), 16, basic), + Self::Etc2RgbA8UnormSrgb => (etc2, float, srgb, (4, 4), 16, basic), + Self::EacRUnorm => (etc2, float, linear, (4, 4), 8, basic), + Self::EacRSnorm => (etc2, float, linear, (4, 4), 8, basic), + Self::EtcRgUnorm => (etc2, float, linear, (4, 4), 16, basic), + Self::EtcRgSnorm => (etc2, float, linear, (4, 4), 16, basic), + + // ASTC compressed textures + Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, (4, 4), 16, basic), + Self::Astc4x4RgbaUnormSrgb => (astc_ldr, float, srgb, (4, 4), 16, basic), + Self::Astc5x4RgbaUnorm => (astc_ldr, float, linear, (5, 4), 16, basic), + Self::Astc5x4RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 4), 16, basic), + Self::Astc5x5RgbaUnorm => (astc_ldr, float, linear, (5, 5), 16, basic), + Self::Astc5x5RgbaUnormSrgb => (astc_ldr, float, srgb, (5, 5), 16, basic), + Self::Astc6x5RgbaUnorm => (astc_ldr, float, linear, (6, 5), 16, basic), + Self::Astc6x5RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 5), 16, basic), + Self::Astc6x6RgbaUnorm => (astc_ldr, float, linear, (6, 6), 16, basic), + Self::Astc6x6RgbaUnormSrgb => (astc_ldr, float, srgb, (6, 6), 16, basic), + Self::Astc8x5RgbaUnorm => (astc_ldr, float, linear, (8, 5), 16, basic), + Self::Astc8x5RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 5), 16, basic), + Self::Astc8x6RgbaUnorm => (astc_ldr, float, linear, (8, 6), 16, basic), + Self::Astc8x6RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 6), 16, basic), + Self::Astc10x5RgbaUnorm => (astc_ldr, float, linear, (10, 5), 16, basic), + Self::Astc10x5RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 5), 16, basic), + Self::Astc10x6RgbaUnorm => (astc_ldr, float, linear, (10, 6), 16, basic), + Self::Astc10x6RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 6), 16, basic), + Self::Astc8x8RgbaUnorm => (astc_ldr, float, linear, (8, 8), 16, basic), + Self::Astc8x8RgbaUnormSrgb => (astc_ldr, float, srgb, (8, 8), 16, basic), + Self::Astc10x8RgbaUnorm => (astc_ldr, float, linear, (10, 8), 16, basic), + Self::Astc10x8RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 8), 16, basic), + Self::Astc10x10RgbaUnorm => (astc_ldr, float, linear, (10, 10), 16, basic), + Self::Astc10x10RgbaUnormSrgb => (astc_ldr, float, srgb, (10, 10), 16, basic), + Self::Astc12x10RgbaUnorm => (astc_ldr, float, linear, (12, 10), 16, basic), + Self::Astc12x10RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 10), 16, basic), + Self::Astc12x12RgbaUnorm => (astc_ldr, float, linear, (12, 12), 16, basic), + Self::Astc12x12RgbaUnormSrgb => (astc_ldr, float, srgb, (12, 12), 16, basic), + }; TextureFormatInfo { - features, + required_features, sample_type, block_dimensions, block_size, srgb, - allowed_usages, + guaranteed_format_features: TextureFormatFeatures { + allowed_usages, + flags: TextureFormatFeatureFlags::empty(), + }, } } } @@ -2303,13 +2349,21 @@ pub enum StorageTextureAccess { /// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage; /// ``` ReadOnly, - /// The texture can only be read in the shader and it must be annotated with `writeonly`. + /// The texture can only be written in the shader and it must be annotated with `writeonly`. /// /// Example GLSL syntax: /// ```cpp,ignore /// layout(set=0, binding=0, r32f) writeonly uniform image2D myStorageImage; /// ``` WriteOnly, + /// The texture can be both read and written in the shader. + /// [`Features::STORAGE_TEXTURE_ACCESS_READ_WRITE`] must be enabled to use this access mode. + /// + /// Example GLSL syntax: + /// ```cpp,ignore + /// layout(set=0, binding=0, r32f) uniform image2D myStorageImage; + /// ``` + ReadWrite, } /// Specific type of a binding.