mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Move surface_configure out of Global
This commit is contained in:
parent
21ea8f2979
commit
73d1334ba3
@ -1737,276 +1737,15 @@ impl Global {
|
|||||||
device_id: DeviceId,
|
device_id: DeviceId,
|
||||||
config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
|
config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
|
||||||
) -> Option<present::ConfigureSurfaceError> {
|
) -> Option<present::ConfigureSurfaceError> {
|
||||||
use present::ConfigureSurfaceError as E;
|
|
||||||
profiling::scope!("surface_configure");
|
|
||||||
|
|
||||||
fn validate_surface_configuration(
|
|
||||||
config: &mut hal::SurfaceConfiguration,
|
|
||||||
caps: &hal::SurfaceCapabilities,
|
|
||||||
max_texture_dimension_2d: u32,
|
|
||||||
) -> Result<(), E> {
|
|
||||||
let width = config.extent.width;
|
|
||||||
let height = config.extent.height;
|
|
||||||
|
|
||||||
if width > max_texture_dimension_2d || height > max_texture_dimension_2d {
|
|
||||||
return Err(E::TooLarge {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
max_texture_dimension_2d,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if !caps.present_modes.contains(&config.present_mode) {
|
|
||||||
// Automatic present mode checks.
|
|
||||||
//
|
|
||||||
// The "Automatic" modes are never supported by the backends.
|
|
||||||
let fallbacks = match config.present_mode {
|
|
||||||
wgt::PresentMode::AutoVsync => {
|
|
||||||
&[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..]
|
|
||||||
}
|
|
||||||
// Always end in FIFO to make sure it's always supported
|
|
||||||
wgt::PresentMode::AutoNoVsync => &[
|
|
||||||
wgt::PresentMode::Immediate,
|
|
||||||
wgt::PresentMode::Mailbox,
|
|
||||||
wgt::PresentMode::Fifo,
|
|
||||||
][..],
|
|
||||||
_ => {
|
|
||||||
return Err(E::UnsupportedPresentMode {
|
|
||||||
requested: config.present_mode,
|
|
||||||
available: caps.present_modes.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_mode = fallbacks
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.find(|fallback| caps.present_modes.contains(fallback))
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
unreachable!(
|
|
||||||
"Fallback system failed to choose present mode. \
|
|
||||||
This is a bug. Mode: {:?}, Options: {:?}",
|
|
||||||
config.present_mode, &caps.present_modes
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
api_log!(
|
|
||||||
"Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}",
|
|
||||||
config.present_mode
|
|
||||||
);
|
|
||||||
config.present_mode = new_mode;
|
|
||||||
}
|
|
||||||
if !caps.formats.contains(&config.format) {
|
|
||||||
return Err(E::UnsupportedFormat {
|
|
||||||
requested: config.format,
|
|
||||||
available: caps.formats.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if !caps
|
|
||||||
.composite_alpha_modes
|
|
||||||
.contains(&config.composite_alpha_mode)
|
|
||||||
{
|
|
||||||
let new_alpha_mode = 'alpha: {
|
|
||||||
// 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 'alpha fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!(
|
|
||||||
"Fallback system failed to choose alpha mode. This is a bug. \
|
|
||||||
AlphaMode: {:?}, Options: {:?}",
|
|
||||||
config.composite_alpha_mode, &caps.composite_alpha_modes
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
api_log!(
|
|
||||||
"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 {
|
|
||||||
requested: config.usage,
|
|
||||||
available: caps.usage,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if width == 0 || height == 0 {
|
|
||||||
return Err(E::ZeroArea);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
log::debug!("configuring surface with {config:?}");
|
|
||||||
|
|
||||||
let error = 'error: {
|
|
||||||
// User callbacks must not be called while we are holding locks.
|
|
||||||
let user_callbacks;
|
|
||||||
{
|
|
||||||
let device = self.hub.devices.get(device_id);
|
let device = self.hub.devices.get(device_id);
|
||||||
|
let surface = self.surfaces.get(surface_id);
|
||||||
|
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
if let Some(ref mut trace) = *device.trace.lock() {
|
if let Some(ref mut trace) = *device.trace.lock() {
|
||||||
trace.add(trace::Action::ConfigureSurface(surface_id, config.clone()));
|
trace.add(trace::Action::ConfigureSurface(surface_id, config.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = device.check_is_valid() {
|
device.configure_surface(&surface, config)
|
||||||
break 'error e.into();
|
|
||||||
}
|
|
||||||
|
|
||||||
let surface = self.surfaces.get(surface_id);
|
|
||||||
|
|
||||||
let caps = match surface.get_capabilities(&device.adapter) {
|
|
||||||
Ok(caps) => caps,
|
|
||||||
Err(_) => break 'error E::UnsupportedQueueFamily,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut hal_view_formats = Vec::new();
|
|
||||||
for format in config.view_formats.iter() {
|
|
||||||
if *format == config.format {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !caps.formats.contains(&config.format) {
|
|
||||||
break 'error E::UnsupportedFormat {
|
|
||||||
requested: config.format,
|
|
||||||
available: caps.formats,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
|
|
||||||
break 'error 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 'error E::MissingDownlevelFlags(missing_flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let maximum_frame_latency = config.desired_maximum_frame_latency.clamp(
|
|
||||||
*caps.maximum_frame_latency.start(),
|
|
||||||
*caps.maximum_frame_latency.end(),
|
|
||||||
);
|
|
||||||
let mut hal_config = hal::SurfaceConfiguration {
|
|
||||||
maximum_frame_latency,
|
|
||||||
present_mode: config.present_mode,
|
|
||||||
composite_alpha_mode: config.alpha_mode,
|
|
||||||
format: config.format,
|
|
||||||
extent: wgt::Extent3d {
|
|
||||||
width: config.width,
|
|
||||||
height: config.height,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
},
|
|
||||||
usage: conv::map_texture_usage(
|
|
||||||
config.usage,
|
|
||||||
hal::FormatAspects::COLOR,
|
|
||||||
wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY
|
|
||||||
| wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY
|
|
||||||
| wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
|
|
||||||
),
|
|
||||||
view_formats: hal_view_formats,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(error) = validate_surface_configuration(
|
|
||||||
&mut hal_config,
|
|
||||||
&caps,
|
|
||||||
device.limits.max_texture_dimension_2d,
|
|
||||||
) {
|
|
||||||
break 'error error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for all work to finish before configuring the surface.
|
|
||||||
let snatch_guard = device.snatchable_lock.read();
|
|
||||||
let fence = device.fence.read();
|
|
||||||
|
|
||||||
let maintain_result;
|
|
||||||
(user_callbacks, maintain_result) =
|
|
||||||
device.maintain(fence, wgt::PollType::wait_indefinitely(), snatch_guard);
|
|
||||||
|
|
||||||
match maintain_result {
|
|
||||||
// We're happy
|
|
||||||
Ok(wgt::PollStatus::QueueEmpty) => {}
|
|
||||||
Ok(wgt::PollStatus::WaitSucceeded) => {
|
|
||||||
// After the wait, the queue should be empty. It can only be non-empty
|
|
||||||
// if another thread is submitting at the same time.
|
|
||||||
break 'error E::GpuWaitTimeout;
|
|
||||||
}
|
|
||||||
Ok(wgt::PollStatus::Poll) => {
|
|
||||||
unreachable!("Cannot get a Poll result from a Wait action.")
|
|
||||||
}
|
|
||||||
Err(WaitIdleError::Timeout) if cfg!(target_arch = "wasm32") => {
|
|
||||||
// On wasm, you cannot actually successfully wait for the surface.
|
|
||||||
// However WebGL does not actually require you do this, so ignoring
|
|
||||||
// the failure is totally fine. See https://github.com/gfx-rs/wgpu/issues/7363
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
break 'error e.into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All textures must be destroyed before the surface can be re-configured.
|
|
||||||
if let Some(present) = surface.presentation.lock().take() {
|
|
||||||
if present.acquired_texture.is_some() {
|
|
||||||
break 'error E::PreviousOutputExists;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Texture views may still be alive that point to the texture.
|
|
||||||
// this will allow the user to render to the surface texture, long after
|
|
||||||
// it has been removed.
|
|
||||||
//
|
|
||||||
// https://github.com/gfx-rs/wgpu/issues/4105
|
|
||||||
|
|
||||||
let surface_raw = surface.raw(device.backend()).unwrap();
|
|
||||||
match unsafe { surface_raw.configure(device.raw(), &hal_config) } {
|
|
||||||
Ok(()) => (),
|
|
||||||
Err(error) => {
|
|
||||||
break 'error match error {
|
|
||||||
hal::SurfaceError::Outdated | hal::SurfaceError::Lost => {
|
|
||||||
E::InvalidSurface
|
|
||||||
}
|
|
||||||
hal::SurfaceError::Device(error) => {
|
|
||||||
E::Device(device.handle_hal_error(error))
|
|
||||||
}
|
|
||||||
hal::SurfaceError::Other(message) => {
|
|
||||||
log::error!("surface configuration failed: {message}");
|
|
||||||
E::InvalidSurface
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut presentation = surface.presentation.lock();
|
|
||||||
*presentation = Some(present::Presentation {
|
|
||||||
device,
|
|
||||||
config: config.clone(),
|
|
||||||
acquired_texture: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
user_callbacks.fire();
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check `device_id` for freeable resources and completed buffer mappings.
|
/// Check `device_id` for freeable resources and completed buffer mappings.
|
||||||
|
|||||||
@ -24,6 +24,7 @@ use wgt::{
|
|||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use crate::device::trace;
|
use crate::device::trace;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
api_log,
|
||||||
binding_model::{self, BindGroup, BindGroupLayout, BindGroupLayoutEntryError},
|
binding_model::{self, BindGroup, BindGroupLayout, BindGroupLayoutEntryError},
|
||||||
command, conv,
|
command, conv,
|
||||||
device::{
|
device::{
|
||||||
@ -39,6 +40,7 @@ use crate::{
|
|||||||
lock::{rank, Mutex, RwLock},
|
lock::{rank, Mutex, RwLock},
|
||||||
pipeline,
|
pipeline,
|
||||||
pool::ResourcePool,
|
pool::ResourcePool,
|
||||||
|
present,
|
||||||
resource::{
|
resource::{
|
||||||
self, Buffer, ExternalTexture, Fallible, Labeled, ParentDevice, QuerySet,
|
self, Buffer, ExternalTexture, Fallible, Labeled, ParentDevice, QuerySet,
|
||||||
RawResourceAccess, Sampler, StagingBuffer, Texture, TextureView,
|
RawResourceAccess, Sampler, StagingBuffer, Texture, TextureView,
|
||||||
@ -4693,6 +4695,274 @@ impl Device {
|
|||||||
Ok(query_set)
|
Ok(query_set)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn configure_surface(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
surface: &crate::instance::Surface,
|
||||||
|
config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
|
||||||
|
) -> Option<present::ConfigureSurfaceError> {
|
||||||
|
use present::ConfigureSurfaceError as E;
|
||||||
|
profiling::scope!("surface_configure");
|
||||||
|
|
||||||
|
fn validate_surface_configuration(
|
||||||
|
config: &mut hal::SurfaceConfiguration,
|
||||||
|
caps: &hal::SurfaceCapabilities,
|
||||||
|
max_texture_dimension_2d: u32,
|
||||||
|
) -> Result<(), E> {
|
||||||
|
let width = config.extent.width;
|
||||||
|
let height = config.extent.height;
|
||||||
|
|
||||||
|
if width > max_texture_dimension_2d || height > max_texture_dimension_2d {
|
||||||
|
return Err(E::TooLarge {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
max_texture_dimension_2d,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !caps.present_modes.contains(&config.present_mode) {
|
||||||
|
// Automatic present mode checks.
|
||||||
|
//
|
||||||
|
// The "Automatic" modes are never supported by the backends.
|
||||||
|
let fallbacks = match config.present_mode {
|
||||||
|
wgt::PresentMode::AutoVsync => {
|
||||||
|
&[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..]
|
||||||
|
}
|
||||||
|
// Always end in FIFO to make sure it's always supported
|
||||||
|
wgt::PresentMode::AutoNoVsync => &[
|
||||||
|
wgt::PresentMode::Immediate,
|
||||||
|
wgt::PresentMode::Mailbox,
|
||||||
|
wgt::PresentMode::Fifo,
|
||||||
|
][..],
|
||||||
|
_ => {
|
||||||
|
return Err(E::UnsupportedPresentMode {
|
||||||
|
requested: config.present_mode,
|
||||||
|
available: caps.present_modes.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_mode = fallbacks
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.find(|fallback| caps.present_modes.contains(fallback))
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
unreachable!(
|
||||||
|
"Fallback system failed to choose present mode. \
|
||||||
|
This is a bug. Mode: {:?}, Options: {:?}",
|
||||||
|
config.present_mode, &caps.present_modes
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
api_log!(
|
||||||
|
"Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}",
|
||||||
|
config.present_mode
|
||||||
|
);
|
||||||
|
config.present_mode = new_mode;
|
||||||
|
}
|
||||||
|
if !caps.formats.contains(&config.format) {
|
||||||
|
return Err(E::UnsupportedFormat {
|
||||||
|
requested: config.format,
|
||||||
|
available: caps.formats.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !caps
|
||||||
|
.composite_alpha_modes
|
||||||
|
.contains(&config.composite_alpha_mode)
|
||||||
|
{
|
||||||
|
let new_alpha_mode = 'alpha: {
|
||||||
|
// 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 'alpha fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!(
|
||||||
|
"Fallback system failed to choose alpha mode. This is a bug. \
|
||||||
|
AlphaMode: {:?}, Options: {:?}",
|
||||||
|
config.composite_alpha_mode, &caps.composite_alpha_modes
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
api_log!(
|
||||||
|
"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 {
|
||||||
|
requested: config.usage,
|
||||||
|
available: caps.usage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if width == 0 || height == 0 {
|
||||||
|
return Err(E::ZeroArea);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("configuring surface with {config:?}");
|
||||||
|
|
||||||
|
let error = 'error: {
|
||||||
|
// User callbacks must not be called while we are holding locks.
|
||||||
|
let user_callbacks;
|
||||||
|
{
|
||||||
|
if let Err(e) = self.check_is_valid() {
|
||||||
|
break 'error e.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
let caps = match surface.get_capabilities(&self.adapter) {
|
||||||
|
Ok(caps) => caps,
|
||||||
|
Err(_) => break 'error E::UnsupportedQueueFamily,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut hal_view_formats = Vec::new();
|
||||||
|
for format in config.view_formats.iter() {
|
||||||
|
if *format == config.format {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !caps.formats.contains(&config.format) {
|
||||||
|
break 'error E::UnsupportedFormat {
|
||||||
|
requested: config.format,
|
||||||
|
available: caps.formats,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
|
||||||
|
break 'error E::InvalidViewFormat(*format, config.format);
|
||||||
|
}
|
||||||
|
hal_view_formats.push(*format);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hal_view_formats.is_empty() {
|
||||||
|
if let Err(missing_flag) =
|
||||||
|
self.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS)
|
||||||
|
{
|
||||||
|
break 'error E::MissingDownlevelFlags(missing_flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let maximum_frame_latency = config.desired_maximum_frame_latency.clamp(
|
||||||
|
*caps.maximum_frame_latency.start(),
|
||||||
|
*caps.maximum_frame_latency.end(),
|
||||||
|
);
|
||||||
|
let mut hal_config = hal::SurfaceConfiguration {
|
||||||
|
maximum_frame_latency,
|
||||||
|
present_mode: config.present_mode,
|
||||||
|
composite_alpha_mode: config.alpha_mode,
|
||||||
|
format: config.format,
|
||||||
|
extent: wgt::Extent3d {
|
||||||
|
width: config.width,
|
||||||
|
height: config.height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
usage: conv::map_texture_usage(
|
||||||
|
config.usage,
|
||||||
|
hal::FormatAspects::COLOR,
|
||||||
|
wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY
|
||||||
|
| wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY
|
||||||
|
| wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
|
||||||
|
),
|
||||||
|
view_formats: hal_view_formats,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(error) = validate_surface_configuration(
|
||||||
|
&mut hal_config,
|
||||||
|
&caps,
|
||||||
|
self.limits.max_texture_dimension_2d,
|
||||||
|
) {
|
||||||
|
break 'error error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all work to finish before configuring the surface.
|
||||||
|
let snatch_guard = self.snatchable_lock.read();
|
||||||
|
let fence = self.fence.read();
|
||||||
|
|
||||||
|
let maintain_result;
|
||||||
|
(user_callbacks, maintain_result) =
|
||||||
|
self.maintain(fence, wgt::PollType::wait_indefinitely(), snatch_guard);
|
||||||
|
|
||||||
|
match maintain_result {
|
||||||
|
// We're happy
|
||||||
|
Ok(wgt::PollStatus::QueueEmpty) => {}
|
||||||
|
Ok(wgt::PollStatus::WaitSucceeded) => {
|
||||||
|
// After the wait, the queue should be empty. It can only be non-empty
|
||||||
|
// if another thread is submitting at the same time.
|
||||||
|
break 'error E::GpuWaitTimeout;
|
||||||
|
}
|
||||||
|
Ok(wgt::PollStatus::Poll) => {
|
||||||
|
unreachable!("Cannot get a Poll result from a Wait action.")
|
||||||
|
}
|
||||||
|
Err(WaitIdleError::Timeout) if cfg!(target_arch = "wasm32") => {
|
||||||
|
// On wasm, you cannot actually successfully wait for the surface.
|
||||||
|
// However WebGL does not actually require you do this, so ignoring
|
||||||
|
// the failure is totally fine. See https://github.com/gfx-rs/wgpu/issues/7363
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
break 'error e.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All textures must be destroyed before the surface can be re-configured.
|
||||||
|
if let Some(present) = surface.presentation.lock().take() {
|
||||||
|
if present.acquired_texture.is_some() {
|
||||||
|
break 'error E::PreviousOutputExists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Texture views may still be alive that point to the texture.
|
||||||
|
// this will allow the user to render to the surface texture, long after
|
||||||
|
// it has been removed.
|
||||||
|
//
|
||||||
|
// https://github.com/gfx-rs/wgpu/issues/4105
|
||||||
|
|
||||||
|
let surface_raw = surface.raw(self.backend()).unwrap();
|
||||||
|
match unsafe { surface_raw.configure(self.raw(), &hal_config) } {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(error) => {
|
||||||
|
break 'error match error {
|
||||||
|
hal::SurfaceError::Outdated | hal::SurfaceError::Lost => {
|
||||||
|
E::InvalidSurface
|
||||||
|
}
|
||||||
|
hal::SurfaceError::Device(error) => {
|
||||||
|
E::Device(self.handle_hal_error(error))
|
||||||
|
}
|
||||||
|
hal::SurfaceError::Other(message) => {
|
||||||
|
log::error!("surface configuration failed: {message}");
|
||||||
|
E::InvalidSurface
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut presentation = surface.presentation.lock();
|
||||||
|
*presentation = Some(present::Presentation {
|
||||||
|
device: Arc::clone(self),
|
||||||
|
config: config.clone(),
|
||||||
|
acquired_texture: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
user_callbacks.fire();
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(error)
|
||||||
|
}
|
||||||
|
|
||||||
fn lose(&self, message: &str) {
|
fn lose(&self, message: &str) {
|
||||||
// Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device.
|
// Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user