mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
Fix surfaces only compatible with first enabled backend (#5535)
This commit is contained in:
parent
ea77d5674d
commit
cbace631ec
@ -153,6 +153,7 @@ Bottom level categories:
|
||||
- Failing to set the device lost closure will call the closure before returning. By @bradwerth in [#5358](https://github.com/gfx-rs/wgpu/pull/5358).
|
||||
- Use memory pooling for UsageScopes to avoid frequent large allocations. by @robtfm in [#5414](https://github.com/gfx-rs/wgpu/pull/5414)
|
||||
- Fix deadlocks caused by recursive read-write lock acquisitions [#5426](https://github.com/gfx-rs/wgpu/pull/5426).
|
||||
- Fix surfaces being only compatible with first backend enabled on an instance, causing failures when manually specifying an adapter. By @Wumpf in [#5535](https://github.com/gfx-rs/wgpu/pull/5535).
|
||||
|
||||
#### Naga
|
||||
- In spv-in, remove unnecessary "gl_PerVertex" name check so unused builtins will always be skipped. By @Imberflur in [#5227](https://github.com/gfx-rs/wgpu/pull/5227).
|
||||
|
@ -1,95 +0,0 @@
|
||||
use wgt::Backend;
|
||||
|
||||
/// The `AnySurface` type: a `Arc` of a `A::Surface` for any backend `A`.
|
||||
use crate::hal_api::HalApi;
|
||||
|
||||
use std::fmt;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
struct AnySurfaceVtable {
|
||||
// We oppurtunistically store the backend here, since we now it will be used
|
||||
// with backend selection and it can be stored in static memory.
|
||||
backend: Backend,
|
||||
// Drop glue which knows how to drop the stored data.
|
||||
drop: unsafe fn(*mut ()),
|
||||
}
|
||||
|
||||
/// An `A::Surface`, for any backend `A`.
|
||||
///
|
||||
/// Any `AnySurface` is just like an `A::Surface`, except that the `A` type
|
||||
/// parameter is erased. To access the `Surface`, you must downcast to a
|
||||
/// particular backend with the \[`downcast_ref`\] or \[`take`\] methods.
|
||||
pub struct AnySurface {
|
||||
data: NonNull<()>,
|
||||
vtable: &'static AnySurfaceVtable,
|
||||
}
|
||||
|
||||
impl AnySurface {
|
||||
/// Construct an `AnySurface` that owns an `A::Surface`.
|
||||
pub fn new<A: HalApi>(surface: A::Surface) -> AnySurface {
|
||||
unsafe fn drop_glue<A: HalApi>(ptr: *mut ()) {
|
||||
unsafe {
|
||||
_ = Box::from_raw(ptr.cast::<A::Surface>());
|
||||
}
|
||||
}
|
||||
|
||||
let data = NonNull::from(Box::leak(Box::new(surface)));
|
||||
|
||||
AnySurface {
|
||||
data: data.cast(),
|
||||
vtable: &AnySurfaceVtable {
|
||||
backend: A::VARIANT,
|
||||
drop: drop_glue::<A>,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the backend this surface was created through.
|
||||
pub fn backend(&self) -> Backend {
|
||||
self.vtable.backend
|
||||
}
|
||||
|
||||
/// If `self` refers to an `A::Surface`, returns a reference to it.
|
||||
pub fn downcast_ref<A: HalApi>(&self) -> Option<&A::Surface> {
|
||||
if A::VARIANT != self.vtable.backend {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: We just checked the instance above implicitly by the backend
|
||||
// that it was statically constructed through.
|
||||
Some(unsafe { &*self.data.as_ptr().cast::<A::Surface>() })
|
||||
}
|
||||
|
||||
/// If `self` is an `Arc<A::Surface>`, returns that.
|
||||
pub fn take<A: HalApi>(self) -> Option<A::Surface> {
|
||||
if A::VARIANT != self.vtable.backend {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Disable drop glue, since we're returning the owned surface. The
|
||||
// caller will be responsible for dropping it.
|
||||
let this = ManuallyDrop::new(self);
|
||||
|
||||
// SAFETY: We just checked the instance above implicitly by the backend
|
||||
// that it was statically constructed through.
|
||||
Some(unsafe { *Box::from_raw(this.data.as_ptr().cast::<A::Surface>()) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AnySurface {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (self.vtable.drop)(self.data.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AnySurface {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "AnySurface<{}>", self.vtable.backend)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl Send for AnySurface {}
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl Sync for AnySurface {}
|
@ -1969,7 +1969,7 @@ impl Global {
|
||||
};
|
||||
|
||||
let caps = unsafe {
|
||||
let suf = A::get_surface(surface);
|
||||
let suf = A::surface_as_hal(surface);
|
||||
let adapter = &device.adapter;
|
||||
match adapter.raw.adapter.surface_capabilities(suf.unwrap()) {
|
||||
Some(caps) => caps,
|
||||
@ -2055,7 +2055,7 @@ impl Global {
|
||||
// https://github.com/gfx-rs/wgpu/issues/4105
|
||||
|
||||
match unsafe {
|
||||
A::get_surface(surface)
|
||||
A::surface_as_hal(surface)
|
||||
.unwrap()
|
||||
.configure(device.raw(), &hal_config)
|
||||
} {
|
||||
|
@ -11,7 +11,7 @@ pub trait HalApi: hal::Api + 'static + WasmNotSendSync {
|
||||
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance;
|
||||
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>;
|
||||
fn hub(global: &Global) -> &Hub<Self>;
|
||||
fn get_surface(surface: &Surface) -> Option<&Self::Surface>;
|
||||
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface>;
|
||||
}
|
||||
|
||||
impl HalApi for hal::api::Empty {
|
||||
@ -25,7 +25,7 @@ impl HalApi for hal::api::Empty {
|
||||
fn hub(_: &Global) -> &Hub<Self> {
|
||||
unimplemented!("called empty api")
|
||||
}
|
||||
fn get_surface(_: &Surface) -> Option<&Self::Surface> {
|
||||
fn surface_as_hal(_: &Surface) -> Option<&Self::Surface> {
|
||||
unimplemented!("called empty api")
|
||||
}
|
||||
}
|
||||
@ -46,8 +46,8 @@ impl HalApi for hal::api::Vulkan {
|
||||
fn hub(global: &Global) -> &Hub<Self> {
|
||||
&global.hubs.vulkan
|
||||
}
|
||||
fn get_surface(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.raw.downcast_ref::<Self>()
|
||||
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.vulkan.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,8 +67,8 @@ impl HalApi for hal::api::Metal {
|
||||
fn hub(global: &Global) -> &Hub<Self> {
|
||||
&global.hubs.metal
|
||||
}
|
||||
fn get_surface(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.raw.downcast_ref::<Self>()
|
||||
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.metal.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,8 +88,8 @@ impl HalApi for hal::api::Dx12 {
|
||||
fn hub(global: &Global) -> &Hub<Self> {
|
||||
&global.hubs.dx12
|
||||
}
|
||||
fn get_surface(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.raw.downcast_ref::<Self>()
|
||||
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.dx12.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ impl HalApi for hal::api::Gles {
|
||||
fn hub(global: &Global) -> &Hub<Self> {
|
||||
&global.hubs.gl
|
||||
}
|
||||
fn get_surface(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.raw.downcast_ref::<Self>()
|
||||
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
|
||||
surface.gl.as_ref()
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ impl<A: HalApi> Hub<A> {
|
||||
if let Element::Occupied(ref surface, _epoch) = *element {
|
||||
if let Some(ref mut present) = surface.presentation.lock().take() {
|
||||
if let Some(device) = present.device.downcast_ref::<A>() {
|
||||
let suf = A::get_surface(surface);
|
||||
let suf = A::surface_as_hal(surface);
|
||||
unsafe {
|
||||
suf.unwrap().unconfigure(device.raw());
|
||||
//TODO: we could destroy the surface here
|
||||
|
@ -1,13 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
any_surface::AnySurface,
|
||||
api_log,
|
||||
device::{queue::Queue, resource::Device, DeviceDescriptor},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
id::markers,
|
||||
id::{AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId},
|
||||
id::{markers, AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId},
|
||||
present::Presentation,
|
||||
resource::{Resource, ResourceInfo, ResourceType},
|
||||
resource_log, LabelHelpers, DOWNLEVEL_WARNING_MESSAGE,
|
||||
@ -21,6 +20,7 @@ use thiserror::Error;
|
||||
|
||||
pub type RequestAdapterOptions = wgt::RequestAdapterOptions<SurfaceId>;
|
||||
type HalInstance<A> = <A as hal::Api>::Instance;
|
||||
type HalSurface<A> = <A as hal::Api>::Surface;
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("Limit '{name}' value {requested} is better than allowed {allowed}")]
|
||||
@ -113,31 +113,36 @@ impl Instance {
|
||||
}
|
||||
|
||||
pub(crate) fn destroy_surface(&self, surface: Surface) {
|
||||
fn destroy<A: HalApi>(instance: &Option<A::Instance>, surface: AnySurface) {
|
||||
unsafe {
|
||||
if let Some(suf) = surface.take::<A>() {
|
||||
instance.as_ref().unwrap().destroy_surface(suf);
|
||||
fn destroy<A: HalApi>(instance: &Option<A::Instance>, mut surface: Option<HalSurface<A>>) {
|
||||
if let Some(surface) = surface.take() {
|
||||
unsafe {
|
||||
instance.as_ref().unwrap().destroy_surface(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
match surface.raw.backend() {
|
||||
#[cfg(vulkan)]
|
||||
Backend::Vulkan => destroy::<hal::api::Vulkan>(&self.vulkan, surface.raw),
|
||||
#[cfg(metal)]
|
||||
Backend::Metal => destroy::<hal::api::Metal>(&self.metal, surface.raw),
|
||||
#[cfg(dx12)]
|
||||
Backend::Dx12 => destroy::<hal::api::Dx12>(&self.dx12, surface.raw),
|
||||
#[cfg(gles)]
|
||||
Backend::Gl => destroy::<hal::api::Gles>(&self.gl, surface.raw),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
#[cfg(vulkan)]
|
||||
destroy::<hal::api::Vulkan>(&self.vulkan, surface.vulkan);
|
||||
#[cfg(metal)]
|
||||
destroy::<hal::api::Metal>(&self.metal, surface.metal);
|
||||
#[cfg(dx12)]
|
||||
destroy::<hal::api::Dx12>(&self.dx12, surface.dx12);
|
||||
#[cfg(gles)]
|
||||
destroy::<hal::api::Gles>(&self.gl, surface.gl);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Surface {
|
||||
pub(crate) presentation: Mutex<Option<Presentation>>,
|
||||
pub(crate) info: ResourceInfo<Surface>,
|
||||
pub(crate) raw: AnySurface,
|
||||
|
||||
#[cfg(vulkan)]
|
||||
pub vulkan: Option<HalSurface<hal::api::Vulkan>>,
|
||||
#[cfg(metal)]
|
||||
pub metal: Option<HalSurface<hal::api::Metal>>,
|
||||
#[cfg(dx12)]
|
||||
pub dx12: Option<HalSurface<hal::api::Dx12>>,
|
||||
#[cfg(gles)]
|
||||
pub gl: Option<HalSurface<hal::api::Gles>>,
|
||||
}
|
||||
|
||||
impl Resource for Surface {
|
||||
@ -163,7 +168,7 @@ impl Surface {
|
||||
&self,
|
||||
adapter: &Adapter<A>,
|
||||
) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
|
||||
let suf = A::get_surface(self).ok_or(GetSurfaceSupportError::Unsupported)?;
|
||||
let suf = A::surface_as_hal(self).ok_or(GetSurfaceSupportError::Unsupported)?;
|
||||
profiling::scope!("surface_capabilities");
|
||||
let caps = unsafe {
|
||||
adapter
|
||||
@ -203,7 +208,7 @@ impl<A: HalApi> Adapter<A> {
|
||||
}
|
||||
|
||||
pub fn is_surface_supported(&self, surface: &Surface) -> bool {
|
||||
let suf = A::get_surface(surface);
|
||||
let suf = A::surface_as_hal(surface);
|
||||
|
||||
// If get_surface returns None, then the API does not advertise support for the surface.
|
||||
//
|
||||
@ -461,13 +466,25 @@ pub enum RequestAdapterError {
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum CreateSurfaceError {
|
||||
#[error("No backend is available")]
|
||||
NoSupportedBackend,
|
||||
#[error(transparent)]
|
||||
InstanceError(#[from] hal::InstanceError),
|
||||
#[error("The backend {0} was not enabled on the instance.")]
|
||||
BackendNotEnabled(Backend),
|
||||
#[error("Failed to create surface for any enabled backend: {0:?}")]
|
||||
FailedToCreateSurfaceForAnyBackend(HashMap<Backend, hal::InstanceError>),
|
||||
}
|
||||
|
||||
impl Global {
|
||||
/// Creates a new surface targeting the given display/window handles.
|
||||
///
|
||||
/// Internally attempts to create hal surfaces for all enabled backends.
|
||||
///
|
||||
/// Fails only if creation for surfaces for all enabled backends fails in which case
|
||||
/// the error for each enabled backend is listed.
|
||||
/// Vice versa, if creation for any backend succeeds, success is returned.
|
||||
/// Surface creation errors are logged to the debug log in any case.
|
||||
///
|
||||
/// id_in:
|
||||
/// - If `Some`, the id to assign to the surface. A new one will be generated otherwise.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `display_handle` must be a valid object to create a surface upon.
|
||||
@ -483,51 +500,86 @@ impl Global {
|
||||
profiling::scope!("Instance::create_surface");
|
||||
|
||||
fn init<A: HalApi>(
|
||||
errors: &mut HashMap<Backend, hal::InstanceError>,
|
||||
any_created: &mut bool,
|
||||
backend: Backend,
|
||||
inst: &Option<A::Instance>,
|
||||
display_handle: raw_window_handle::RawDisplayHandle,
|
||||
window_handle: raw_window_handle::RawWindowHandle,
|
||||
) -> Option<Result<AnySurface, hal::InstanceError>> {
|
||||
inst.as_ref().map(|inst| unsafe {
|
||||
match inst.create_surface(display_handle, window_handle) {
|
||||
Ok(raw) => Ok(AnySurface::new::<A>(raw)),
|
||||
Err(e) => Err(e),
|
||||
) -> Option<HalSurface<A>> {
|
||||
inst.as_ref().and_then(|inst| {
|
||||
match unsafe { inst.create_surface(display_handle, window_handle) } {
|
||||
Ok(raw) => {
|
||||
*any_created = true;
|
||||
Some(raw)
|
||||
}
|
||||
Err(err) => {
|
||||
log::debug!(
|
||||
"Instance::create_surface: failed to create surface for {:?}: {:?}",
|
||||
backend,
|
||||
err
|
||||
);
|
||||
errors.insert(backend, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let mut hal_surface: Option<Result<AnySurface, hal::InstanceError>> = None;
|
||||
|
||||
#[cfg(vulkan)]
|
||||
if hal_surface.is_none() {
|
||||
hal_surface =
|
||||
init::<hal::api::Vulkan>(&self.instance.vulkan, display_handle, window_handle);
|
||||
}
|
||||
#[cfg(metal)]
|
||||
if hal_surface.is_none() {
|
||||
hal_surface =
|
||||
init::<hal::api::Metal>(&self.instance.metal, display_handle, window_handle);
|
||||
}
|
||||
#[cfg(dx12)]
|
||||
if hal_surface.is_none() {
|
||||
hal_surface =
|
||||
init::<hal::api::Dx12>(&self.instance.dx12, display_handle, window_handle);
|
||||
}
|
||||
#[cfg(gles)]
|
||||
if hal_surface.is_none() {
|
||||
hal_surface = init::<hal::api::Gles>(&self.instance.gl, display_handle, window_handle);
|
||||
}
|
||||
|
||||
let hal_surface = hal_surface.ok_or(CreateSurfaceError::NoSupportedBackend)??;
|
||||
let mut errors = HashMap::default();
|
||||
let mut any_created = false;
|
||||
|
||||
let surface = Surface {
|
||||
presentation: Mutex::new(None),
|
||||
info: ResourceInfo::new("<Surface>", None),
|
||||
raw: hal_surface,
|
||||
|
||||
#[cfg(vulkan)]
|
||||
vulkan: init::<hal::api::Vulkan>(
|
||||
&mut errors,
|
||||
&mut any_created,
|
||||
Backend::Vulkan,
|
||||
&self.instance.vulkan,
|
||||
display_handle,
|
||||
window_handle,
|
||||
),
|
||||
#[cfg(metal)]
|
||||
metal: init::<hal::api::Metal>(
|
||||
&mut errors,
|
||||
&mut any_created,
|
||||
Backend::Metal,
|
||||
&self.instance.metal,
|
||||
display_handle,
|
||||
window_handle,
|
||||
),
|
||||
#[cfg(dx12)]
|
||||
dx12: init::<hal::api::Dx12>(
|
||||
&mut errors,
|
||||
&mut any_created,
|
||||
Backend::Dx12,
|
||||
&self.instance.dx12,
|
||||
display_handle,
|
||||
window_handle,
|
||||
),
|
||||
#[cfg(gles)]
|
||||
gl: init::<hal::api::Gles>(
|
||||
&mut errors,
|
||||
&mut any_created,
|
||||
Backend::Gl,
|
||||
&self.instance.gl,
|
||||
display_handle,
|
||||
window_handle,
|
||||
),
|
||||
};
|
||||
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
Ok(id)
|
||||
if any_created {
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
Ok(id)
|
||||
} else {
|
||||
Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
|
||||
errors,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@ -538,29 +590,57 @@ impl Global {
|
||||
&self,
|
||||
layer: *mut std::ffi::c_void,
|
||||
id_in: Option<SurfaceId>,
|
||||
) -> SurfaceId {
|
||||
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||
profiling::scope!("Instance::create_surface_metal");
|
||||
|
||||
let surface = Surface {
|
||||
presentation: Mutex::new(None),
|
||||
info: ResourceInfo::new("<Surface>", None),
|
||||
raw: {
|
||||
let hal_surface = self
|
||||
.instance
|
||||
.metal
|
||||
.as_ref()
|
||||
.map(|inst| {
|
||||
// we don't want to link to metal-rs for this
|
||||
#[allow(clippy::transmute_ptr_to_ref)]
|
||||
inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) })
|
||||
})
|
||||
.unwrap();
|
||||
AnySurface::new::<hal::api::Metal>(hal_surface)
|
||||
},
|
||||
metal: Some(self.instance.metal.as_ref().map_or(
|
||||
Err(CreateSurfaceError::BackendNotEnabled(Backend::Metal)),
|
||||
|inst| {
|
||||
// we don't want to link to metal-rs for this
|
||||
#[allow(clippy::transmute_ptr_to_ref)]
|
||||
Ok(inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }))
|
||||
},
|
||||
)?),
|
||||
#[cfg(dx12)]
|
||||
dx12: None,
|
||||
#[cfg(vulkan)]
|
||||
vulkan: None,
|
||||
#[cfg(gles)]
|
||||
gl: None,
|
||||
};
|
||||
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
id
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[cfg(dx12)]
|
||||
fn instance_create_surface_dx12(
|
||||
&self,
|
||||
id_in: Option<SurfaceId>,
|
||||
create_surface_func: impl FnOnce(&HalInstance<hal::api::Dx12>) -> HalSurface<hal::api::Dx12>,
|
||||
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||
let surface = Surface {
|
||||
presentation: Mutex::new(None),
|
||||
info: ResourceInfo::new("<Surface>", None),
|
||||
dx12: Some(create_surface_func(
|
||||
self.instance
|
||||
.dx12
|
||||
.as_ref()
|
||||
.ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?,
|
||||
)),
|
||||
#[cfg(metal)]
|
||||
metal: None,
|
||||
#[cfg(vulkan)]
|
||||
vulkan: None,
|
||||
#[cfg(gles)]
|
||||
gl: None,
|
||||
};
|
||||
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[cfg(dx12)]
|
||||
@ -571,25 +651,11 @@ impl Global {
|
||||
&self,
|
||||
visual: *mut std::ffi::c_void,
|
||||
id_in: Option<SurfaceId>,
|
||||
) -> SurfaceId {
|
||||
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||
profiling::scope!("Instance::instance_create_surface_from_visual");
|
||||
|
||||
let surface = Surface {
|
||||
presentation: Mutex::new(None),
|
||||
info: ResourceInfo::new("<Surface>", None),
|
||||
raw: {
|
||||
let hal_surface = self
|
||||
.instance
|
||||
.dx12
|
||||
.as_ref()
|
||||
.map(|inst| unsafe { inst.create_surface_from_visual(visual as _) })
|
||||
.unwrap();
|
||||
AnySurface::new::<hal::api::Dx12>(hal_surface)
|
||||
},
|
||||
};
|
||||
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
id
|
||||
self.instance_create_surface_dx12(id_in, |inst| unsafe {
|
||||
inst.create_surface_from_visual(visual as _)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(dx12)]
|
||||
@ -600,25 +666,11 @@ impl Global {
|
||||
&self,
|
||||
surface_handle: *mut std::ffi::c_void,
|
||||
id_in: Option<SurfaceId>,
|
||||
) -> SurfaceId {
|
||||
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||
profiling::scope!("Instance::instance_create_surface_from_surface_handle");
|
||||
|
||||
let surface = Surface {
|
||||
presentation: Mutex::new(None),
|
||||
info: ResourceInfo::new("<Surface>", None),
|
||||
raw: {
|
||||
let hal_surface = self
|
||||
.instance
|
||||
.dx12
|
||||
.as_ref()
|
||||
.map(|inst| unsafe { inst.create_surface_from_surface_handle(surface_handle) })
|
||||
.unwrap();
|
||||
AnySurface::new::<hal::api::Dx12>(hal_surface)
|
||||
},
|
||||
};
|
||||
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
id
|
||||
self.instance_create_surface_dx12(id_in, |inst| unsafe {
|
||||
inst.create_surface_from_surface_handle(surface_handle)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(dx12)]
|
||||
@ -629,27 +681,11 @@ impl Global {
|
||||
&self,
|
||||
swap_chain_panel: *mut std::ffi::c_void,
|
||||
id_in: Option<SurfaceId>,
|
||||
) -> SurfaceId {
|
||||
) -> Result<SurfaceId, CreateSurfaceError> {
|
||||
profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
|
||||
|
||||
let surface = Surface {
|
||||
presentation: Mutex::new(None),
|
||||
info: ResourceInfo::new("<Surface>", None),
|
||||
raw: {
|
||||
let hal_surface = self
|
||||
.instance
|
||||
.dx12
|
||||
.as_ref()
|
||||
.map(|inst| unsafe {
|
||||
inst.create_surface_from_swap_chain_panel(swap_chain_panel as _)
|
||||
})
|
||||
.unwrap();
|
||||
AnySurface::new::<hal::api::Dx12>(hal_surface)
|
||||
},
|
||||
};
|
||||
|
||||
let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface));
|
||||
id
|
||||
self.instance_create_surface_dx12(id_in, |inst| unsafe {
|
||||
inst.create_surface_from_swap_chain_panel(swap_chain_panel as _)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn surface_drop(&self, id: SurfaceId) {
|
||||
@ -657,11 +693,15 @@ impl Global {
|
||||
|
||||
api_log!("Surface::drop {id:?}");
|
||||
|
||||
fn unconfigure<A: HalApi>(global: &Global, surface: &AnySurface, present: &Presentation) {
|
||||
let hub = HalApi::hub(global);
|
||||
if let Some(hal_surface) = surface.downcast_ref::<A>() {
|
||||
fn unconfigure<A: HalApi>(
|
||||
global: &Global,
|
||||
surface: &Option<HalSurface<A>>,
|
||||
present: &Presentation,
|
||||
) {
|
||||
if let Some(surface) = surface {
|
||||
let hub = HalApi::hub(global);
|
||||
if let Some(device) = present.device.downcast_ref::<A>() {
|
||||
hub.surface_unconfigure(device, hal_surface);
|
||||
hub.surface_unconfigure(device, surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -669,15 +709,16 @@ impl Global {
|
||||
let surface = self.surfaces.unregister(id);
|
||||
let surface = Arc::into_inner(surface.unwrap())
|
||||
.expect("Surface cannot be destroyed because is still in use");
|
||||
|
||||
if let Some(present) = surface.presentation.lock().take() {
|
||||
#[cfg(vulkan)]
|
||||
unconfigure::<hal::api::Vulkan>(self, &surface.raw, &present);
|
||||
unconfigure::<hal::api::Vulkan>(self, &surface.vulkan, &present);
|
||||
#[cfg(metal)]
|
||||
unconfigure::<hal::api::Metal>(self, &surface.raw, &present);
|
||||
unconfigure::<hal::api::Metal>(self, &surface.metal, &present);
|
||||
#[cfg(dx12)]
|
||||
unconfigure::<hal::api::Dx12>(self, &surface.raw, &present);
|
||||
unconfigure::<hal::api::Dx12>(self, &surface.dx12, &present);
|
||||
#[cfg(gles)]
|
||||
unconfigure::<hal::api::Gles>(self, &surface.raw, &present);
|
||||
unconfigure::<hal::api::Gles>(self, &surface.gl, &present);
|
||||
}
|
||||
self.instance.destroy_surface(surface);
|
||||
}
|
||||
@ -785,7 +826,7 @@ impl Global {
|
||||
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
|
||||
}
|
||||
if let Some(surface) = compatible_surface {
|
||||
let surface = &A::get_surface(surface);
|
||||
let surface = &A::surface_as_hal(surface);
|
||||
adapters.retain(|exposed| unsafe {
|
||||
// If the surface does not exist for this backend,
|
||||
// then the surface is not supported.
|
||||
|
@ -50,7 +50,6 @@
|
||||
unused_qualifications
|
||||
)]
|
||||
|
||||
pub mod any_surface;
|
||||
pub mod binding_model;
|
||||
pub mod command;
|
||||
mod conv;
|
||||
|
@ -157,7 +157,7 @@ impl Global {
|
||||
#[cfg(not(feature = "trace"))]
|
||||
let _ = device;
|
||||
|
||||
let suf = A::get_surface(surface.as_ref());
|
||||
let suf = A::surface_as_hal(surface.as_ref());
|
||||
let (texture_id, status) = match unsafe {
|
||||
suf.unwrap()
|
||||
.acquire_texture(Some(std::time::Duration::from_millis(
|
||||
@ -324,7 +324,7 @@ impl Global {
|
||||
.textures
|
||||
.remove(texture.info.tracker_index());
|
||||
let mut exclusive_snatch_guard = device.snatchable_lock.write();
|
||||
let suf = A::get_surface(&surface);
|
||||
let suf = A::surface_as_hal(&surface);
|
||||
let mut inner = texture.inner_mut(&mut exclusive_snatch_guard);
|
||||
let inner = inner.as_mut().unwrap();
|
||||
|
||||
@ -418,7 +418,7 @@ impl Global {
|
||||
.lock()
|
||||
.textures
|
||||
.remove(texture.info.tracker_index());
|
||||
let suf = A::get_surface(&surface);
|
||||
let suf = A::surface_as_hal(&surface);
|
||||
let exclusive_snatch_guard = device.snatchable_lock.write();
|
||||
match texture.inner.snatch(exclusive_snatch_guard).unwrap() {
|
||||
resource::TextureInner::Surface { mut raw, parent_id } => {
|
||||
|
@ -1023,7 +1023,9 @@ impl Global {
|
||||
profiling::scope!("Surface::as_hal");
|
||||
|
||||
let surface = self.surfaces.get(id).ok();
|
||||
let hal_surface = surface.as_ref().and_then(|surface| A::get_surface(surface));
|
||||
let hal_surface = surface
|
||||
.as_ref()
|
||||
.and_then(|surface| A::surface_as_hal(surface));
|
||||
|
||||
hal_surface_callback(hal_surface)
|
||||
}
|
||||
|
@ -554,7 +554,7 @@ impl crate::Context for ContextWgpuCore {
|
||||
raw_window_handle,
|
||||
} => unsafe {
|
||||
self.0
|
||||
.instance_create_surface(raw_display_handle, raw_window_handle, None)?
|
||||
.instance_create_surface(raw_display_handle, raw_window_handle, None)
|
||||
},
|
||||
|
||||
#[cfg(metal)]
|
||||
@ -578,7 +578,7 @@ impl crate::Context for ContextWgpuCore {
|
||||
self.0
|
||||
.instance_create_surface_from_swap_chain_panel(swap_chain_panel, None)
|
||||
},
|
||||
};
|
||||
}?;
|
||||
|
||||
Ok((
|
||||
id,
|
||||
|
@ -366,9 +366,19 @@ static_assertions::assert_impl_all!(SurfaceConfiguration: Send, Sync);
|
||||
/// serves a similar role.
|
||||
pub struct Surface<'window> {
|
||||
context: Arc<C>,
|
||||
_surface: Option<Box<dyn WindowHandle + 'window>>,
|
||||
|
||||
/// Optionally, keep the source of the handle used for the surface alive.
|
||||
///
|
||||
/// This is useful for platforms where the surface is created from a window and the surface
|
||||
/// would become invalid when the window is dropped.
|
||||
_handle_source: Option<Box<dyn WindowHandle + 'window>>,
|
||||
|
||||
/// Wgpu-core surface id.
|
||||
id: ObjectId,
|
||||
data: Box<Data>,
|
||||
|
||||
/// Additional surface data returned by [`DynContext::instance_create_surface`].
|
||||
surface_data: Box<Data>,
|
||||
|
||||
// Stores the latest `SurfaceConfiguration` that was set using `Surface::configure`.
|
||||
// It is required to set the attributes of the `SurfaceTexture` in the
|
||||
// `Surface::get_current_texture` method.
|
||||
@ -385,15 +395,15 @@ impl<'window> fmt::Debug for Surface<'window> {
|
||||
f.debug_struct("Surface")
|
||||
.field("context", &self.context)
|
||||
.field(
|
||||
"_surface",
|
||||
&if self._surface.is_some() {
|
||||
"_handle_source",
|
||||
&if self._handle_source.is_some() {
|
||||
"Some"
|
||||
} else {
|
||||
"None"
|
||||
},
|
||||
)
|
||||
.field("id", &self.id)
|
||||
.field("data", &self.data)
|
||||
.field("data", &self.surface_data)
|
||||
.field("config", &self.config)
|
||||
.finish()
|
||||
}
|
||||
@ -405,7 +415,8 @@ static_assertions::assert_impl_all!(Surface<'_>: Send, Sync);
|
||||
impl Drop for Surface<'_> {
|
||||
fn drop(&mut self) {
|
||||
if !thread::panicking() {
|
||||
self.context.surface_drop(&self.id, self.data.as_ref())
|
||||
self.context
|
||||
.surface_drop(&self.id, self.surface_data.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1967,6 +1978,8 @@ impl Instance {
|
||||
|
||||
/// Creates a new surface targeting a given window/canvas/surface/etc..
|
||||
///
|
||||
/// Internally, this creates surfaces for all backends that are enabled for this instance.
|
||||
///
|
||||
/// See [`SurfaceTarget`] for what targets are supported.
|
||||
/// See [`Instance::create_surface_unsafe`] for surface creation with unsafe target variants.
|
||||
///
|
||||
@ -1977,7 +1990,7 @@ impl Instance {
|
||||
target: impl Into<SurfaceTarget<'window>>,
|
||||
) -> Result<Surface<'window>, CreateSurfaceError> {
|
||||
// Handle origin (i.e. window) to optionally take ownership of to make the surface outlast the window.
|
||||
let handle_origin;
|
||||
let handle_source;
|
||||
|
||||
let target = target.into();
|
||||
let mut surface = match target {
|
||||
@ -1987,14 +2000,14 @@ impl Instance {
|
||||
inner: CreateSurfaceErrorKind::RawHandle(e),
|
||||
})?,
|
||||
);
|
||||
handle_origin = Some(window);
|
||||
handle_source = Some(window);
|
||||
|
||||
surface
|
||||
}?,
|
||||
|
||||
#[cfg(any(webgpu, webgl))]
|
||||
SurfaceTarget::Canvas(canvas) => {
|
||||
handle_origin = None;
|
||||
handle_source = None;
|
||||
|
||||
let value: &wasm_bindgen::JsValue = &canvas;
|
||||
let obj = std::ptr::NonNull::from(value).cast();
|
||||
@ -2013,7 +2026,7 @@ impl Instance {
|
||||
|
||||
#[cfg(any(webgpu, webgl))]
|
||||
SurfaceTarget::OffscreenCanvas(canvas) => {
|
||||
handle_origin = None;
|
||||
handle_source = None;
|
||||
|
||||
let value: &wasm_bindgen::JsValue = &canvas;
|
||||
let obj = std::ptr::NonNull::from(value).cast();
|
||||
@ -2032,13 +2045,15 @@ impl Instance {
|
||||
}
|
||||
};
|
||||
|
||||
surface._surface = handle_origin;
|
||||
surface._handle_source = handle_source;
|
||||
|
||||
Ok(surface)
|
||||
}
|
||||
|
||||
/// Creates a new surface targeting a given window/canvas/surface/etc. using an unsafe target.
|
||||
///
|
||||
/// Internally, this creates surfaces for all backends that are enabled for this instance.
|
||||
///
|
||||
/// See [`SurfaceTargetUnsafe`] for what targets are supported.
|
||||
/// See [`Instance::create_surface`] for surface creation with safe target variants.
|
||||
///
|
||||
@ -2053,9 +2068,9 @@ impl Instance {
|
||||
|
||||
Ok(Surface {
|
||||
context: Arc::clone(&self.context),
|
||||
_surface: None,
|
||||
_handle_source: None,
|
||||
id,
|
||||
data,
|
||||
surface_data: data,
|
||||
config: Mutex::new(None),
|
||||
})
|
||||
}
|
||||
@ -2229,7 +2244,7 @@ impl Adapter {
|
||||
&self.id,
|
||||
self.data.as_ref(),
|
||||
&surface.id,
|
||||
surface.data.as_ref(),
|
||||
surface.surface_data.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -4833,7 +4848,7 @@ impl Surface<'_> {
|
||||
DynContext::surface_get_capabilities(
|
||||
&*self.context,
|
||||
&self.id,
|
||||
self.data.as_ref(),
|
||||
self.surface_data.as_ref(),
|
||||
&adapter.id,
|
||||
adapter.data.as_ref(),
|
||||
)
|
||||
@ -4872,7 +4887,7 @@ impl Surface<'_> {
|
||||
DynContext::surface_configure(
|
||||
&*self.context,
|
||||
&self.id,
|
||||
self.data.as_ref(),
|
||||
self.surface_data.as_ref(),
|
||||
&device.id,
|
||||
device.data.as_ref(),
|
||||
config,
|
||||
@ -4891,8 +4906,11 @@ impl Surface<'_> {
|
||||
/// If a SurfaceTexture referencing this surface is alive when the swapchain is recreated,
|
||||
/// recreating the swapchain will panic.
|
||||
pub fn get_current_texture(&self) -> Result<SurfaceTexture, SurfaceError> {
|
||||
let (texture_id, texture_data, status, detail) =
|
||||
DynContext::surface_get_current_texture(&*self.context, &self.id, self.data.as_ref());
|
||||
let (texture_id, texture_data, status, detail) = DynContext::surface_get_current_texture(
|
||||
&*self.context,
|
||||
&self.id,
|
||||
self.surface_data.as_ref(),
|
||||
);
|
||||
|
||||
let suboptimal = match status {
|
||||
SurfaceStatus::Good => false,
|
||||
@ -4955,7 +4973,7 @@ impl Surface<'_> {
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.map(|ctx| unsafe {
|
||||
ctx.surface_as_hal::<A, F, R>(
|
||||
self.data.downcast_ref().unwrap(),
|
||||
self.surface_data.downcast_ref().unwrap(),
|
||||
hal_surface_callback,
|
||||
)
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user