mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Add view_formats in TextureDescriptor (#3237)
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com> Co-authored-by: crowlkats <crowlkats@toaxl.com> Closes https://github.com/gfx-rs/wgpu/issues/3030
This commit is contained in:
parent
fae740df5c
commit
0849e78600
13
CHANGELOG.md
13
CHANGELOG.md
@ -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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -424,6 +424,15 @@
|
||||
converter: webidl.converters["GPUTextureUsageFlags"],
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
key: "viewFormats",
|
||||
converter: webidl.createSequenceConverter(
|
||||
webidl.converters["GPUTextureFormat"],
|
||||
),
|
||||
get defaultValue() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
];
|
||||
webidl.converters["GPUTextureDescriptor"] = webidl.createDictionaryConverter(
|
||||
"GPUTextureDescriptor",
|
||||
|
||||
@ -34,6 +34,7 @@ pub struct CreateTextureArgs {
|
||||
dimension: wgpu_types::TextureDimension,
|
||||
format: wgpu_types::TextureFormat,
|
||||
usage: u32,
|
||||
view_formats: Vec<wgpu_types::TextureFormat>,
|
||||
}
|
||||
|
||||
#[op]
|
||||
@ -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(
|
||||
|
||||
@ -201,6 +201,7 @@ dictionary GPUTextureDescriptor : GPUObjectDescriptorBase {
|
||||
GPUTextureDimension dimension = "2d";
|
||||
required GPUTextureFormat format;
|
||||
required GPUTextureUsageFlags usage;
|
||||
sequence<GPUTextureFormat> viewFormats = [];
|
||||
};
|
||||
|
||||
enum GPUTextureDimension {
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
dimension: r#2d,
|
||||
format: "rgba8unorm",
|
||||
usage: 27,
|
||||
view_formats: [],
|
||||
)),
|
||||
CreateTextureView(
|
||||
id: Id(0, 1, Empty),
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
dimension: r#2d,
|
||||
format: "rgba8unorm",
|
||||
usage: 5, // SAMPLED + COPY_SRC
|
||||
view_formats: [],
|
||||
)),
|
||||
CreateTextureView(
|
||||
id: Id(0, 1, Empty),
|
||||
@ -54,6 +55,7 @@
|
||||
dimension: r#2d,
|
||||
format: "rgba8unorm",
|
||||
usage: 9, // STORAGE + COPY_SRC
|
||||
view_formats: [],
|
||||
)),
|
||||
CreateTextureView(
|
||||
id: Id(1, 1, Empty),
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
dimension: r#2d,
|
||||
format: "rgba8unorm",
|
||||
usage: 1, // COPY_SRC
|
||||
view_formats: [],
|
||||
)),
|
||||
CreateBuffer(
|
||||
Id(0, 1, Empty),
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
dimension: r#2d,
|
||||
format: "rgba8unorm",
|
||||
usage: 17, // RENDER_ATTACHMENT + COPY_SRC
|
||||
view_formats: [],
|
||||
)),
|
||||
CreateTextureView(
|
||||
id: Id(0, 1, Empty),
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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> {
|
||||
|
||||
@ -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.
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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> {
|
||||
@ -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,
|
||||
@ -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")]
|
||||
@ -626,6 +628,8 @@ pub enum CreateTextureViewError {
|
||||
texture: wgt::TextureFormat,
|
||||
view: wgt::TextureFormat,
|
||||
},
|
||||
#[error(transparent)]
|
||||
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
|
||||
@ -1142,6 +1142,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2540,6 +2545,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]
|
||||
@ -4322,7 +4350,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
|
||||
@ -4339,12 +4367,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,
|
||||
@ -4353,6 +4386,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()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -4365,7 +4417,8 @@ 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,
|
||||
@ -4373,6 +4426,7 @@ impl<L> TextureDescriptor<L> {
|
||||
/// 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 }));
|
||||
@ -5090,7 +5144,7 @@ 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,
|
||||
@ -5098,7 +5152,7 @@ impl ImageSubresourceRange {
|
||||
}
|
||||
|
||||
/// 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 => {
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -232,6 +232,7 @@ impl framework::Example for Example {
|
||||
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
| wgpu::TextureUsages::COPY_DST,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
});
|
||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
//Note: we could use queue.write_texture instead, and this is what other
|
||||
|
||||
@ -109,6 +109,7 @@ impl Example {
|
||||
format: config.format,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
};
|
||||
|
||||
device
|
||||
|
||||
@ -197,6 +197,7 @@ impl Example {
|
||||
format: Self::DEPTH_FORMAT,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
|
||||
@ -385,6 +386,7 @@ impl framework::Example for Example {
|
||||
format: Self::SHADOW_FORMAT,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
});
|
||||
let shadow_view = shadow_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
|
||||
@ -85,6 +85,7 @@ impl Skybox {
|
||||
format: Self::DEPTH_FORMAT,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
|
||||
@ -328,6 +329,7 @@ impl framework::Example for Skybox {
|
||||
format: skybox_format,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
},
|
||||
&image.data,
|
||||
);
|
||||
|
||||
@ -153,6 +153,7 @@ impl framework::Example for Triangles {
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Stencil8,
|
||||
view_formats: &[],
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
});
|
||||
|
||||
|
||||
@ -164,21 +164,26 @@ impl framework::Example for Example {
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
};
|
||||
let red_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("red"),
|
||||
view_formats: &[],
|
||||
..texture_descriptor
|
||||
});
|
||||
let green_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("green"),
|
||||
view_formats: &[],
|
||||
..texture_descriptor
|
||||
});
|
||||
let blue_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("blue"),
|
||||
view_formats: &[],
|
||||
..texture_descriptor
|
||||
});
|
||||
let white_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("white"),
|
||||
view_formats: &[],
|
||||
..texture_descriptor
|
||||
});
|
||||
|
||||
|
||||
@ -197,6 +197,7 @@ impl Example {
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||
| wgpu::TextureUsages::COPY_DST
|
||||
| wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let draw_depth_buffer = device.create_texture(&wgpu::TextureDescriptor {
|
||||
@ -209,6 +210,7 @@ impl Example {
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING
|
||||
| wgpu::TextureUsages::COPY_DST
|
||||
| wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let color_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
|
||||
@ -135,15 +135,10 @@ impl Context {
|
||||
device: &Device,
|
||||
desc: &TextureDescriptor,
|
||||
) -> Texture {
|
||||
let descriptor = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec());
|
||||
let global = &self.0;
|
||||
let (id, error) = unsafe {
|
||||
global.create_texture_from_hal::<A>(
|
||||
hal_texture,
|
||||
device.id,
|
||||
&desc.map_label(|l| l.map(Borrowed)),
|
||||
(),
|
||||
)
|
||||
};
|
||||
let (id, error) =
|
||||
unsafe { global.create_texture_from_hal::<A>(hal_texture, device.id, &descriptor, ()) };
|
||||
if let Some(cause) = error {
|
||||
self.handle_error(
|
||||
&device.error_sink,
|
||||
@ -1249,10 +1244,11 @@ impl crate::Context for Context {
|
||||
device_data: &Self::DeviceData,
|
||||
desc: &TextureDescriptor,
|
||||
) -> (Self::TextureId, Self::TextureData) {
|
||||
let wgt_desc = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec());
|
||||
let global = &self.0;
|
||||
let (id, error) = wgc::gfx_select!(device => global.device_create_texture(
|
||||
*device,
|
||||
&desc.map_label(|l| l.map(Borrowed)),
|
||||
&wgt_desc,
|
||||
()
|
||||
));
|
||||
if let Some(cause) = error {
|
||||
|
||||
@ -1583,6 +1583,12 @@ impl crate::context::Context for Context {
|
||||
mapped_desc.dimension(map_texture_dimension(desc.dimension));
|
||||
mapped_desc.mip_level_count(desc.mip_level_count);
|
||||
mapped_desc.sample_count(desc.sample_count);
|
||||
let mapped_view_formats = desc
|
||||
.view_formats
|
||||
.iter()
|
||||
.map(|format| JsValue::from(map_texture_format(*format)))
|
||||
.collect::<js_sys::Array>();
|
||||
mapped_desc.view_formats(&mapped_view_formats);
|
||||
(create_identified(device.0.create_texture(&mapped_desc)), ())
|
||||
}
|
||||
|
||||
|
||||
@ -896,7 +896,7 @@ static_assertions::assert_impl_all!(RenderBundleDescriptor: Send, Sync);
|
||||
///
|
||||
/// Corresponds to [WebGPU `GPUTextureDescriptor`](
|
||||
/// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedescriptor).
|
||||
pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>>;
|
||||
pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, &'a [TextureFormat]>;
|
||||
static_assertions::assert_impl_all!(TextureDescriptor: Send, Sync);
|
||||
/// Describes a [`QuerySet`].
|
||||
///
|
||||
@ -2054,6 +2054,7 @@ impl Device {
|
||||
owned: true,
|
||||
descriptor: TextureDescriptor {
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
..desc.clone()
|
||||
},
|
||||
}
|
||||
@ -2090,6 +2091,7 @@ impl Device {
|
||||
owned: true,
|
||||
descriptor: TextureDescriptor {
|
||||
label: None,
|
||||
view_formats: &[],
|
||||
..desc.clone()
|
||||
},
|
||||
}
|
||||
@ -4095,6 +4097,7 @@ impl Surface {
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: TextureDimension::D2,
|
||||
view_formats: &[],
|
||||
};
|
||||
|
||||
texture_id
|
||||
|
||||
@ -225,6 +225,7 @@ fn single_texture_clear_test(
|
||||
// Forces internally the required usages to be able to clear it.
|
||||
// This is not visible on the API level.
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
});
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
|
||||
@ -64,7 +64,7 @@ fn write_png(
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_difference(lhs: u8, rhs: u8) -> u8 {
|
||||
pub fn calc_difference(lhs: u8, rhs: u8) -> u8 {
|
||||
(lhs as i16 - rhs as i16).unsigned_abs() as u8
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ fn queue_write_texture_overflow() {
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba32Float,
|
||||
usage: wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let data = vec![255; 128];
|
||||
|
||||
@ -44,6 +44,7 @@ fn bad_texture() {
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::all(),
|
||||
view_formats: &[],
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ mod resource_descriptor_accessor;
|
||||
mod resource_error;
|
||||
mod shader;
|
||||
mod shader_primitive_index;
|
||||
mod shader_view_format;
|
||||
mod texture_bounds;
|
||||
mod transfer;
|
||||
mod vertex_indices;
|
||||
|
||||
@ -165,6 +165,7 @@ fn pulling_common(
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let color_view = color_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
|
||||
208
wgpu/tests/shader_view_format/mod.rs
Normal file
208
wgpu/tests/shader_view_format/mod.rs
Normal file
@ -0,0 +1,208 @@
|
||||
use crate::common::{image::calc_difference, initialize_test, TestParameters, TestingContext};
|
||||
use std::num::NonZeroU32;
|
||||
use wgpu::{util::DeviceExt, DownlevelFlags, Limits, TextureFormat};
|
||||
|
||||
#[test]
|
||||
fn reinterpret_srgb_ness() {
|
||||
let parameters = TestParameters::default()
|
||||
.downlevel_flags(DownlevelFlags::VIEW_FORMATS)
|
||||
.limits(Limits::downlevel_defaults())
|
||||
.specific_failure(Some(wgpu::Backends::GL), None, None, true);
|
||||
initialize_test(parameters, |ctx| {
|
||||
let unorm_data: [[u8; 4]; 4] = [
|
||||
[180, 0, 0, 255],
|
||||
[0, 84, 0, 127],
|
||||
[0, 0, 62, 100],
|
||||
[62, 180, 84, 90],
|
||||
];
|
||||
let srgb_data: [[u8; 4]; 4] = [
|
||||
[116, 0, 0, 255],
|
||||
[0, 23, 0, 127],
|
||||
[0, 0, 12, 100],
|
||||
[12, 116, 23, 90],
|
||||
];
|
||||
|
||||
let size = wgpu::Extent3d {
|
||||
width: 2,
|
||||
height: 2,
|
||||
depth_or_array_layers: 1,
|
||||
};
|
||||
|
||||
let shader = ctx
|
||||
.device
|
||||
.create_shader_module(wgpu::include_wgsl!("view_format.wgsl"));
|
||||
|
||||
// Reinterpret Rgba8Unorm as Rgba8UnormSrgb
|
||||
reinterpret(
|
||||
&ctx,
|
||||
&shader,
|
||||
size,
|
||||
TextureFormat::Rgba8Unorm,
|
||||
TextureFormat::Rgba8UnormSrgb,
|
||||
&unorm_data,
|
||||
&srgb_data,
|
||||
);
|
||||
|
||||
// Reinterpret Rgba8UnormSrgb back to Rgba8Unorm
|
||||
reinterpret(
|
||||
&ctx,
|
||||
&shader,
|
||||
size,
|
||||
TextureFormat::Rgba8UnormSrgb,
|
||||
TextureFormat::Rgba8Unorm,
|
||||
&srgb_data,
|
||||
&unorm_data,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn reinterpret(
|
||||
ctx: &TestingContext,
|
||||
shader: &wgpu::ShaderModule,
|
||||
size: wgpu::Extent3d,
|
||||
src_format: wgpu::TextureFormat,
|
||||
reinterpret_to: wgpu::TextureFormat,
|
||||
src_data: &[[u8; 4]],
|
||||
expect_data: &[[u8; 4]],
|
||||
) {
|
||||
let tex = ctx.device.create_texture_with_data(
|
||||
&ctx.queue,
|
||||
&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
size,
|
||||
format: src_format,
|
||||
usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
view_formats: &[reinterpret_to],
|
||||
},
|
||||
bytemuck::cast_slice(src_data),
|
||||
);
|
||||
let tv = tex.create_view(&wgpu::TextureViewDescriptor {
|
||||
format: Some(reinterpret_to),
|
||||
..Default::default()
|
||||
});
|
||||
let pipeline = ctx
|
||||
.device
|
||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("reinterpret pipeline"),
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[Some(src_format.into())],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
front_face: wgpu::FrontFace::Cw,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
});
|
||||
let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&tv),
|
||||
}],
|
||||
label: None,
|
||||
});
|
||||
|
||||
let target_tex = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: src_format,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let target_view = target_tex.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
ops: wgpu::Operations::default(),
|
||||
resolve_target: None,
|
||||
view: &target_view,
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
label: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_bind_group(0, &bind_group, &[]);
|
||||
rpass.draw(0..3, 0..1);
|
||||
drop(rpass);
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
|
||||
let read_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as u64 * 2,
|
||||
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::ImageCopyTexture {
|
||||
texture: &target_tex,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
wgpu::ImageCopyBuffer {
|
||||
buffer: &read_buffer,
|
||||
layout: wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: NonZeroU32::new(wgpu::COPY_BYTES_PER_ROW_ALIGNMENT),
|
||||
rows_per_image: None,
|
||||
},
|
||||
},
|
||||
size,
|
||||
);
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
|
||||
let slice = read_buffer.slice(..);
|
||||
slice.map_async(wgpu::MapMode::Read, |_| ());
|
||||
ctx.device.poll(wgpu::Maintain::Wait);
|
||||
|
||||
let data: Vec<u8> = slice.get_mapped_range().to_vec();
|
||||
let tolerance_data: [[u8; 4]; 4] = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 1, 1, 0]];
|
||||
|
||||
for h in 0..size.height {
|
||||
let offset = h * wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
|
||||
for w in 0..size.width {
|
||||
let expect = expect_data[(h * size.width + w) as usize];
|
||||
let tolerance = tolerance_data[(h * size.width + w) as usize];
|
||||
let index = (w * 4 + offset) as usize;
|
||||
if calc_difference(expect[0], data[index]) > tolerance[0]
|
||||
|| calc_difference(expect[1], data[index + 1]) > tolerance[1]
|
||||
|| calc_difference(expect[2], data[index + 2]) > tolerance[2]
|
||||
|| calc_difference(expect[3], data[index + 3]) > tolerance[3]
|
||||
{
|
||||
panic!(
|
||||
"Reinterpret {:?} as {:?} mismatch! expect {:?} get [{}, {}, {}, {}]",
|
||||
src_format,
|
||||
reinterpret_to,
|
||||
expect,
|
||||
data[index],
|
||||
data[index + 1],
|
||||
data[index + 2],
|
||||
data[index + 3]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
wgpu/tests/shader_view_format/view_format.wgsl
Normal file
12
wgpu/tests/shader_view_format/view_format.wgsl
Normal file
@ -0,0 +1,12 @@
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> @builtin(position) vec4<f32> {
|
||||
let uv: vec2<f32> = vec2<f32>(f32((vertexIndex << 1u) & 2u), f32(vertexIndex & 2u));
|
||||
return vec4<f32>(uv * 2.0 - 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var tex: texture_2d<f32>;
|
||||
|
||||
@fragment
|
||||
fn fs_main(@builtin(position) coord: vec4<f32>) -> @location(0) vec4<f32> {
|
||||
return textureLoad(tex, vec2<i32>(coord.xy), 0);
|
||||
}
|
||||
@ -103,6 +103,7 @@ const TEXTURE_DESCRIPTOR: wgpu::TextureDescriptor = wgpu::TextureDescriptor {
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::COPY_DST.union(wgpu::TextureUsages::COPY_SRC),
|
||||
view_formats: &[],
|
||||
};
|
||||
|
||||
const BYTES_PER_PIXEL: u32 = 4;
|
||||
|
||||
@ -21,6 +21,7 @@ fn copy_overflow_z() {
|
||||
usage: wgpu::TextureUsages::COPY_DST,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
view_formats: &[],
|
||||
});
|
||||
let t2 = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
@ -34,6 +35,7 @@ fn copy_overflow_z() {
|
||||
usage: wgpu::TextureUsages::COPY_DST,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
fail(&ctx.device, || {
|
||||
|
||||
@ -97,6 +97,7 @@ fn pulling_common(
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
},
|
||||
&[0, 0, 0, 1],
|
||||
)
|
||||
|
||||
@ -25,6 +25,7 @@ fn write_texture_subset() {
|
||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
view_formats: &[],
|
||||
});
|
||||
let data = vec![1u8; size as usize * 2];
|
||||
// Write the first two rows
|
||||
|
||||
@ -208,6 +208,7 @@ fn create_white_texture_and_readback_buffer(
|
||||
| wgpu::TextureUsages::COPY_SRC
|
||||
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
},
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
// Clear using a write_texture operation. We could also clear using a render_pass clear.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user