From 44399bb4a34334fba1b3bada020f69618bfc3770 Mon Sep 17 00:00:00 2001 From: Jinlei Li Date: Mon, 19 Sep 2022 12:10:21 +0800 Subject: [PATCH] Expose alpha_mode, support non-opaque mode on metal and vk backends (#2836) --- CHANGELOG.md | 14 ++++ wgpu-core/src/device/mod.rs | 99 ++++++++++++++++++++++------ wgpu-core/src/instance.rs | 41 +++++++----- wgpu-core/src/present.rs | 5 ++ wgpu-hal/examples/halmark/main.rs | 2 +- wgpu-hal/src/auxil/dxgi/conv.rs | 9 +-- wgpu-hal/src/dx12/adapter.rs | 6 +- wgpu-hal/src/dx12/device.rs | 2 +- wgpu-hal/src/gles/adapter.rs | 2 +- wgpu-hal/src/lib.rs | 35 ++-------- wgpu-hal/src/metal/adapter.rs | 5 +- wgpu-hal/src/metal/surface.rs | 6 +- wgpu-hal/src/vulkan/conv.rs | 23 ++++--- wgpu-types/src/lib.rs | 34 ++++++++++ wgpu/examples/framework.rs | 2 + wgpu/examples/hello-triangle/main.rs | 1 + wgpu/examples/hello-windows/main.rs | 1 + wgpu/src/backend/direct.rs | 24 +++++-- wgpu/src/backend/web.rs | 16 ++++- wgpu/src/lib.rs | 42 +++++++----- 20 files changed, 254 insertions(+), 115 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b1cb526e8..804b90d40c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,9 +56,23 @@ the same every time it is rendered, we now warn if it is missing. +fn vert_main(v_in: VertexInput) -> @builtin(position) @invariant vec4 {...} ``` +#### Alpha Mode + +Surface supports `alpha_mode` now. When alpha_mode is equal to `PreMultiplied` or `PostMultiplied`, +the alpha channel of framebuffer is respected in the compositing process, but which mode is available depends on +the different API and `Device`. If don't care about alpha_mode, you can set it to `Auto`. + +```diff +SurfaceConfiguration { +// ... ++ alpha_mode: surface.get_supported_alpha_modes(&adapter)[0], +} +``` + ### Added/New Features - Add `Buffer::size()` and `Buffer::usage()`; by @kpreid in [#2923](https://github.com/gfx-rs/wgpu/pull/2923) +- Expose `alpha_mode` on SurfaceConfiguration, by @jinleili in [#2836](https://github.com/gfx-rs/wgpu/pull/2836) ### Bug Fixes diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index a5c5cbe51c..41f3e50be2 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -7,7 +7,8 @@ use crate::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, TextureInitTracker, TextureInitTrackerAction, }, - instance, pipeline, present, + instance::{self, Adapter, Surface}, + pipeline, present, resource::{self, BufferMapState}, resource::{BufferAccessError, BufferMapAsyncStatus, BufferMapOperation}, track::{BindGroupStates, TextureSelector, Tracker}, @@ -681,7 +682,7 @@ impl Device { fn create_texture( &self, self_id: id::DeviceId, - adapter: &crate::instance::Adapter, + adapter: &Adapter, desc: &resource::TextureDescriptor, ) -> Result, resource::CreateTextureError> { use resource::{CreateTextureError, TextureDimensionError}; @@ -2443,7 +2444,7 @@ impl Device { fn create_render_pipeline( &self, self_id: id::DeviceId, - adapter: &crate::instance::Adapter, + adapter: &Adapter, desc: &pipeline::RenderPipelineDescriptor, implicit_context: Option, hub: &Hub, @@ -2930,7 +2931,7 @@ impl Device { fn describe_format_features( &self, - adapter: &crate::instance::Adapter, + adapter: &Adapter, format: TextureFormat, ) -> Result { let format_desc = format.describe(); @@ -3151,32 +3152,56 @@ impl Global { .map_err(|_| instance::IsSurfaceSupportedError::InvalidSurface)?; Ok(adapter.is_surface_supported(surface)) } + pub fn surface_get_supported_formats( &self, surface_id: id::SurfaceId, adapter_id: id::AdapterId, ) -> Result, instance::GetSurfaceSupportError> { profiling::scope!("Surface::get_supported_formats"); - let hub = A::hub(self); - let mut token = Token::root(); + self.fetch_adapter_and_surface::>( + surface_id, + adapter_id, + |adapter, surface| surface.get_supported_formats(adapter), + ) + } - let (surface_guard, mut token) = self.surfaces.read(&mut token); - let (adapter_guard, mut _token) = hub.adapters.read(&mut token); - let adapter = adapter_guard - .get(adapter_id) - .map_err(|_| instance::GetSurfaceSupportError::InvalidAdapter)?; - let surface = surface_guard - .get(surface_id) - .map_err(|_| instance::GetSurfaceSupportError::InvalidSurface)?; + pub fn surface_get_supported_present_modes( + &self, + surface_id: id::SurfaceId, + adapter_id: id::AdapterId, + ) -> Result, instance::GetSurfaceSupportError> { + profiling::scope!("Surface::get_supported_present_modes"); + self.fetch_adapter_and_surface::>( + surface_id, + adapter_id, + |adapter, surface| surface.get_supported_present_modes(adapter), + ) + } - surface.get_supported_formats(adapter) + pub fn surface_get_supported_alpha_modes( + &self, + surface_id: id::SurfaceId, + adapter_id: id::AdapterId, + ) -> Result, instance::GetSurfaceSupportError> { + profiling::scope!("Surface::get_supported_alpha_modes"); + self.fetch_adapter_and_surface::>( + surface_id, + adapter_id, + |adapter, surface| surface.get_supported_alpha_modes(adapter), + ) } - pub fn surface_get_supported_modes( + + fn fetch_adapter_and_surface< + A: HalApi, + F: FnOnce(&Adapter, &Surface) -> Result, + B, + >( &self, surface_id: id::SurfaceId, adapter_id: id::AdapterId, - ) -> Result, instance::GetSurfaceSupportError> { - profiling::scope!("Surface::get_supported_modes"); + get_supported_callback: F, + ) -> Result { let hub = A::hub(self); let mut token = Token::root(); @@ -3189,7 +3214,7 @@ impl Global { .get(surface_id) .map_err(|_| instance::GetSurfaceSupportError::InvalidSurface)?; - surface.get_supported_modes(adapter) + get_supported_callback(adapter, surface) } pub fn device_features( @@ -5070,6 +5095,40 @@ impl Global { available: caps.formats.clone(), }); } + if !caps + .composite_alpha_modes + .contains(&config.composite_alpha_mode) + { + let new_alpha_mode = 'b: loop { + // Automatic alpha mode checks. + let fallbacks = match config.composite_alpha_mode { + wgt::CompositeAlphaMode::Auto => &[ + wgt::CompositeAlphaMode::Opaque, + wgt::CompositeAlphaMode::Inherit, + ][..], + _ => { + return Err(E::UnsupportedAlphaMode { + requested: config.composite_alpha_mode, + available: caps.composite_alpha_modes.clone(), + }); + } + }; + + for &fallback in fallbacks { + if caps.composite_alpha_modes.contains(&fallback) { + break 'b fallback; + } + } + + unreachable!("Fallback system failed to choose alpha mode. This is a bug. AlphaMode: {:?}, Options: {:?}", config.composite_alpha_mode, &caps.composite_alpha_modes); + }; + + log::info!( + "Automatically choosing alpha mode by rule {:?}. Chose {new_alpha_mode:?}", + config.composite_alpha_mode + ); + config.composite_alpha_mode = new_alpha_mode; + } if !caps.usage.contains(config.usage) { return Err(E::UnsupportedUsage); } @@ -5119,7 +5178,7 @@ impl Global { let mut hal_config = hal::SurfaceConfiguration { swap_chain_size: num_frames, present_mode: config.present_mode, - composite_alpha_mode: hal::CompositeAlphaMode::Opaque, + composite_alpha_mode: config.alpha_mode, format: config.format, extent: wgt::Extent3d { width: config.width, diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 1aa1470c8d..6fd32e9f47 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -8,7 +8,7 @@ use crate::{ use wgt::{Backend, Backends, PowerPreference}; -use hal::{Adapter as _, Instance as _}; +use hal::{Adapter as _, Instance as _, SurfaceCapabilities}; use thiserror::Error; pub type RequestAdapterOptions = wgt::RequestAdapterOptions; @@ -156,29 +156,36 @@ impl Surface { &self, adapter: &Adapter, ) -> Result, GetSurfaceSupportError> { - let suf = A::get_surface(self); - let mut caps = unsafe { - profiling::scope!("surface_capabilities"); - adapter - .raw - .adapter - .surface_capabilities(&suf.raw) - .ok_or(GetSurfaceSupportError::UnsupportedQueueFamily)? - }; + self.get_capabilities(adapter).map(|mut caps| { + // TODO: maybe remove once we support texture view changing srgb-ness + caps.formats.sort_by_key(|f| !f.describe().srgb); + caps.formats + }) + } - // TODO: maybe remove once we support texture view changing srgb-ness - caps.formats.sort_by_key(|f| !f.describe().srgb); + pub fn get_supported_present_modes( + &self, + adapter: &Adapter, + ) -> Result, GetSurfaceSupportError> { + self.get_capabilities(adapter) + .map(|caps| caps.present_modes) + } - Ok(caps.formats) + pub fn get_supported_alpha_modes( + &self, + adapter: &Adapter, + ) -> Result, GetSurfaceSupportError> { + self.get_capabilities(adapter) + .map(|caps| caps.composite_alpha_modes) } - pub fn get_supported_modes( + fn get_capabilities( &self, adapter: &Adapter, - ) -> Result, GetSurfaceSupportError> { + ) -> Result { let suf = A::get_surface(self); + profiling::scope!("surface_capabilities"); let caps = unsafe { - profiling::scope!("surface_capabilities"); adapter .raw .adapter @@ -186,7 +193,7 @@ impl Surface { .ok_or(GetSurfaceSupportError::UnsupportedQueueFamily)? }; - Ok(caps.present_modes) + Ok(caps) } } diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 79a2f97c38..250b136862 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -80,6 +80,11 @@ pub enum ConfigureSurfaceError { requested: wgt::PresentMode, available: Vec, }, + #[error("requested alpha mode {requested:?} is not in the list of supported alpha modes: {available:?}")] + UnsupportedAlphaMode { + requested: wgt::CompositeAlphaMode, + available: Vec, + }, #[error("requested usage is not supported")] UnsupportedUsage, } diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index b9df5f2171..ac88bc86d8 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -122,7 +122,7 @@ impl Example { .max(*surface_caps.swap_chain_sizes.start()) .min(*surface_caps.swap_chain_sizes.end()), present_mode: wgt::PresentMode::Fifo, - composite_alpha_mode: hal::CompositeAlphaMode::Opaque, + composite_alpha_mode: wgt::CompositeAlphaMode::Opaque, format: wgt::TextureFormat::Bgra8UnormSrgb, extent: wgt::Extent3d { width: window_size.0, diff --git a/wgpu-hal/src/auxil/dxgi/conv.rs b/wgpu-hal/src/auxil/dxgi/conv.rs index faf42bc98a..46bc11332d 100644 --- a/wgpu-hal/src/auxil/dxgi/conv.rs +++ b/wgpu-hal/src/auxil/dxgi/conv.rs @@ -177,11 +177,6 @@ pub fn map_vertex_format(format: wgt::VertexFormat) -> dxgiformat::DXGI_FORMAT { } } -pub fn map_acomposite_alpha_mode(mode: crate::CompositeAlphaMode) -> native::AlphaMode { - use crate::CompositeAlphaMode as Cam; - match mode { - Cam::Opaque => native::AlphaMode::Ignore, - Cam::PreMultiplied => native::AlphaMode::Premultiplied, - Cam::PostMultiplied => native::AlphaMode::Straight, - } +pub fn map_acomposite_alpha_mode(_mode: wgt::CompositeAlphaMode) -> native::AlphaMode { + native::AlphaMode::Ignore } diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index d17fd9b0b6..55e3602c33 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -488,11 +488,7 @@ impl crate::Adapter for super::Adapter { | crate::TextureUses::COPY_SRC | crate::TextureUses::COPY_DST, present_modes, - composite_alpha_modes: vec![ - crate::CompositeAlphaMode::Opaque, - crate::CompositeAlphaMode::PreMultiplied, - crate::CompositeAlphaMode::PostMultiplied, - ], + composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], }) } } diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index de81b4e1bd..bdba9a6182 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -671,7 +671,7 @@ impl crate::Device for super::Device { allocator, device: self.raw, shared: Arc::clone(&self.shared), - null_rtv_handle: self.null_rtv_handle.clone(), + null_rtv_handle: self.null_rtv_handle, list: None, free_lists: Vec::new(), pass: super::PassState::new(), diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index a1b88c5b24..af29b1d0aa 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -780,7 +780,7 @@ impl crate::Adapter for super::Adapter { ] }, present_modes: vec![wgt::PresentMode::Fifo], //TODO - composite_alpha_modes: vec![crate::CompositeAlphaMode::Opaque], //TODO + composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], //TODO swap_chain_sizes: 2..=2, current_extent: None, extents: wgt::Extent3d { diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 259318bf59..90f358ccbd 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -106,7 +106,7 @@ pub type Label<'a> = Option<&'a str>; pub type MemoryRange = Range; pub type FenceValue = u64; -#[derive(Clone, Debug, Eq, PartialEq, Error)] +#[derive(Clone, Debug, PartialEq, Error)] pub enum DeviceError { #[error("out of memory")] OutOfMemory, @@ -114,7 +114,7 @@ pub enum DeviceError { Lost, } -#[derive(Clone, Debug, Eq, PartialEq, Error)] +#[derive(Clone, Debug, PartialEq, Error)] pub enum ShaderError { #[error("compilation failed: {0:?}")] Compilation(String), @@ -122,7 +122,7 @@ pub enum ShaderError { Device(#[from] DeviceError), } -#[derive(Clone, Debug, Eq, PartialEq, Error)] +#[derive(Clone, Debug, PartialEq, Error)] pub enum PipelineError { #[error("linkage failed for stage {0:?}: {1}")] Linkage(wgt::ShaderStages, String), @@ -132,7 +132,7 @@ pub enum PipelineError { Device(#[from] DeviceError), } -#[derive(Clone, Debug, Eq, PartialEq, Error)] +#[derive(Clone, Debug, PartialEq, Error)] pub enum SurfaceError { #[error("surface is lost")] Lost, @@ -144,7 +144,7 @@ pub enum SurfaceError { Other(&'static str), } -#[derive(Clone, Debug, Eq, PartialEq, Error)] +#[derive(Clone, Debug, PartialEq, Error)] #[error("Not supported")] pub struct InstanceError; @@ -779,7 +779,7 @@ pub struct SurfaceCapabilities { /// List of supported alpha composition modes. /// /// Must be at least one. - pub composite_alpha_modes: Vec, + pub composite_alpha_modes: Vec, } #[derive(Debug)] @@ -1031,27 +1031,6 @@ pub struct RenderPipelineDescriptor<'a, A: Api> { pub multiview: Option, } -/// Specifies how the alpha channel of the textures should be handled during (martin mouv i step) -/// compositing. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum CompositeAlphaMode { - /// The alpha channel, if it exists, of the textures is ignored in the - /// compositing process. Instead, the textures is treated as if it has a - /// constant alpha of 1.0. - Opaque, - /// The alpha channel, if it exists, of the textures is respected in the - /// compositing process. The non-alpha channels of the textures are - /// expected to already be multiplied by the alpha channel by the - /// application. - PreMultiplied, - /// The alpha channel, if it exists, of the textures is respected in the - /// compositing process. The non-alpha channels of the textures are not - /// expected to already be multiplied by the alpha channel by the - /// application; instead, the compositor will multiply the non-alpha - /// channels of the texture by the alpha channel during compositing. - PostMultiplied, -} - #[derive(Debug, Clone)] pub struct SurfaceConfiguration { /// Number of textures in the swap chain. Must be in @@ -1060,7 +1039,7 @@ pub struct SurfaceConfiguration { /// Vertical synchronization mode. pub present_mode: wgt::PresentMode, /// Alpha composition mode. - pub composite_alpha_mode: CompositeAlphaMode, + pub composite_alpha_mode: wgt::CompositeAlphaMode, /// Format of the surface textures. pub format: wgt::TextureFormat, /// Requested texture extent. Must be in diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 82e2f1f073..7a219ed88a 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -307,9 +307,8 @@ impl crate::Adapter for super::Adapter { vec![wgt::PresentMode::Fifo] }, composite_alpha_modes: vec![ - crate::CompositeAlphaMode::Opaque, - crate::CompositeAlphaMode::PreMultiplied, - crate::CompositeAlphaMode::PostMultiplied, + wgt::CompositeAlphaMode::Opaque, + wgt::CompositeAlphaMode::PostMultiplied, ], current_extent, diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index cd6a3ce935..1e0f1070b8 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -189,9 +189,9 @@ impl crate::Surface for super::Surface { let drawable_size = CGSize::new(config.extent.width as f64, config.extent.height as f64); match config.composite_alpha_mode { - crate::CompositeAlphaMode::Opaque => render_layer.set_opaque(true), - crate::CompositeAlphaMode::PostMultiplied => render_layer.set_opaque(false), - crate::CompositeAlphaMode::PreMultiplied => (), + wgt::CompositeAlphaMode::Opaque => render_layer.set_opaque(true), + wgt::CompositeAlphaMode::PostMultiplied => render_layer.set_opaque(false), + _ => (), } let device_raw = device.shared.device.lock(); diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index dc5b915970..a2e7b7a598 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -446,24 +446,29 @@ pub fn map_vk_present_mode(mode: vk::PresentModeKHR) -> Option } } -pub fn map_composite_alpha_mode(mode: crate::CompositeAlphaMode) -> vk::CompositeAlphaFlagsKHR { +pub fn map_composite_alpha_mode(mode: wgt::CompositeAlphaMode) -> vk::CompositeAlphaFlagsKHR { match mode { - crate::CompositeAlphaMode::Opaque => vk::CompositeAlphaFlagsKHR::OPAQUE, - crate::CompositeAlphaMode::PostMultiplied => vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED, - crate::CompositeAlphaMode::PreMultiplied => vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED, + wgt::CompositeAlphaMode::Opaque => vk::CompositeAlphaFlagsKHR::OPAQUE, + wgt::CompositeAlphaMode::PreMultiplied => vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED, + wgt::CompositeAlphaMode::PostMultiplied => vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED, + wgt::CompositeAlphaMode::Inherit => vk::CompositeAlphaFlagsKHR::INHERIT, + wgt::CompositeAlphaMode::Auto => unreachable!(), } } -pub fn map_vk_composite_alpha(flags: vk::CompositeAlphaFlagsKHR) -> Vec { +pub fn map_vk_composite_alpha(flags: vk::CompositeAlphaFlagsKHR) -> Vec { let mut modes = Vec::new(); if flags.contains(vk::CompositeAlphaFlagsKHR::OPAQUE) { - modes.push(crate::CompositeAlphaMode::Opaque); + modes.push(wgt::CompositeAlphaMode::Opaque); + } + if flags.contains(vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED) { + modes.push(wgt::CompositeAlphaMode::PreMultiplied); } if flags.contains(vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED) { - modes.push(crate::CompositeAlphaMode::PostMultiplied); + modes.push(wgt::CompositeAlphaMode::PostMultiplied); } - if flags.contains(vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED) { - modes.push(crate::CompositeAlphaMode::PreMultiplied); + if flags.contains(vk::CompositeAlphaFlagsKHR::INHERIT) { + modes.push(wgt::CompositeAlphaMode::Inherit); } modes } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8718d79794..25bf4c5d35 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3033,6 +3033,38 @@ impl Default for PresentMode { } } +/// Specifies how the alpha channel of the textures should be handled during (martin mouv i step) +/// compositing. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "trace", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub enum CompositeAlphaMode { + /// Chooses either `Opaque` or `Inherit` automatically,depending on the + /// `alpha_mode` that the current surface can support. + Auto = 0, + /// The alpha channel, if it exists, of the textures is ignored in the + /// compositing process. Instead, the textures is treated as if it has a + /// constant alpha of 1.0. + Opaque = 1, + /// The alpha channel, if it exists, of the textures is respected in the + /// compositing process. The non-alpha channels of the textures are + /// expected to already be multiplied by the alpha channel by the + /// application. + PreMultiplied = 2, + /// The alpha channel, if it exists, of the textures is respected in the + /// compositing process. The non-alpha channels of the textures are not + /// expected to already be multiplied by the alpha channel by the + /// application; instead, the compositor will multiply the non-alpha + /// channels of the texture by the alpha channel during compositing. + PostMultiplied = 3, + /// The alpha channel, if it exists, of the textures is unknown for processing + /// during compositing. Instead, the application is responsible for setting + /// the composite alpha blending mode using native WSI command. If not set, + /// then a platform-specific default will be used. + Inherit = 4, +} + bitflags::bitflags! { /// Different ways that you can use a texture. /// @@ -3083,6 +3115,8 @@ pub struct SurfaceConfiguration { /// AutoNoVsync will gracefully do a designed sets of fallbacks if their primary modes are /// unsupported. pub present_mode: PresentMode, + /// Specifies how the alpha channel of the textures should be handled during compositing. + pub alpha_mode: CompositeAlphaMode, } /// Status of the recieved surface image. diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 0d8ed6df4b..795765e653 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -273,6 +273,7 @@ fn start( width: size.width, height: size.height, present_mode: wgpu::PresentMode::Fifo, + alpha_mode: surface.get_supported_alpha_modes(&adapter)[0], }; surface.configure(&device, &config); @@ -544,6 +545,7 @@ pub fn test(mut params: FrameworkRefTest) { width: params.width, height: params.height, present_mode: wgpu::PresentMode::Fifo, + alpha_mode: wgpu::CompositeAlphaMode::Auto, }, &ctx.adapter, &ctx.device, diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs index dd1012e2ba..c61ce36882 100644 --- a/wgpu/examples/hello-triangle/main.rs +++ b/wgpu/examples/hello-triangle/main.rs @@ -73,6 +73,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { width: size.width, height: size.height, present_mode: wgpu::PresentMode::Fifo, + alpha_mode: surface.get_supported_alpha_modes(&adapter)[0], }; surface.configure(&device, &config); diff --git a/wgpu/examples/hello-windows/main.rs b/wgpu/examples/hello-windows/main.rs index 0d0e596110..ade351fee9 100644 --- a/wgpu/examples/hello-windows/main.rs +++ b/wgpu/examples/hello-windows/main.rs @@ -37,6 +37,7 @@ impl ViewportDesc { width: size.width, height: size.height, present_mode: wgpu::PresentMode::Fifo, + alpha_mode: self.surface.get_supported_alpha_modes(adapter)[0], }; self.surface.configure(device, &config); diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 67d439e199..4fe977fdce 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -19,7 +19,7 @@ use std::{ slice, sync::Arc, }; -use wgt::PresentMode; +use wgt::{CompositeAlphaMode, PresentMode}; const LABEL: &str = "label"; @@ -974,17 +974,33 @@ impl crate::Context for Context { } } - fn surface_get_supported_modes( + fn surface_get_supported_present_modes( &self, surface: &Self::SurfaceId, adapter: &Self::AdapterId, ) -> Vec { let global = &self.0; - match wgc::gfx_select!(adapter => global.surface_get_supported_modes(surface.id, *adapter)) + match wgc::gfx_select!(adapter => global.surface_get_supported_present_modes(surface.id, *adapter)) { Ok(modes) => modes, Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => vec![], - Err(err) => self.handle_error_fatal(err, "Surface::get_supported_formats"), + Err(err) => self.handle_error_fatal(err, "Surface::get_supported_present_modes"), + } + } + + fn surface_get_supported_alpha_modes( + &self, + surface: &Self::SurfaceId, + adapter: &Self::AdapterId, + ) -> Vec { + let global = &self.0; + match wgc::gfx_select!(adapter => global.surface_get_supported_alpha_modes(surface.id, *adapter)) + { + Ok(modes) => modes, + Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => { + vec![CompositeAlphaMode::Opaque] + } + Err(err) => self.handle_error_fatal(err, "Surface::get_supported_alpha_modes"), } } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index fcd6c89b78..3a9c58fb65 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1214,7 +1214,7 @@ impl crate::Context for Context { ] } - fn surface_get_supported_modes( + fn surface_get_supported_present_modes( &self, _surface: &Self::SurfaceId, _adapter: &Self::AdapterId, @@ -1222,6 +1222,14 @@ impl crate::Context for Context { vec![wgt::PresentMode::Fifo] } + fn surface_get_supported_alpha_modes( + &self, + _surface: &Self::SurfaceId, + _adapter: &Self::AdapterId, + ) -> Vec { + vec![wgt::CompositeAlphaMode::Opaque] + } + fn surface_configure( &self, surface: &Self::SurfaceId, @@ -1231,6 +1239,12 @@ impl crate::Context for Context { if let wgt::PresentMode::Mailbox | wgt::PresentMode::Immediate = config.present_mode { panic!("Only FIFO/Auto* is supported on web"); } + if let wgt::CompositeAlphaMode::PreMultiplied + | wgt::CompositeAlphaMode::PostMultiplied + | wgt::CompositeAlphaMode::Inherit = config.alpha_mode + { + panic!("Only Opaque/Auto alpha mode is supported on web"); + } let mut mapped = web_sys::GpuCanvasConfiguration::new(&device.0, map_texture_format(config.format)); mapped.usage(config.usage.bits()); diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 7c188bdc74..f793678573 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -29,18 +29,18 @@ pub use wgt::{ AdapterInfo, AddressMode, AstcBlock, AstcChannel, Backend, Backends, BindGroupLayoutEntry, BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites, - CommandBufferDescriptor, CompareFunction, DepthBiasState, DepthStencilState, DeviceType, - DownlevelCapabilities, DownlevelFlags, DynamicOffset, Extent3d, Face, Features, FilterMode, - FrontFace, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits, MultisampleState, - Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, PresentMode, PrimitiveState, - PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBindingType, - SamplerBorderColor, ShaderLocation, ShaderModel, ShaderStages, StencilFaceState, - StencilOperation, StencilState, StorageTextureAccess, SurfaceConfiguration, SurfaceStatus, - TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, - TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, - VertexFormat, VertexStepMode, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, - MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, - QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, + CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, DepthBiasState, + DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, DynamicOffset, Extent3d, + Face, Features, FilterMode, FrontFace, ImageDataLayout, ImageSubresourceRange, IndexFormat, + Limits, MultisampleState, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, + PresentMode, PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, + RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, + ShaderStages, StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, + SurfaceConfiguration, SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, + TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureUsages, + TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, COPY_BUFFER_ALIGNMENT, + COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, + QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; use backend::{BufferMappedRange, Context as C, QueueWriteBuffer}; @@ -232,11 +232,16 @@ trait Context: Debug + Send + Sized + Sync { surface: &Self::SurfaceId, adapter: &Self::AdapterId, ) -> Vec; - fn surface_get_supported_modes( + fn surface_get_supported_present_modes( &self, surface: &Self::SurfaceId, adapter: &Self::AdapterId, ) -> Vec; + fn surface_get_supported_alpha_modes( + &self, + surface: &Self::SurfaceId, + adapter: &Self::AdapterId, + ) -> Vec; fn surface_configure( &self, surface: &Self::SurfaceId, @@ -3673,8 +3678,15 @@ impl Surface { /// Returns a vec of supported presentation modes to use for the [`Surface`] with this adapter. /// /// Returns an empty vector if the surface is incompatible with the adapter. - pub fn get_supported_modes(&self, adapter: &Adapter) -> Vec { - Context::surface_get_supported_modes(&*self.context, &self.id, &adapter.id) + pub fn get_supported_present_modes(&self, adapter: &Adapter) -> Vec { + Context::surface_get_supported_present_modes(&*self.context, &self.id, &adapter.id) + } + + /// Returns a vec of supported alpha modes to use for the [`Surface`] with this adapter. + /// + /// Will return at least one element, CompositeAlphaMode::Opaque or CompositeAlphaMode::Inherit. + pub fn get_supported_alpha_modes(&self, adapter: &Adapter) -> Vec { + Context::surface_get_supported_alpha_modes(&*self.context, &self.id, &adapter.id) } /// Initializes [`Surface`] for presentation.