Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add view_formats in TextureDescriptor #3237

Merged
merged 20 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non

`wgpu`'s DX12 backend can now suballocate buffers and textures when the `windows_rs` feature is enabled, which can give a significant increase in performance (in testing I've seen a 10000%+ improvement in a simple scene with 200 `write_buffer` calls per frame, and a 40%+ improvement in [Bistro using Bevy](https://github.com/vleue/bevy_bistro_playground)). Previously `wgpu-hal`'s DX12 backend created a new heap on the GPU every time you called write_buffer (by calling `CreateCommittedResource`), whereas now with the `windows_rs` feature enabled it uses [`gpu_allocator`](https://crates.io/crates/gpu-allocator) to manage GPU memory (and calls `CreatePlacedResource` with a suballocated heap). By @Elabajaba in [#3163](https://github.com/gfx-rs/wgpu/pull/3163)

#### Texture Format Reinterpretation

The `view_formats` field is used to specify formats that are compatible with the texture format to allow the creation of views with different formats, currently, only changing srgb-ness is allowed.

```diff
let texture = device.create_texture(&wgpu::TextureDescriptor {
// ...
format: TextureFormat::Rgba8UnormSrgb,
+ view_formats: &[TextureFormat::Rgba8Unorm],
});
```

### Changes

#### General
Expand All @@ -125,6 +137,7 @@ Additionally `Surface::get_default_config` now returns an Option and returns Non
- Make `ObjectId` structure and invariants idiomatic. By @teoxoy in [#3347](https://github.com/gfx-rs/wgpu/pull/3347)
- Add validation in accordance with WebGPU `GPUSamplerDescriptor` valid usage for `lodMinClamp` and `lodMaxClamp`. By @James2022-rgb in [#3353](https://github.com/gfx-rs/wgpu/pull/3353)
- Remove panics in `Deref` implementations for `QueueWriteBufferView` and `BufferViewMut`. Instead, warnings are logged, since reading from these types is not recommended. By @botahamec in [#3336]
- Implement `view_formats` in TextureDescriptor to match the WebGPU spec. By @jinleili in [#3237](https://github.com/gfx-rs/wgpu/pull/3237)

#### WebGPU

Expand Down
9 changes: 9 additions & 0 deletions deno_webgpu/src/02_idl_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,15 @@
converter: webidl.converters["GPUTextureUsageFlags"],
required: true,
},
{
key: "viewFormats",
converter: webidl.createSequenceConverter(
webidl.converters["GPUTextureFormat"],
),
get defaultValue() {
return [];
},
},
];
webidl.converters["GPUTextureDescriptor"] = webidl.createDictionaryConverter(
"GPUTextureDescriptor",
Expand Down
2 changes: 2 additions & 0 deletions deno_webgpu/src/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub struct CreateTextureArgs {
dimension: wgpu_types::TextureDimension,
format: wgpu_types::TextureFormat,
usage: u32,
view_formats: Vec<wgpu_types::TextureFormat>,
}

#[op]
Expand All @@ -55,6 +56,7 @@ pub fn op_webgpu_create_texture(
dimension: args.dimension,
format: args.format,
usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage),
view_formats: args.view_formats,
};

gfx_put!(device => instance.device_create_texture(
Expand Down
1 change: 1 addition & 0 deletions deno_webgpu/webgpu.idl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
GPUTextureDimension dimension = "2d";
required GPUTextureFormat format;
required GPUTextureUsageFlags usage;
sequence<GPUTextureFormat> viewFormats = [];
};

enum GPUTextureDimension {
Expand Down
1 change: 1 addition & 0 deletions player/tests/data/clear-buffer-texture.ron
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
dimension: r#2d,
format: "rgba8unorm",
usage: 27,
view_formats: [],
)),
// First fill the texture to ensure it wasn't just zero initialized or "happened" to be zero.
WriteTexture(
Expand Down
1 change: 1 addition & 0 deletions player/tests/data/quad.ron
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
dimension: r#2d,
format: "rgba8unorm",
usage: 27,
view_formats: [],
)),
CreateTextureView(
id: Id(0, 1, Empty),
Expand Down
2 changes: 2 additions & 0 deletions player/tests/data/zero-init-texture-binding.ron
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
dimension: r#2d,
format: "rgba8unorm",
usage: 5, // SAMPLED + COPY_SRC
view_formats: [],
)),
CreateTextureView(
id: Id(0, 1, Empty),
Expand All @@ -54,6 +55,7 @@
dimension: r#2d,
format: "rgba8unorm",
usage: 9, // STORAGE + COPY_SRC
view_formats: [],
)),
CreateTextureView(
id: Id(1, 1, Empty),
Expand Down
1 change: 1 addition & 0 deletions player/tests/data/zero-init-texture-copytobuffer.ron
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
dimension: r#2d,
format: "rgba8unorm",
usage: 1, // COPY_SRC
view_formats: [],
)),
CreateBuffer(
Id(0, 1, Empty),
Expand Down
1 change: 1 addition & 0 deletions player/tests/data/zero-init-texture-rendertarget.ron
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
dimension: r#2d,
format: "rgba8unorm",
usage: 17, // RENDER_ATTACHMENT + COPY_SRC
view_formats: [],
)),
CreateTextureView(
id: Id(0, 1, Empty),
Expand Down
2 changes: 1 addition & 1 deletion wgpu-core/src/command/clear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ pub(crate) fn clear_texture<A: HalApi>(
}

fn clear_texture_via_buffer_copies<A: hal::Api>(
texture_desc: &wgt::TextureDescriptor<()>,
texture_desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
alignments: &hal::Alignments,
zero_buffer: &A::Buffer, // Buffer of size device::ZERO_BUFFER_SIZE
range: TextureInitRange,
Expand Down
2 changes: 1 addition & 1 deletion wgpu-core/src/command/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ pub(crate) fn validate_linear_texture_data(
/// [vtcr]: https://gpuweb.github.io/gpuweb/#valid-texture-copy-range
pub(crate) fn validate_texture_copy_range(
texture_copy_view: &ImageCopyTexture,
desc: &wgt::TextureDescriptor<()>,
desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
texture_side: CopySide,
copy_size: &Extent3d,
) -> Result<(hal::CopyExtent, u32), TransferError> {
Expand Down
20 changes: 15 additions & 5 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,14 @@ impl<A: HalApi> Device<A> {
));
}

// TODO: validate missing TextureDescriptor::view_formats.
for format in desc.view_formats.iter() {
if desc.format == *format {
continue;
}
if desc.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
return Err(CreateTextureError::InvalidViewFormat(*format, desc.format));
}
}

// Enforce having COPY_DST/DEPTH_STENCIL_WRIT/COLOR_TARGET otherwise we
// wouldn't be able to initialize the texture.
Expand Down Expand Up @@ -1086,10 +1093,13 @@ impl<A: HalApi> Device<A> {
}
let format = desc.format.unwrap_or(texture.desc.format);
if format != texture.desc.format {
return Err(resource::CreateTextureViewError::FormatReinterpretation {
texture: texture.desc.format,
view: format,
});
if !texture.desc.view_formats.contains(&format) {
return Err(resource::CreateTextureViewError::FormatReinterpretation {
texture: texture.desc.format,
view: format,
});
}
self.require_downlevel_flags(wgt::DownlevelFlags::VIEW_FORMATS)?;
}

// filter the usages based on the other criteria
Expand Down
2 changes: 1 addition & 1 deletion wgpu-core/src/init_tracker/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) struct TextureInitRange {
pub(crate) fn has_copy_partial_init_tracker_coverage(
copy_size: &wgt::Extent3d,
mip_level: u32,
desc: &wgt::TextureDescriptor<()>,
desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
) -> bool {
let target_size = desc.mip_level_size(mip_level).unwrap();
copy_size.width != target_size.width
Expand Down
1 change: 1 addition & 0 deletions wgpu-core/src/present.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
format: config.format,
dimension: wgt::TextureDimension::D2,
usage: config.usage,
view_formats: vec![],
},
hal_usage: conv::map_texture_usage(config.usage, config.format.into()),
format_features: wgt::TextureFormatFeatures {
Expand Down
8 changes: 6 additions & 2 deletions wgpu-core/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ impl<A: hal::Api> Resource for StagingBuffer<A> {
}
}

pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>>;
pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, Vec<wgt::TextureFormat>>;

#[derive(Debug)]
pub(crate) enum TextureInner<A: hal::Api> {
Expand Down Expand Up @@ -338,7 +338,7 @@ pub enum TextureClearMode<A: hal::Api> {
pub struct Texture<A: hal::Api> {
pub(crate) inner: TextureInner<A>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: wgt::TextureDescriptor<()>,
pub(crate) desc: wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
pub(crate) hal_usage: hal::TextureUses,
pub(crate) format_features: wgt::TextureFormatFeatures,
pub(crate) initialization_status: TextureInitTracker,
Expand Down Expand Up @@ -507,6 +507,8 @@ pub enum CreateTextureError {
if *.2 { " due to downlevel restrictions" } else { "" }
)]
InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat, bool),
#[error("The view format {0:?} is not compatible with texture format {1:?}, only changing srgb-ness is allowed.")]
InvalidViewFormat(wgt::TextureFormat, 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")]
Expand Down Expand Up @@ -626,6 +628,8 @@ pub enum CreateTextureViewError {
texture: wgt::TextureFormat,
view: wgt::TextureFormat,
},
#[error(transparent)]
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
}

#[derive(Clone, Debug, Error)]
Expand Down
68 changes: 61 additions & 7 deletions wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,11 @@ bitflags::bitflags! {
///
/// Corresponds to Vulkan's `VkPhysicalDeviceFeatures.depthBiasClamp`
const DEPTH_BIAS_CLAMP = 1 << 18;

/// Supports specifying which view format values are allowed when create_view() is called on a texture.
///
/// The WebGL and GLES backends doesn't support this.
const VIEW_FORMATS = 1 << 19;
}
}

Expand Down Expand Up @@ -2537,6 +2542,29 @@ impl TextureFormat {
},
}
}

/// Strips the `Srgb` suffix from the given texture format.
pub fn remove_srgb_suffix(&self) -> TextureFormat {
match *self {
Self::Rgba8UnormSrgb => Self::Rgba8Unorm,
Self::Bgra8UnormSrgb => Self::Bgra8Unorm,
Self::Bc1RgbaUnormSrgb => Self::Bc1RgbaUnorm,
Self::Bc2RgbaUnormSrgb => Self::Bc2RgbaUnorm,
Self::Bc3RgbaUnormSrgb => Self::Bc3RgbaUnorm,
Self::Bc7RgbaUnormSrgb => Self::Bc7RgbaUnorm,
Self::Etc2Rgb8UnormSrgb => Self::Etc2Rgb8Unorm,
Self::Etc2Rgb8A1UnormSrgb => Self::Etc2Rgb8A1Unorm,
Self::Etc2Rgba8UnormSrgb => Self::Etc2Rgba8Unorm,
Self::Astc {
block,
channel: AstcChannel::UnormSrgb,
} => Self::Astc {
block,
channel: AstcChannel::Unorm,
},
_ => *self,
}
}
}

#[test]
Expand Down Expand Up @@ -4319,7 +4347,7 @@ fn test_max_mips() {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TextureDescriptor<L> {
pub struct TextureDescriptor<L, V> {
/// Debug label of the texture. This will show up in graphics debuggers for easy identification.
pub label: L,
/// Size of the texture. All components must be greater than zero. For a
Expand All @@ -4336,12 +4364,17 @@ 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
/// Specifies what view formats will be allowed when calling create_view() on this texture.
///
/// View formats of the same format as the texture are always allowed.
///
/// Note: currently, only the srgb-ness is allowed to change. (ex: Rgba8Unorm texture + Rgba8UnormSrgb view)
pub view_formats: V,
}

impl<L> TextureDescriptor<L> {
impl<L, V: Clone> TextureDescriptor<L, V> {
/// Takes a closure and maps the label of the texture descriptor into another.
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> TextureDescriptor<K> {
pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> TextureDescriptor<K, V> {
TextureDescriptor {
label: fun(&self.label),
size: self.size,
Expand All @@ -4350,6 +4383,25 @@ impl<L> TextureDescriptor<L> {
dimension: self.dimension,
format: self.format,
usage: self.usage,
view_formats: self.view_formats.clone(),
}
}

/// Maps the label and view_formats of the texture descriptor into another.
pub fn map_label_and_view_formats<K, M>(
&self,
l_fun: impl FnOnce(&L) -> K,
v_fun: impl FnOnce(V) -> M,
) -> TextureDescriptor<K, M> {
TextureDescriptor {
label: l_fun(&self.label),
size: self.size,
mip_level_count: self.mip_level_count,
sample_count: self.sample_count,
dimension: self.dimension,
format: self.format,
usage: self.usage,
view_formats: v_fun(self.view_formats.clone()),
}
}

Expand All @@ -4362,14 +4414,16 @@ impl<L> TextureDescriptor<L> {
///
/// ```rust
/// # use wgpu_types as wgpu;
/// let desc = wgpu::TextureDescriptor {
/// # type TextureDescriptor<'a> = wgpu::TextureDescriptor<(), &'a [wgpu::TextureFormat]>;
/// let desc = TextureDescriptor {
/// label: (),
/// size: wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 },
/// mip_level_count: 7,
/// sample_count: 1,
/// dimension: wgpu::TextureDimension::D3,
/// format: wgpu::TextureFormat::Rgba8Sint,
/// usage: wgpu::TextureUsages::empty(),
/// view_formats: &[],
/// };
///
/// assert_eq!(desc.mip_level_size(0), Some(wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 }));
Expand Down Expand Up @@ -5087,15 +5141,15 @@ impl ImageSubresourceRange {
}

/// Returns the mip level range of a subresource range describes for a specific texture.
pub fn mip_range<L>(&self, texture_desc: &TextureDescriptor<L>) -> Range<u32> {
pub fn mip_range<L, V>(&self, texture_desc: &TextureDescriptor<L, V>) -> Range<u32> {
self.base_mip_level..match self.mip_level_count {
Some(mip_level_count) => self.base_mip_level + mip_level_count.get(),
None => texture_desc.mip_level_count,
}
}

/// Returns the layer range of a subresource range describes for a specific texture.
pub fn layer_range<L>(&self, texture_desc: &TextureDescriptor<L>) -> Range<u32> {
pub fn layer_range<L, V>(&self, texture_desc: &TextureDescriptor<L, V>) -> Range<u32> {
self.base_array_layer..match self.array_layer_count {
Some(array_layer_count) => self.base_array_layer + array_layer_count.get(),
None => {
Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/bunnymark/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ impl framework::Example for Example {
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
queue.write_texture(
texture.as_image_copy(),
Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/capture/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ async fn create_red_image_with_dimensions(
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
label: None,
view_formats: &[],
});

// Set the background to be red
Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/conservative-raster/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl Example {
format: RENDER_TARGET_FORMAT,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
})
.create_view(&Default::default());

Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/cube/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ impl framework::Example for Example {
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Uint,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
queue.write_texture(
Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ pub fn test<E: Example>(mut params: FrameworkRefTest) {
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});

let dst_view = dst_texture.create_view(&wgpu::TextureViewDescriptor::default());
Expand Down
Loading