use alloc::{boxed::Box, string::String, vec, vec::Vec};
#[cfg(wgpu_core)]
use core::ops::Deref;
use core::{error, fmt};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use crate::util::Mutex;
use crate::*;
pub type SurfaceConfiguration = wgt::SurfaceConfiguration<Vec<TextureFormat>>;
static_assertions::assert_impl_all!(SurfaceConfiguration: Send, Sync);
pub struct Surface<'window> {
pub(crate) inner: dispatch::DispatchSurface,
pub(crate) config: Mutex<Option<SurfaceConfiguration>>,
pub(crate) _handle_source: Option<Box<dyn WindowHandle + 'window>>,
}
impl Surface<'_> {
pub fn get_capabilities(&self, adapter: &Adapter) -> SurfaceCapabilities {
self.inner.get_capabilities(&adapter.inner)
}
pub fn get_default_config(
&self,
adapter: &Adapter,
width: u32,
height: u32,
) -> Option<SurfaceConfiguration> {
let caps = self.get_capabilities(adapter);
Some(SurfaceConfiguration {
usage: wgt::TextureUsages::RENDER_ATTACHMENT,
format: *caps.formats.first()?,
width,
height,
desired_maximum_frame_latency: 2,
present_mode: *caps.present_modes.first()?,
alpha_mode: wgt::CompositeAlphaMode::Auto,
view_formats: vec![],
})
}
pub fn configure(&self, device: &Device, config: &SurfaceConfiguration) {
self.inner.configure(&device.inner, config);
let mut conf = self.config.lock();
*conf = Some(config.clone());
}
pub fn get_configuration(&self) -> Option<SurfaceConfiguration> {
self.config.lock().clone()
}
pub fn get_current_texture(&self) -> CurrentSurfaceTexture {
let (texture, status, detail) = self.inner.get_current_texture();
let suboptimal = match status {
SurfaceStatus::Good => false,
SurfaceStatus::Suboptimal => true,
SurfaceStatus::Timeout => return CurrentSurfaceTexture::Timeout,
SurfaceStatus::Occluded => return CurrentSurfaceTexture::Occluded,
SurfaceStatus::Outdated => return CurrentSurfaceTexture::Outdated,
SurfaceStatus::Lost => return CurrentSurfaceTexture::Lost,
SurfaceStatus::Validation => return CurrentSurfaceTexture::Validation,
};
let guard = self.config.lock();
let config = guard
.as_ref()
.expect("This surface has not been configured yet.");
let descriptor = TextureDescriptor {
label: None,
size: Extent3d {
width: config.width,
height: config.height,
depth_or_array_layers: 1,
},
format: config.format,
usage: config.usage,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
view_formats: &[],
};
match texture {
Some(texture) => {
let surface_texture = SurfaceTexture {
texture: Texture {
inner: texture,
descriptor,
},
presented: false,
detail,
};
if suboptimal {
CurrentSurfaceTexture::Suboptimal(surface_texture)
} else {
CurrentSurfaceTexture::Success(surface_texture)
}
}
None => CurrentSurfaceTexture::Lost,
}
}
#[doc = crate::macros::hal_type_vulkan!("Surface")]
#[doc = crate::macros::hal_type_metal!("Surface")]
#[doc = crate::macros::hal_type_dx12!("Surface")]
#[doc = crate::macros::hal_type_gles!("Surface")]
#[cfg(wgpu_core)]
pub unsafe fn as_hal<A: hal::Api>(
&self,
) -> Option<impl Deref<Target = A::Surface> + WasmNotSendSync> {
let core_surface = self.inner.as_core_opt()?;
unsafe { core_surface.context.surface_as_hal::<A>(core_surface) }
}
#[cfg(custom)]
pub fn as_custom<T: custom::SurfaceInterface>(&self) -> Option<&T> {
self.inner.as_custom()
}
}
impl fmt::Debug for Surface<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Surface")
.field(
"_handle_source",
&if self._handle_source.is_some() {
"Some"
} else {
"None"
},
)
.field("inner", &self.inner)
.field("config", &self.config)
.finish()
}
}
#[cfg(send_sync)]
static_assertions::assert_impl_all!(Surface<'_>: Send, Sync);
crate::cmp::impl_eq_ord_hash_proxy!(Surface<'_> => .inner);
pub trait WindowHandle: HasWindowHandle + WasmNotSendSync {}
impl<T: HasWindowHandle + WasmNotSendSync> WindowHandle for T {}
pub trait DisplayAndWindowHandle: WindowHandle + HasDisplayHandle {}
impl<T> DisplayAndWindowHandle for T where T: WindowHandle + HasDisplayHandle {}
#[non_exhaustive]
pub enum SurfaceTarget<'window> {
DisplayAndWindow(Box<dyn DisplayAndWindowHandle + 'window>),
Window(Box<dyn WindowHandle + 'window>),
#[cfg(web)]
Canvas(web_sys::HtmlCanvasElement),
#[cfg(web)]
OffscreenCanvas(web_sys::OffscreenCanvas),
}
impl<'a> SurfaceTarget<'a> {
pub fn from_window_without_display(window: impl WindowHandle + 'a) -> Self {
Self::Window(Box::new(window))
}
}
impl<'a, T> From<T> for SurfaceTarget<'a>
where
T: DisplayAndWindowHandle + 'a,
{
fn from(window: T) -> Self {
Self::DisplayAndWindow(Box::new(window))
}
}
#[non_exhaustive]
pub enum SurfaceTargetUnsafe {
RawHandle {
raw_display_handle: Option<raw_window_handle::RawDisplayHandle>,
raw_window_handle: raw_window_handle::RawWindowHandle,
},
#[cfg(all(unix, not(target_vendor = "apple"), not(target_family = "wasm")))]
Drm {
fd: i32,
plane: u32,
connector_id: u32,
width: u32,
height: u32,
refresh_rate: u32,
},
#[cfg(metal)]
CoreAnimationLayer(*mut core::ffi::c_void),
#[cfg(dx12)]
CompositionVisual(*mut core::ffi::c_void),
#[cfg(dx12)]
SurfaceHandle(*mut core::ffi::c_void),
#[cfg(dx12)]
SwapChainPanel(*mut core::ffi::c_void),
}
impl SurfaceTargetUnsafe {
pub unsafe fn from_display_and_window(
display: &impl HasDisplayHandle,
window: &impl HasWindowHandle,
) -> Result<Self, raw_window_handle::HandleError> {
Ok(Self::RawHandle {
raw_display_handle: Some(display.display_handle()?.as_raw()),
raw_window_handle: window.window_handle()?.as_raw(),
})
}
pub unsafe fn from_window(
window: &impl HasWindowHandle,
) -> Result<Self, raw_window_handle::HandleError> {
Ok(Self::RawHandle {
raw_display_handle: None,
raw_window_handle: window.window_handle()?.as_raw(),
})
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct CreateSurfaceError {
pub(crate) inner: CreateSurfaceErrorKind,
}
#[derive(Clone, Debug)]
pub(crate) enum CreateSurfaceErrorKind {
#[cfg(wgpu_core)]
Hal(wgc::instance::CreateSurfaceError),
#[cfg_attr(not(webgpu), expect(dead_code))]
Web(String),
RawHandle(raw_window_handle::HandleError),
}
static_assertions::assert_impl_all!(CreateSurfaceError: Send, Sync);
impl fmt::Display for CreateSurfaceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
#[cfg(wgpu_core)]
CreateSurfaceErrorKind::Hal(e) => e.fmt(f),
CreateSurfaceErrorKind::Web(e) => e.fmt(f),
CreateSurfaceErrorKind::RawHandle(e) => e.fmt(f),
}
}
}
impl error::Error for CreateSurfaceError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self.inner {
#[cfg(wgpu_core)]
CreateSurfaceErrorKind::Hal(e) => e.source(),
CreateSurfaceErrorKind::Web(_) => None,
#[cfg(feature = "std")]
CreateSurfaceErrorKind::RawHandle(e) => e.source(),
#[cfg(not(feature = "std"))]
CreateSurfaceErrorKind::RawHandle(_) => None,
}
}
}
#[cfg(wgpu_core)]
impl From<wgc::instance::CreateSurfaceError> for CreateSurfaceError {
fn from(e: wgc::instance::CreateSurfaceError) -> Self {
Self {
inner: CreateSurfaceErrorKind::Hal(e),
}
}
}