Improve Presentation Api (#2803)

* Add new presentation modes

* Expand presentation formats

* Add Surface::get_supported_modes

* Update to rust 2021 and improve some metal surface code

* Update wgpu-types/src/lib.rs

Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com>

* Fix windows build errors

* Fix issues with ALLOW_TEARING

Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com>
This commit is contained in:
Connor Fitzgerald 2022-06-30 14:24:17 -04:00 committed by GitHub
parent 98597da1ec
commit ea05b44f38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 277 additions and 80 deletions

View File

@ -4,7 +4,7 @@ version = "0.1.0"
authors = [
"Luca Casonato <hello@lcas.dev>",
]
edition = "2018"
edition = "2021"
description = "CTS runner for wgpu"
license = "MIT OR Apache-2.0"
publish = false

View File

@ -4,7 +4,7 @@
name = "deno_webgpu"
version = "0.54.0"
authors = ["the Deno authors"]
edition = "2018"
edition = "2021"
license = "MIT"
readme = "README.md"
repository = "https://github.com/gfx-rs/wgpu"

View File

@ -4,7 +4,7 @@ version = "0.1.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
]
edition = "2018"
edition = "2021"
license = "MIT OR Apache-2.0"
publish = false

View File

@ -4,7 +4,7 @@ version = "0.1.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
]
edition = "2018"
edition = "2021"
description = "WebGPU trace player"
homepage = "https://github.com/gfx-rs/wgpu"
repository = "https://github.com/gfx-rs/wgpu"

View File

@ -1,7 +1,7 @@
[package]
name = "run-wasm"
version = "0.1.0"
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -2,7 +2,7 @@
name = "wgpu-core"
version = "0.12.0"
authors = ["wgpu developers"]
edition = "2018"
edition = "2021"
description = "WebGPU core logic on wgpu-hal"
homepage = "https://github.com/gfx-rs/wgpu"
repository = "https://github.com/gfx-rs/wgpu"

View File

@ -3134,7 +3134,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
&self,
surface_id: id::SurfaceId,
adapter_id: id::AdapterId,
) -> Result<Vec<TextureFormat>, instance::GetSurfacePreferredFormatError> {
) -> Result<Vec<TextureFormat>, instance::GetSurfaceSupportError> {
profiling::scope!("Surface::get_supported_formats");
let hub = A::hub(self);
let mut token = Token::root();
@ -3143,13 +3143,33 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (adapter_guard, mut _token) = hub.adapters.read(&mut token);
let adapter = adapter_guard
.get(adapter_id)
.map_err(|_| instance::GetSurfacePreferredFormatError::InvalidAdapter)?;
.map_err(|_| instance::GetSurfaceSupportError::InvalidAdapter)?;
let surface = surface_guard
.get(surface_id)
.map_err(|_| instance::GetSurfacePreferredFormatError::InvalidSurface)?;
.map_err(|_| instance::GetSurfaceSupportError::InvalidSurface)?;
surface.get_supported_formats(adapter)
}
pub fn surface_get_supported_modes<A: HalApi>(
&self,
surface_id: id::SurfaceId,
adapter_id: id::AdapterId,
) -> Result<Vec<wgt::PresentMode>, instance::GetSurfaceSupportError> {
profiling::scope!("Surface::get_supported_modes");
let hub = A::hub(self);
let mut token = Token::root();
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)?;
surface.get_supported_modes(adapter)
}
pub fn device_features<A: HalApi>(
&self,
@ -4955,11 +4975,40 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
);
}
if !caps.present_modes.contains(&config.present_mode) {
log::warn!(
"Surface does not support present mode: {:?}, falling back to FIFO",
config.present_mode,
let new_mode = loop {
// Automatic present mode checks.
//
// The "Automatic" modes are never supported by the backends.
match config.present_mode {
wgt::PresentMode::AutoVsync => {
if caps.present_modes.contains(&wgt::PresentMode::FifoRelaxed) {
break wgt::PresentMode::FifoRelaxed;
}
if caps.present_modes.contains(&wgt::PresentMode::Fifo) {
break wgt::PresentMode::Fifo;
}
}
wgt::PresentMode::AutoNoVsync => {
if caps.present_modes.contains(&wgt::PresentMode::Immediate) {
break wgt::PresentMode::Immediate;
}
if caps.present_modes.contains(&wgt::PresentMode::Mailbox) {
break wgt::PresentMode::Mailbox;
}
}
_ => {}
}
return Err(E::UnsupportedPresentMode {
requested: config.present_mode,
available: caps.present_modes.clone(),
});
};
log::info!(
"Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}",
config.present_mode
);
config.present_mode = wgt::PresentMode::Fifo;
config.present_mode = new_mode;
}
if !caps.formats.contains(&config.format) {
return Err(E::UnsupportedFormat {

View File

@ -155,7 +155,7 @@ impl Surface {
pub fn get_supported_formats<A: HalApi>(
&self,
adapter: &Adapter<A>,
) -> Result<Vec<wgt::TextureFormat>, GetSurfacePreferredFormatError> {
) -> Result<Vec<wgt::TextureFormat>, GetSurfaceSupportError> {
let suf = A::get_surface(self);
let mut caps = unsafe {
profiling::scope!("surface_capabilities");
@ -163,7 +163,7 @@ impl Surface {
.raw
.adapter
.surface_capabilities(&suf.raw)
.ok_or(GetSurfacePreferredFormatError::UnsupportedQueueFamily)?
.ok_or(GetSurfaceSupportError::UnsupportedQueueFamily)?
};
// TODO: maybe remove once we support texture view changing srgb-ness
@ -171,6 +171,23 @@ impl Surface {
Ok(caps.formats)
}
pub fn get_supported_modes<A: HalApi>(
&self,
adapter: &Adapter<A>,
) -> Result<Vec<wgt::PresentMode>, GetSurfaceSupportError> {
let suf = A::get_surface(self);
let caps = unsafe {
profiling::scope!("surface_capabilities");
adapter
.raw
.adapter
.surface_capabilities(&suf.raw)
.ok_or(GetSurfaceSupportError::UnsupportedQueueFamily)?
};
Ok(caps.present_modes)
}
}
pub struct Adapter<A: hal::Api> {
@ -341,7 +358,7 @@ pub enum IsSurfaceSupportedError {
}
#[derive(Clone, Debug, Error)]
pub enum GetSurfacePreferredFormatError {
pub enum GetSurfaceSupportError {
#[error("invalid adapter")]
InvalidAdapter,
#[error("invalid surface")]

View File

@ -75,6 +75,11 @@ pub enum ConfigureSurfaceError {
requested: wgt::TextureFormat,
available: Vec<wgt::TextureFormat>,
},
#[error("requested present mode {requested:?} is not in the list of supported present modes: {available:?}")]
UnsupportedPresentMode {
requested: wgt::PresentMode,
available: Vec<wgt::PresentMode>,
},
#[error("requested usage is not supported")]
UnsupportedUsage,
}

View File

@ -2,7 +2,7 @@
name = "wgpu-hal"
version = "0.12.0"
authors = ["wgpu developers"]
edition = "2018"
edition = "2021"
description = "WebGPU hardware abstraction layer"
homepage = "https://github.com/gfx-rs/wgpu"
repository = "https://github.com/gfx-rs/wgpu"

View File

@ -4,7 +4,7 @@ use crate::{
};
use std::{mem, sync::Arc, thread};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_5, minwindef, windef, winerror},
shared::{dxgi, dxgi1_2, windef, winerror},
um::{d3d12, d3d12sdklayers, winuser},
};
@ -426,20 +426,9 @@ impl crate::Adapter<super::Api> for super::Adapter {
}
};
let mut present_modes = vec![wgt::PresentMode::Fifo];
#[allow(trivial_casts)]
if let Some(factory5) = surface.factory.as_factory5() {
let mut allow_tearing: minwindef::BOOL = minwindef::FALSE;
let hr = factory5.CheckFeatureSupport(
dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
&mut allow_tearing as *mut _ as *mut _,
mem::size_of::<minwindef::BOOL>() as _,
);
match hr.into_result() {
Err(err) => log::warn!("Unable to check for tearing support: {}", err),
Ok(()) => present_modes.push(wgt::PresentMode::Immediate),
}
let mut present_modes = vec![wgt::PresentMode::Mailbox, wgt::PresentMode::Fifo];
if surface.supports_allow_tearing {
present_modes.push(wgt::PresentMode::Immediate);
}
Some(crate::SurfaceCapabilities {

View File

@ -1,6 +1,8 @@
use winapi::shared::{dxgi1_5, minwindef};
use super::SurfaceTarget;
use crate::auxil::{self, dxgi::result::HResult as _};
use std::sync::Arc;
use std::{mem, sync::Arc};
impl Drop for super::Instance {
fn drop(&mut self) {
@ -37,11 +39,28 @@ impl crate::Instance<super::Api> for super::Instance {
desc.flags,
)?;
let mut supports_allow_tearing = false;
#[allow(trivial_casts)]
if let Some(factory5) = factory.as_factory5() {
let mut allow_tearing: minwindef::BOOL = minwindef::FALSE;
let hr = factory5.CheckFeatureSupport(
dxgi1_5::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
&mut allow_tearing as *mut _ as *mut _,
mem::size_of::<minwindef::BOOL>() as _,
);
match hr.into_result() {
Err(err) => log::warn!("Unable to check for tearing support: {}", err),
Ok(()) => supports_allow_tearing = true,
}
}
Ok(Self {
// The call to create_factory will only succeed if we get a factory4, so this is safe.
factory,
library: Arc::new(lib_main),
_lib_dxgi: lib_dxgi,
supports_allow_tearing,
flags: desc.flags,
})
}
@ -54,6 +73,7 @@ impl crate::Instance<super::Api> for super::Instance {
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
factory: self.factory,
target: SurfaceTarget::WndHandle(handle.hwnd as *mut _),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: None,
}),
_ => Err(crate::InstanceError),

View File

@ -88,6 +88,7 @@ const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10;
pub struct Instance {
factory: native::DxgiFactory,
library: Arc<native::D3D12Lib>,
supports_allow_tearing: bool,
_lib_dxgi: native::DxgiLib,
flags: crate::InstanceFlags,
}
@ -100,6 +101,7 @@ impl Instance {
Surface {
factory: self.factory,
target: SurfaceTarget::Visual(native::WeakPtr::from_raw(visual)),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: None,
}
}
@ -128,6 +130,7 @@ enum SurfaceTarget {
pub struct Surface {
factory: native::DxgiFactory,
target: SurfaceTarget,
supports_allow_tearing: bool,
swap_chain: Option<SwapChain>,
}
@ -556,12 +559,12 @@ impl crate::Surface<Api> for Surface {
config: &crate::SurfaceConfiguration,
) -> Result<(), crate::SurfaceError> {
let mut flags = dxgi::DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
match config.present_mode {
wgt::PresentMode::Immediate => {
// We always set ALLOW_TEARING on the swapchain no matter
// what kind of swapchain we want because ResizeBuffers
// cannot change if ALLOW_TEARING is applied to the swapchain.
if self.supports_allow_tearing {
flags |= dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
}
_ => {}
}
let non_srgb_format = auxil::dxgi::conv::map_texture_format_nosrgb(config.format);
@ -771,9 +774,11 @@ impl crate::Queue<Api> for Queue {
sc.acquired_count -= 1;
let (interval, flags) = match sc.present_mode {
// We only allow immediate if ALLOW_TEARING is valid.
wgt::PresentMode::Immediate => (0, dxgi::DXGI_PRESENT_ALLOW_TEARING),
wgt::PresentMode::Mailbox => (0, 0),
wgt::PresentMode::Fifo => (1, 0),
wgt::PresentMode::Mailbox => (1, 0),
m => unreachable!("Cannot make surface with present mode {m:?}"),
};
profiling::scope!("IDXGISwapchain3::Present");

View File

@ -281,13 +281,18 @@ impl crate::Adapter<super::Api> for super::Adapter {
None
};
let pc = &self.shared.private_caps;
Some(crate::SurfaceCapabilities {
formats: vec![
let mut formats = vec![
wgt::TextureFormat::Bgra8Unorm,
wgt::TextureFormat::Bgra8UnormSrgb,
wgt::TextureFormat::Rgba16Float,
],
];
if self.shared.private_caps.format_rgb10a2_unorm_surface {
formats.push(wgt::TextureFormat::Rgb10a2Unorm);
}
let pc = &self.shared.private_caps;
Some(crate::SurfaceCapabilities {
formats,
//Note: this is hardcoded in `CAMetalLayer` documentation
swap_chain_sizes: if pc.can_set_maximum_drawables_count {
2..=3
@ -575,6 +580,7 @@ impl super::PrivateCapabilities {
format_rgba8_srgb_no_write: !Self::supports_any(device, RGBA8_SRGB),
format_rgb10a2_unorm_all: Self::supports_any(device, RGB10A2UNORM_ALL),
format_rgb10a2_unorm_no_write: !Self::supports_any(device, RGB10A2UNORM_ALL),
format_rgb10a2_unorm_surface: os_is_mac,
format_rgb10a2_uint_color: !Self::supports_any(device, RGB10A2UINT_COLOR_WRITE),
format_rgb10a2_uint_color_write: Self::supports_any(device, RGB10A2UINT_COLOR_WRITE),
format_rg11b10_all: Self::supports_any(device, RG11B10FLOAT_ALL),

View File

@ -180,6 +180,7 @@ struct PrivateCapabilities {
format_rgba8_srgb_no_write: bool,
format_rgb10a2_unorm_all: bool,
format_rgb10a2_unorm_no_write: bool,
format_rgb10a2_unorm_surface: bool,
format_rgb10a2_uint_color: bool,
format_rgb10a2_uint_color_write: bool,
format_rg11b10_all: bool,

View File

@ -170,7 +170,11 @@ impl crate::Surface<super::Api> for super::Surface {
let render_layer = self.render_layer.lock();
let framebuffer_only = config.usage == crate::TextureUses::COLOR_TARGET;
let display_sync = config.present_mode != wgt::PresentMode::Immediate;
let display_sync = match config.present_mode {
wgt::PresentMode::Fifo => true,
wgt::PresentMode::Immediate => false,
m => unreachable!("Unsupported present mode: {m:?}"),
};
let drawable_size = CGSize::new(config.extent.width as f64, config.extent.height as f64);
match config.composite_alpha_mode {

View File

@ -1613,22 +1613,9 @@ impl crate::Adapter<super::Api> for super::Adapter {
}
};
let supported_formats = [
wgt::TextureFormat::Rgba8Unorm,
wgt::TextureFormat::Rgba8UnormSrgb,
wgt::TextureFormat::Bgra8Unorm,
wgt::TextureFormat::Bgra8UnormSrgb,
wgt::TextureFormat::Rgba16Float,
];
let formats = supported_formats
.iter()
.cloned()
.filter(|&format| {
let vk_format = self.private_caps.map_texture_format(format);
raw_surface_formats
.iter()
.any(|sf| sf.format == vk_format || sf.format == vk::Format::UNDEFINED)
})
let formats = raw_surface_formats
.into_iter()
.filter_map(conv::map_vk_surface_formats)
.collect();
Some(crate::SurfaceCapabilities {
formats,

View File

@ -144,6 +144,24 @@ impl super::PrivateCapabilities {
}
}
pub fn map_vk_surface_formats(sf: vk::SurfaceFormatKHR) -> Option<wgt::TextureFormat> {
use ash::vk::Format as F;
use wgt::TextureFormat as Tf;
// List we care about pulled from https://vulkan.gpuinfo.org/listsurfaceformats.php
Some(match sf.format {
F::B8G8R8A8_UNORM => Tf::Bgra8Unorm,
F::B8G8R8A8_SRGB => Tf::Bgra8UnormSrgb,
F::R8G8B8A8_SNORM => Tf::Rgba8Snorm,
F::R8G8B8A8_UNORM => Tf::Rgba8Unorm,
F::R8G8B8A8_SRGB => Tf::Rgba8UnormSrgb,
F::R16G16B16A16_SFLOAT => Tf::Rgba16Float,
F::R16G16B16A16_SNORM => Tf::Rgba16Snorm,
F::R16G16B16A16_UNORM => Tf::Rgba16Unorm,
F::A2B10G10R10_UNORM_PACK32 => Tf::Rgb10a2Unorm,
_ => return None,
})
}
impl crate::Attachment<'_, super::Api> {
pub(super) fn make_attachment_key(
&self,
@ -405,7 +423,10 @@ pub fn map_present_mode(mode: wgt::PresentMode) -> vk::PresentModeKHR {
wgt::PresentMode::Immediate => vk::PresentModeKHR::IMMEDIATE,
wgt::PresentMode::Mailbox => vk::PresentModeKHR::MAILBOX,
wgt::PresentMode::Fifo => vk::PresentModeKHR::FIFO,
//wgt::PresentMode::Relaxed => vk::PresentModeKHR::FIFO_RELAXED,
wgt::PresentMode::FifoRelaxed => vk::PresentModeKHR::FIFO_RELAXED,
wgt::PresentMode::AutoNoVsync | wgt::PresentMode::AutoVsync => {
unreachable!("Cannot create swapchain with Auto PresentationMode")
}
}
}

View File

@ -2,7 +2,7 @@
name = "wgpu-info"
version = "0.12.0"
authors = ["wgpu developers"]
edition = "2018"
edition = "2021"
description = "Adapter information and per-adapter test program"
homepage = "https://github.com/gfx-rs/wgpu"
repository = "https://github.com/gfx-rs/wgpu"

View File

@ -2,7 +2,7 @@
name = "wgpu-types"
version = "0.12.0"
authors = ["wgpu developers"]
edition = "2018"
edition = "2021"
description = "WebGPU types"
homepage = "https://github.com/gfx-rs/wgpu"
repository = "https://github.com/gfx-rs/wgpu"

View File

@ -2949,20 +2949,75 @@ impl<T> Default for CommandEncoderDescriptor<Option<T>> {
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum PresentMode {
/// The presentation engine does **not** wait for a vertical blanking period and
/// the request is presented immediately. This is a low-latency presentation mode,
/// but visible tearing may be observed. Will fallback to `Fifo` if unavailable on the
/// selected platform and backend. Not optimal for mobile.
Immediate = 0,
/// The presentation engine waits for the next vertical blanking period to update
/// the current image, but frames may be submitted without delay. This is a low-latency
/// presentation mode and visible tearing will **not** be observed. Will fallback to `Fifo`
/// if unavailable on the selected platform and backend. Not optimal for mobile.
Mailbox = 1,
/// The presentation engine waits for the next vertical blanking period to update
/// the current image. The framerate will be capped at the display refresh rate,
/// corresponding to the `VSync`. Tearing cannot be observed. Optimal for mobile.
/// Chooses FifoRelaxed -> Fifo based on availability.
///
/// Because of the fallback behavior, it is supported everywhere.
AutoVsync = 0,
/// Chooses Immediate -> Mailbox -> Fifo (on web) based on availability.
///
/// Because of the fallback behavior, it is supported everywhere.
AutoNoVsync = 1,
/// Presentation frames are kept in a First-In-First-Out queue approximately 3 frames
/// long. Every vertical blanking period, the presentation engine will pop a frame
/// off the queue to display. If there is no frame to display, it will present the same
/// frame again until the next vblank.
///
/// When a present command is executed on the gpu, the presented image is added on the queue.
///
/// No tearing will be observed.
///
/// Calls to get_current_texture will block until there is a spot in the queue.
///
/// Supported on all platforms.
///
/// If you don't know what mode to choose, choose this mode. This is traditionally called "Vsync On".
Fifo = 2,
/// Presentation frames are kept in a First-In-First-Out queue approximately 3 frames
/// long. Every vertical blanking period, the presentation engine will pop a frame
/// off the queue to display. If there is no frame to display, it will present the
/// same frame until there is a frame in the queue. The moment there is a frame in the
/// queue, it will immediately pop the frame off the queue.
///
/// When a present command is executed on the gpu, the presented image is added on the queue.
///
/// Tearing will be observed if frames last more than one vblank as the front buffer.
///
/// Calls to get_current_texture will block until there is a spot in the queue.
///
/// Supported on AMD on Vulkan.
///
/// This is traditionally called "Adaptive Vsync"
FifoRelaxed = 3,
/// Presentation frames are not queued at all. The moment a present command
/// is executed on the GPU, the presented image is swapped onto the front buffer
/// immediately.
///
/// Tearing can be observed.
///
/// Supported on most platforms except older DX12.
///
/// This is traditionally called "Vsync Off".
Immediate = 4,
/// Presentation frames are kept in a single-frame queue. Every vertical blanking period,
/// the presentation engine will pop a frame from the queue. If there is no frame to display,
/// it will present the same frame again until the next vblank.
///
/// When a present command is executed on the gpu, the frame will be put into the queue.
/// If there was already a frame in the queue, the new frame will _replace_ the old frame
/// on the queue.
///
/// No tearing will be observed.
///
/// Supported on DX11/12 on Windows 10, and NVidia on Vulkan.
///
/// This is traditionally called "Fast Vsync"
Mailbox = 5,
}
impl Default for PresentMode {
fn default() -> Self {
Self::Fifo
}
}
bitflags::bitflags! {

View File

@ -2,7 +2,7 @@
name = "wgpu"
version = "0.12.0"
authors = ["wgpu developers"]
edition = "2018"
edition = "2021"
description = "Rusty WebGPU API wrapper"
homepage = "https://wgpu.rs/"
repository = "https://github.com/gfx-rs/wgpu/tree/v0.12"

View File

@ -72,7 +72,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
format: swapchain_format,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Mailbox,
present_mode: wgpu::PresentMode::Fifo,
};
surface.configure(&device, &config);

View File

@ -20,6 +20,7 @@ use std::{
slice,
sync::Arc,
};
use wgt::PresentMode;
const LABEL: &str = "label";
@ -972,7 +973,21 @@ impl crate::Context for Context {
match wgc::gfx_select!(adapter => global.surface_get_supported_formats(surface.id, *adapter))
{
Ok(formats) => formats,
Err(wgc::instance::GetSurfacePreferredFormatError::UnsupportedQueueFamily) => vec![],
Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => vec![],
Err(err) => self.handle_error_fatal(err, "Surface::get_supported_formats"),
}
}
fn surface_get_supported_modes(
&self,
surface: &Self::SurfaceId,
adapter: &Self::AdapterId,
) -> Vec<PresentMode> {
let global = &self.0;
match wgc::gfx_select!(adapter => global.surface_get_supported_modes(surface.id, *adapter))
{
Ok(modes) => modes,
Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => vec![],
Err(err) => self.handle_error_fatal(err, "Surface::get_supported_formats"),
}
}

View File

@ -1207,12 +1207,23 @@ impl crate::Context for Context {
]
}
fn surface_get_supported_modes(
&self,
_surface: &Self::SurfaceId,
_adapter: &Self::AdapterId,
) -> Vec<wgt::PresentMode> {
vec![wgt::PresentMode::Fifo]
}
fn surface_configure(
&self,
surface: &Self::SurfaceId,
device: &Self::DeviceId,
config: &wgt::SurfaceConfiguration,
) {
if let wgt::PresentMode::Mailbox | wgt::PresentMode::Immediate = config.present_mode {
panic!("Only FIFO/Auto* is supported on web");
}
let mut mapped =
web_sys::GpuCanvasConfiguration::new(&device.0, map_texture_format(config.format));
mapped.usage(config.usage.bits());

View File

@ -230,6 +230,11 @@ trait Context: Debug + Send + Sized + Sync {
surface: &Self::SurfaceId,
adapter: &Self::AdapterId,
) -> Vec<TextureFormat>;
fn surface_get_supported_modes(
&self,
surface: &Self::SurfaceId,
adapter: &Self::AdapterId,
) -> Vec<PresentMode>;
fn surface_configure(
&self,
surface: &Self::SurfaceId,
@ -3554,6 +3559,13 @@ impl Surface {
Context::surface_get_supported_formats(&*self.context, &self.id, &adapter.id)
}
/// 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<PresentMode> {
Context::surface_get_supported_modes(&*self.context, &self.id, &adapter.id)
}
/// Initializes [`Surface`] for presentation.
///
/// # Panics