Skip to content

Commit

Permalink
Implement view_formats for SurfaceConfiguration (#3409)
Browse files Browse the repository at this point in the history
Co-authored-by: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com>
Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
  • Loading branch information
3 people authored Jan 25, 2023
1 parent 5ded4ba commit 33f94c7
Show file tree
Hide file tree
Showing 20 changed files with 172 additions and 34 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ let texture = device.create_texture(&wgpu::TextureDescriptor {
});
```

```diff
let config = wgpu::SurfaceConfiguration {
// ...
format: TextureFormat::Rgba8Unorm,
+ view_formats: &[wgpu::TextureFormat::Rgba8UnormSrgb],
};
surface.configure(&device, &config);
```

### Changes

#### General
Expand All @@ -183,9 +192,10 @@ let texture = device.create_texture(&wgpu::TextureDescriptor {
- 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)
- Implement `view_formats` in the TextureDescriptor to match the WebGPU spec. By @jinleili in [#3237](https://github.com/gfx-rs/wgpu/pull/3237)
- Show more information in error message for non-aligned buffer bindings in WebGL [#3414](https://github.com/gfx-rs/wgpu/pull/3414)
- Update `TextureView` validation according to the WebGPU spec. By @teoxoy in [#3410](https://github.com/gfx-rs/wgpu/pull/3410)
- Implement `view_formats` in the SurfaceConfiguration to match the WebGPU spec. By @jinleili in [#3409](https://github.com/gfx-rs/wgpu/pull/3409)

#### WebGPU

Expand Down
9 changes: 9 additions & 0 deletions deno_webgpu/src/04_surface_idl_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@
converter: webidl.converters["long"],
required: true,
},
{
key: "viewFormats",
converter: webidl.createSequenceConverter(
webidl.converters["GPUTextureFormat"],
),
get defaultValue() {
return [];
},
},
];
webidl.converters["GPUCanvasConfiguration"] = webidl
.createDictionaryConverter(
Expand Down
4 changes: 3 additions & 1 deletion deno_webgpu/src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub struct SurfaceConfigureArgs {
height: u32,
present_mode: Option<wgpu_types::PresentMode>,
alpha_mode: wgpu_types::CompositeAlphaMode,
view_formats: Vec<wgpu_types::TextureFormat>,
}

#[op]
Expand All @@ -71,13 +72,14 @@ pub fn op_webgpu_surface_configure(
.get::<WebGpuSurface>(args.surface_rid)?;
let surface = surface_resource.0;

let conf = wgpu_types::SurfaceConfiguration {
let conf = wgpu_types::SurfaceConfiguration::<Vec<wgpu_types::TextureFormat>> {
usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage),
format: args.format,
width: args.width,
height: args.height,
present_mode: args.present_mode.unwrap_or_default(),
alpha_mode: args.alpha_mode,
view_formats: args.view_formats,
};

let err = gfx_select!(device => instance.surface_configure(surface, device, &conf));
Expand Down
1 change: 1 addition & 0 deletions deno_webgpu/webgpu.idl
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,7 @@ dictionary GPUCanvasConfiguration {
required GPUTextureFormat format;
GPUTextureUsageFlags usage = 0x10; // GPUTextureUsage.RENDER_ATTACHMENT
GPUCanvasAlphaMode alphaMode = "opaque";
sequence<GPUTextureFormat> viewFormats = [];
};

enum GPUDeviceLostReason {
Expand Down
30 changes: 28 additions & 2 deletions wgpu-core/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5186,7 +5186,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
&self,
surface_id: id::SurfaceId,
device_id: id::DeviceId,
config: &wgt::SurfaceConfiguration,
config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
) -> Option<present::ConfigureSurfaceError> {
use hal::{Adapter as _, Surface as _};
use present::ConfigureSurfaceError as E;
Expand Down Expand Up @@ -5309,7 +5309,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (adapter_guard, mut token) = hub.adapters.read(&mut token);
let (device_guard, _token) = hub.devices.read(&mut token);

let error = loop {
let error = 'outer: loop {
let device = match device_guard.get(device_id) {
Ok(device) => device,
Err(_) => break DeviceError::Invalid.into(),
Expand All @@ -5335,6 +5335,31 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
};

let mut hal_view_formats = vec![];
for format in config.view_formats.iter() {
if *format == config.format {
continue;
}
if !caps.formats.contains(&config.format) {
break 'outer E::UnsupportedFormat {
requested: config.format,
available: caps.formats.clone(),
};
}
if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
break 'outer E::InvalidViewFormat(*format, config.format);
}
hal_view_formats.push(*format);
}

if !hal_view_formats.is_empty() {
if let Err(missing_flag) =
device.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS)
{
break 'outer E::MissingDownlevelFlags(missing_flag);
}
}

let num_frames = present::DESIRED_NUM_FRAMES
.clamp(*caps.swap_chain_sizes.start(), *caps.swap_chain_sizes.end());
let mut hal_config = hal::SurfaceConfiguration {
Expand All @@ -5348,6 +5373,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth_or_array_layers: 1,
},
usage: conv::map_texture_usage(config.usage, hal::FormatAspects::COLOR),
view_formats: hal_view_formats,
};

if let Err(error) = validate_surface_configuration(&mut hal_config, &caps) {
Expand Down
5 changes: 4 additions & 1 deletion wgpu-core/src/device/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ pub enum Action<'a> {
desc: crate::device::DeviceDescriptor<'a>,
backend: wgt::Backend,
},
ConfigureSurface(id::SurfaceId, wgt::SurfaceConfiguration),
ConfigureSurface(
id::SurfaceId,
wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
),
CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>),
FreeBuffer(id::BufferId),
DestroyBuffer(id::BufferId),
Expand Down
10 changes: 7 additions & 3 deletions wgpu-core/src/present.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::borrow::Borrow;
use crate::device::trace::Action;
use crate::{
conv,
device::DeviceError,
device::{DeviceError, MissingDownlevelFlags},
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token},
id::{DeviceId, SurfaceId, TextureId, Valid},
init_tracker::TextureInitTracker,
Expand All @@ -32,7 +32,7 @@ pub const DESIRED_NUM_FRAMES: u32 = 3;
#[derive(Debug)]
pub(crate) struct Presentation {
pub(crate) device_id: Stored<DeviceId>,
pub(crate) config: wgt::SurfaceConfiguration,
pub(crate) config: wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
#[allow(unused)]
pub(crate) num_frames: u32,
pub(crate) acquired_texture: Option<Stored<TextureId>>,
Expand Down Expand Up @@ -64,6 +64,10 @@ pub enum ConfigureSurfaceError {
Device(#[from] DeviceError),
#[error("invalid surface")]
InvalidSurface,
#[error("The view format {0:?} is not compatible with texture format {1:?}, only changing srgb-ness is allowed.")]
InvalidViewFormat(wgt::TextureFormat, wgt::TextureFormat),
#[error(transparent)]
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
#[error("`SurfaceOutput` must be dropped before a new `Surface` is made")]
PreviousOutputExists,
#[error("Both `Surface` width and height must be non-zero. Wait to recreate the `Surface` until the window has non-zero area.")]
Expand Down Expand Up @@ -180,7 +184,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
format: config.format,
dimension: wgt::TextureDimension::D2,
usage: config.usage,
view_formats: vec![],
view_formats: config.view_formats,
},
hal_usage: conv::map_texture_usage(config.usage, config.format.into()),
format_features: wgt::TextureFormatFeatures {
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/examples/halmark/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl<A: hal::Api> Example<A> {
depth_or_array_layers: 1,
},
usage: hal::TextureUses::COLOR_TARGET,
view_formats: vec![],
};
unsafe {
surface.configure(&device, &surface_config).unwrap();
Expand Down
3 changes: 3 additions & 0 deletions wgpu-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,9 @@ pub struct SurfaceConfiguration {
pub extent: wgt::Extent3d,
/// Allowed usage of surface textures,
pub usage: TextureUses,
/// Allows views of swapchain texture to have a different format
/// than the texture does.
pub view_formats: Vec<wgt::TextureFormat>,
}

#[derive(Debug, Clone)]
Expand Down
9 changes: 9 additions & 0 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ impl PhysicalDeviceFeatures {
| Df::VIEW_FORMATS
| Df::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES;

dl_flags.set(
Df::SURFACE_VIEW_FORMATS,
caps.supports_extension(vk::KhrSwapchainMutableFormatFn::name()),
);
dl_flags.set(Df::CUBE_ARRAY_TEXTURES, self.core.image_cube_array != 0);
dl_flags.set(Df::ANISOTROPIC_FILTERING, self.core.sampler_anisotropy != 0);
dl_flags.set(
Expand Down Expand Up @@ -644,6 +648,11 @@ impl PhysicalDeviceCapabilities {
}
}

// Optional `VK_KHR_swapchain_mutable_format`
if self.supports_extension(vk::KhrSwapchainMutableFormatFn::name()) {
extensions.push(vk::KhrSwapchainMutableFormatFn::name());
}

// Optional `VK_EXT_robustness2`
if self.supports_extension(vk::ExtRobustness2Fn::name()) {
extensions.push(vk::ExtRobustness2Fn::name());
Expand Down
26 changes: 23 additions & 3 deletions wgpu-hal/src/vulkan/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,11 +546,25 @@ impl super::Device {
} else {
vk::ColorSpaceKHR::SRGB_NONLINEAR
};
let info = vk::SwapchainCreateInfoKHR::builder()
.flags(vk::SwapchainCreateFlagsKHR::empty())

let original_format = self.shared.private_caps.map_texture_format(config.format);
let mut raw_flags = vk::SwapchainCreateFlagsKHR::empty();
let mut raw_view_formats: Vec<vk::Format> = vec![];
if !config.view_formats.is_empty() {
raw_flags |= vk::SwapchainCreateFlagsKHR::MUTABLE_FORMAT;
raw_view_formats = config
.view_formats
.iter()
.map(|f| self.shared.private_caps.map_texture_format(*f))
.collect();
raw_view_formats.push(original_format);
}

let mut info = vk::SwapchainCreateInfoKHR::builder()
.flags(raw_flags)
.surface(surface.raw)
.min_image_count(config.swap_chain_size)
.image_format(self.shared.private_caps.map_texture_format(config.format))
.image_format(original_format)
.image_color_space(color_space)
.image_extent(vk::Extent2D {
width: config.extent.width,
Expand All @@ -565,6 +579,12 @@ impl super::Device {
.clipped(true)
.old_swapchain(old_swapchain);

let mut format_list_info = vk::ImageFormatListCreateInfo::builder();
if !raw_view_formats.is_empty() {
format_list_info = format_list_info.view_formats(&raw_view_formats);
info = info.push_next(&mut format_list_info);
}

let result = {
profiling::scope!("vkCreateSwapchainKHR");
unsafe { functor.create_swapchain(&info, None) }
Expand Down
28 changes: 27 additions & 1 deletion wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,11 @@ bitflags::bitflags! {
///
/// WebGL doesn't support this. WebGPU does.
const UNRESTRICTED_EXTERNAL_TEXTURE_COPIES = 1 << 20;

/// Supports specifying which view formats are allowed when calling create_view on the texture returned by get_current_texture.
///
/// The GLES/WebGL and Vulkan on Android doesn't support this.
const SURFACE_VIEW_FORMATS = 1 << 21;
}
}

Expand Down Expand Up @@ -4007,7 +4012,7 @@ impl Default for SurfaceCapabilities {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SurfaceConfiguration {
pub struct SurfaceConfiguration<V> {
/// The usage of the swap chain. The only supported usage is `RENDER_ATTACHMENT`.
pub usage: TextureUsages,
/// The texture format of the swap chain. The only formats that are guaranteed are
Expand All @@ -4024,6 +4029,27 @@ pub struct SurfaceConfiguration {
pub present_mode: PresentMode,
/// Specifies how the alpha channel of the textures should be handled during compositing.
pub alpha_mode: CompositeAlphaMode,
/// Specifies what view formats will be allowed when calling create_view() on texture returned by get_current_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<V: Clone> SurfaceConfiguration<V> {
/// Map view_formats of the texture descriptor into another.
pub fn map_view_formats<M>(&self, fun: impl FnOnce(V) -> M) -> SurfaceConfiguration<M> {
SurfaceConfiguration {
usage: self.usage,
format: self.format,
width: self.width,
height: self.height,
present_mode: self.present_mode,
alpha_mode: self.alpha_mode,
view_formats: fun(self.view_formats.clone()),
}
}
}

/// Status of the recieved surface image.
Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ pub fn test<E: Example>(mut params: FrameworkRefTest) {
height: params.height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: &[wgpu::TextureFormat::Rgba8Unorm],
},
&ctx.adapter,
&ctx.device,
Expand Down
1 change: 1 addition & 0 deletions wgpu/examples/hello-triangle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
height: size.height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: swapchain_capabilities.alpha_modes[0],
view_formats: &[],
};

surface.configure(&device, &config);
Expand Down
3 changes: 2 additions & 1 deletion wgpu/examples/hello-windows/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct ViewportDesc {

struct Viewport {
desc: ViewportDesc,
config: wgpu::SurfaceConfiguration,
config: wgpu::SurfaceConfiguration<'static>,
}

impl ViewportDesc {
Expand All @@ -39,6 +39,7 @@ impl ViewportDesc {
height: size.height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: caps.alpha_modes[0],
view_formats: &[],
};

self.surface.configure(device, &config);
Expand Down
12 changes: 9 additions & 3 deletions wgpu/examples/msaa-line/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct Example {
vertex_count: u32,
sample_count: u32,
rebuild_bundle: bool,
config: wgpu::SurfaceConfiguration,
config: wgpu::SurfaceConfiguration<'static>,
max_sample_count: u32,
}

Expand Down Expand Up @@ -204,7 +204,10 @@ impl framework::Example for Example {
sample_count,
max_sample_count,
rebuild_bundle: false,
config: config.clone(),
config: wgpu::SurfaceConfiguration {
view_formats: &[],
..config.clone()
},
}
}

Expand Down Expand Up @@ -242,7 +245,10 @@ impl framework::Example for Example {
device: &wgpu::Device,
_queue: &wgpu::Queue,
) {
self.config = config.clone();
self.config = wgpu::SurfaceConfiguration {
view_formats: &[],
..config.clone()
};
self.multisampled_framebuffer =
Example::create_multisampled_framebuffer(device, config, self.sample_count);
}
Expand Down
4 changes: 2 additions & 2 deletions wgpu/src/backend/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,10 +734,10 @@ impl crate::Context for Context {
surface_data: &Self::SurfaceData,
device: &Self::DeviceId,
_device_data: &Self::DeviceData,
config: &wgt::SurfaceConfiguration,
config: &crate::SurfaceConfiguration,
) {
let global = &self.0;
let error = wgc::gfx_select!(device => global.surface_configure(*surface, *device, config));
let error = wgc::gfx_select!(device => global.surface_configure(*surface, *device, &config.map_view_formats(|v| v.to_vec())));
if let Some(e) = error {
self.handle_error_fatal(e, "Surface::configure");
} else {
Expand Down
Loading

0 comments on commit 33f94c7

Please sign in to comment.