Core's Surface, Instance and Adapter use now dynamic hal types

This commit is contained in:
Andreas Reich 2024-08-04 21:48:07 +02:00
parent 7c7e4164f1
commit 04cadfb369
10 changed files with 281 additions and 362 deletions

View File

@ -56,7 +56,7 @@ impl Global {
) -> Result<wgt::SurfaceCapabilities, instance::GetSurfaceSupportError> {
profiling::scope!("Surface::get_capabilities");
self.fetch_adapter_and_surface::<A, _, _>(surface_id, adapter_id, |adapter, surface| {
let mut hal_caps = surface.get_capabilities(adapter)?;
let mut hal_caps = surface.get_capabilities::<A>(A::VARIANT, adapter)?;
hal_caps.formats.sort_by_key(|f| !f.is_srgb());
@ -1765,7 +1765,6 @@ impl Global {
device_id: DeviceId,
config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
) -> Option<present::ConfigureSurfaceError> {
use hal::Surface as _;
use present::ConfigureSurfaceError as E;
profiling::scope!("surface_configure");
@ -1909,7 +1908,7 @@ impl Global {
Err(_) => break 'error E::InvalidSurface,
};
let caps = match surface.get_capabilities(&device.adapter) {
let caps = match surface.get_capabilities::<A>(A::VARIANT, &device.adapter) {
Ok(caps) => caps,
Err(_) => break 'error E::UnsupportedQueueFamily,
};
@ -1990,11 +1989,8 @@ impl Global {
//
// https://github.com/gfx-rs/wgpu/issues/4105
match unsafe {
A::surface_as_hal(surface)
.unwrap()
.configure(device.raw().as_any().downcast_ref().unwrap(), &hal_config)
} {
let surface_raw = surface.raw(A::VARIANT).unwrap();
match unsafe { surface_raw.configure(device.raw(), &hal_config) } {
Ok(()) => (),
Err(error) => {
break 'error match error {

View File

@ -1,3 +1,5 @@
use std::collections::HashMap;
use wgt::Backend;
use crate::{
@ -11,14 +13,7 @@ use crate::{
#[derive(Debug, PartialEq, Eq)]
pub struct GlobalReport {
pub surfaces: RegistryReport,
#[cfg(vulkan)]
pub vulkan: Option<HubReport>,
#[cfg(metal)]
pub metal: Option<HubReport>,
#[cfg(dx12)]
pub dx12: Option<HubReport>,
#[cfg(gles)]
pub gl: Option<HubReport>,
pub report_per_backend: HashMap<Backend, HubReport>,
}
impl GlobalReport {
@ -26,17 +21,7 @@ impl GlobalReport {
&self.surfaces
}
pub fn hub_report(&self, backend: Backend) -> &HubReport {
match backend {
#[cfg(vulkan)]
Backend::Vulkan => self.vulkan.as_ref().unwrap(),
#[cfg(metal)]
Backend::Metal => self.metal.as_ref().unwrap(),
#[cfg(dx12)]
Backend::Dx12 => self.dx12.as_ref().unwrap(),
#[cfg(gles)]
Backend::Gl => self.gl.as_ref().unwrap(),
_ => panic!("HubReport is not supported on this backend"),
}
self.report_per_backend.get(&backend).unwrap()
}
}
@ -61,8 +46,14 @@ impl Global {
/// Refer to the creation of wgpu-hal Instance for every backend.
pub unsafe fn from_hal_instance<A: HalApi>(name: &str, hal_instance: A::Instance) -> Self {
profiling::scope!("Global::new");
let dyn_instance: Box<dyn hal::DynInstance> = Box::new(hal_instance);
Self {
instance: A::create_instance_from_hal(name, hal_instance),
instance: Instance {
name: name.to_owned(),
instance_per_backend: std::iter::once((A::VARIANT, dyn_instance)).collect(),
..Default::default()
},
surfaces: Registry::without_backend(),
hubs: Hubs::new(),
}
@ -72,7 +63,13 @@ impl Global {
///
/// - The raw instance handle returned must not be manually destroyed.
pub unsafe fn instance_as_hal<A: HalApi>(&self) -> Option<&A::Instance> {
A::instance_as_hal(&self.instance)
self.instance.raw(A::VARIANT).map(|instance| {
instance
.as_any()
.downcast_ref()
// This should be impossible. It would mean that backend instance and enum type are mismatching.
.expect("Stored instance is not of the correct type")
})
}
/// # Safety
@ -88,32 +85,41 @@ impl Global {
}
pub fn generate_report(&self) -> GlobalReport {
let mut report_per_backend = HashMap::default();
let instance_per_backend = &self.instance.instance_per_backend;
#[cfg(vulkan)]
if instance_per_backend
.iter()
.any(|(backend, _)| backend == &Backend::Vulkan)
{
report_per_backend.insert(Backend::Vulkan, self.hubs.vulkan.generate_report());
};
#[cfg(metal)]
if instance_per_backend
.iter()
.any(|(backend, _)| backend == &Backend::Metal)
{
report_per_backend.insert(Backend::Metal, self.hubs.metal.generate_report());
};
#[cfg(dx12)]
if instance_per_backend
.iter()
.any(|(backend, _)| backend == &Backend::Dx12)
{
report_per_backend.insert(Backend::Dx12, self.hubs.dx12.generate_report());
};
#[cfg(gles)]
if instance_per_backend
.iter()
.any(|(backend, _)| backend == &Backend::Gl)
{
report_per_backend.insert(Backend::Gl, self.hubs.gl.generate_report());
};
GlobalReport {
surfaces: self.surfaces.generate_report(),
#[cfg(vulkan)]
vulkan: if self.instance.vulkan.is_some() {
Some(self.hubs.vulkan.generate_report())
} else {
None
},
#[cfg(metal)]
metal: if self.instance.metal.is_some() {
Some(self.hubs.metal.generate_report())
} else {
None
},
#[cfg(dx12)]
dx12: if self.instance.dx12.is_some() {
Some(self.hubs.dx12.generate_report())
} else {
None
},
#[cfg(gles)]
gl: if self.instance.gl.is_some() {
Some(self.hubs.gl.generate_report())
} else {
None
},
report_per_backend,
}
}
}

View File

@ -1,116 +1,53 @@
use wgt::{Backend, WasmNotSendSync};
use crate::{
global::Global,
hub::Hub,
instance::{Instance, Surface},
};
use crate::{global::Global, hub::Hub};
pub trait HalApi: hal::Api + 'static + WasmNotSendSync {
const VARIANT: Backend;
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 surface_as_hal(surface: &Surface) -> Option<&Self::Surface>;
}
impl HalApi for hal::api::Empty {
const VARIANT: Backend = Backend::Empty;
fn create_instance_from_hal(_: &str, _: Self::Instance) -> Instance {
unimplemented!("called empty api")
}
fn instance_as_hal(_: &Instance) -> Option<&Self::Instance> {
unimplemented!("called empty api")
}
fn hub(_: &Global) -> &Hub<Self> {
unimplemented!("called empty api")
}
fn surface_as_hal(_: &Surface) -> Option<&Self::Surface> {
unimplemented!("called empty api")
}
}
#[cfg(vulkan)]
impl HalApi for hal::api::Vulkan {
const VARIANT: Backend = Backend::Vulkan;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
vulkan: Some(hal_instance),
..Default::default()
}
}
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.vulkan.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.vulkan
}
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
surface.vulkan.as_ref()
}
}
#[cfg(metal)]
impl HalApi for hal::api::Metal {
const VARIANT: Backend = Backend::Metal;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
metal: Some(hal_instance),
..Default::default()
}
}
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.metal.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.metal
}
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
surface.metal.as_ref()
}
}
#[cfg(dx12)]
impl HalApi for hal::api::Dx12 {
const VARIANT: Backend = Backend::Dx12;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
Instance {
name: name.to_owned(),
dx12: Some(hal_instance),
..Default::default()
}
}
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.dx12.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.dx12
}
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
surface.dx12.as_ref()
}
}
#[cfg(gles)]
impl HalApi for hal::api::Gles {
const VARIANT: Backend = Backend::Gl;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance {
#[allow(clippy::needless_update)]
Instance {
name: name.to_owned(),
gl: Some(hal_instance),
..Default::default()
}
}
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.gl.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.gl
}
fn surface_as_hal(surface: &Surface) -> Option<&Self::Surface> {
surface.gl.as_ref()
}
}

View File

@ -215,8 +215,6 @@ impl<A: HalApi> Hub<A> {
}
pub(crate) fn clear(&self, surface_guard: &Storage<Surface>) {
use hal::Surface;
let mut devices = self.devices.write();
for element in devices.map.iter() {
if let Element::Occupied(ref device, _) = *element {
@ -242,10 +240,9 @@ 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::surface_as_hal(surface);
let suf = surface.raw(A::VARIANT);
unsafe {
suf.unwrap()
.unconfigure(device.raw().as_any().downcast_ref().unwrap());
suf.unwrap().unconfigure(device.raw());
}
}
}

View File

@ -15,12 +15,9 @@ use crate::{
use wgt::{Backend, Backends, PowerPreference};
use hal::{Adapter as _, Instance as _, OpenDevice};
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)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@ -58,20 +55,20 @@ fn downlevel_default_limits_less_than_default_limits() {
pub struct Instance {
#[allow(dead_code)]
pub name: String,
#[cfg(vulkan)]
pub vulkan: Option<HalInstance<hal::api::Vulkan>>,
#[cfg(metal)]
pub metal: Option<HalInstance<hal::api::Metal>>,
#[cfg(dx12)]
pub dx12: Option<HalInstance<hal::api::Dx12>>,
#[cfg(gles)]
pub gl: Option<HalInstance<hal::api::Gles>>,
/// List of instances per backend.
///
/// The ordering in this list implies prioritization and needs to be preserved.
pub instance_per_backend: Vec<(Backend, Box<dyn hal::DynInstance>)>,
pub flags: wgt::InstanceFlags,
}
impl Instance {
pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self {
fn init<A: HalApi>(_: A, instance_desc: &wgt::InstanceDescriptor) -> Option<A::Instance> {
fn init<A: HalApi>(
_: A,
instance_desc: &wgt::InstanceDescriptor,
instance_per_backend: &mut Vec<(Backend, Box<dyn hal::DynInstance>)>,
) {
if instance_desc.backends.contains(A::VARIANT.into()) {
let hal_desc = hal::InstanceDescriptor {
name: "wgpu",
@ -79,10 +76,12 @@ impl Instance {
dx12_shader_compiler: instance_desc.dx12_shader_compiler.clone(),
gles_minor_version: instance_desc.gles_minor_version,
};
match unsafe { hal::Instance::init(&hal_desc) } {
use hal::Instance as _;
match unsafe { A::Instance::init(&hal_desc) } {
Ok(instance) => {
log::debug!("Instance::new: created {:?} backend", A::VARIANT);
Some(instance)
instance_per_backend.push((A::VARIANT, Box::new(instance)));
}
Err(err) => {
log::debug!(
@ -90,41 +89,43 @@ impl Instance {
A::VARIANT,
err
);
None
}
}
} else {
log::trace!("Instance::new: backend {:?} not requested", A::VARIANT);
None
}
}
let mut instance_per_backend = Vec::new();
#[cfg(vulkan)]
init(hal::api::Vulkan, &instance_desc, &mut instance_per_backend);
#[cfg(metal)]
init(hal::api::Metal, &instance_desc, &mut instance_per_backend);
#[cfg(dx12)]
init(hal::api::Dx12, &instance_desc, &mut instance_per_backend);
#[cfg(gles)]
init(hal::api::Gles, &instance_desc, &mut instance_per_backend);
Self {
name: name.to_string(),
#[cfg(vulkan)]
vulkan: init(hal::api::Vulkan, &instance_desc),
#[cfg(metal)]
metal: init(hal::api::Metal, &instance_desc),
#[cfg(dx12)]
dx12: init(hal::api::Dx12, &instance_desc),
#[cfg(gles)]
gl: init(hal::api::Gles, &instance_desc),
instance_per_backend,
flags: instance_desc.flags,
}
}
pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynInstance> {
self.instance_per_backend
.iter()
.find_map(|(instance_backend, instance)| {
(*instance_backend == backend).then(|| instance.as_ref())
})
}
}
pub struct Surface {
pub(crate) presentation: Mutex<Option<Presentation>>,
#[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>>,
pub surface_per_backend: HashMap<Backend, Box<dyn hal::DynSurface>>,
}
impl ResourceType for Surface {
@ -137,34 +138,41 @@ impl crate::storage::StorageItem for Surface {
impl Surface {
pub fn get_capabilities<A: HalApi>(
&self,
backend: Backend,
adapter: &Adapter<A>,
) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
self.get_capabilities_with_raw(&adapter.raw)
self.get_capabilities_with_raw(backend, &adapter.raw)
}
pub fn get_capabilities_with_raw<A: HalApi>(
pub fn get_capabilities_with_raw(
&self,
adapter: &hal::ExposedAdapter<A>,
backend: Backend,
adapter: &hal::DynExposedAdapter,
) -> Result<hal::SurfaceCapabilities, GetSurfaceSupportError> {
let suf = A::surface_as_hal(self).ok_or(GetSurfaceSupportError::Unsupported)?;
let suf = self
.raw(backend)
.ok_or(GetSurfaceSupportError::Unsupported)?;
profiling::scope!("surface_capabilities");
let caps = unsafe {
adapter
.adapter
.surface_capabilities(suf)
.ok_or(GetSurfaceSupportError::Unsupported)?
};
let caps = unsafe { adapter.adapter.surface_capabilities(suf) }
.ok_or(GetSurfaceSupportError::Unsupported)?;
Ok(caps)
}
pub fn raw(&self, backend: Backend) -> Option<&dyn hal::DynSurface> {
self.surface_per_backend
.get(&backend)
.map(|surface| surface.as_ref())
}
}
pub struct Adapter<A: HalApi> {
pub(crate) raw: hal::ExposedAdapter<A>,
pub(crate) raw: hal::DynExposedAdapter,
_marker: std::marker::PhantomData<A>,
}
impl<A: HalApi> Adapter<A> {
fn new(mut raw: hal::ExposedAdapter<A>) -> Self {
fn new(mut raw: hal::DynExposedAdapter) -> Self {
// WebGPU requires this offset alignment as lower bound on all adapters.
const MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND: u32 = 32;
@ -177,7 +185,10 @@ impl<A: HalApi> Adapter<A> {
.min_storage_buffer_offset_alignment
.max(MIN_BUFFER_OFFSET_ALIGNMENT_LOWER_BOUND);
Self { raw }
Self {
raw,
_marker: std::marker::PhantomData,
}
}
pub fn is_surface_supported(&self, surface: &Surface) -> bool {
@ -185,7 +196,7 @@ impl<A: HalApi> Adapter<A> {
//
// This could occur if the user is running their app on Wayland but Vulkan does not support
// VK_KHR_wayland_surface.
surface.get_capabilities(self).is_ok()
surface.get_capabilities(A::VARIANT, self).is_ok()
}
pub(crate) fn get_texture_format_features(
@ -259,7 +270,7 @@ impl<A: HalApi> Adapter<A> {
#[allow(clippy::type_complexity)]
fn create_device_and_queue_from_hal(
self: &Arc<Self>,
hal_device: OpenDevice<A>,
hal_device: hal::DynOpenDevice,
desc: &DeviceDescriptor,
instance_flags: wgt::InstanceFlags,
trace_path: Option<&std::path::Path>,
@ -267,15 +278,15 @@ impl<A: HalApi> Adapter<A> {
api_log!("Adapter::create_device");
if let Ok(device) = Device::new(
Box::new(hal_device.device),
&hal_device.queue,
hal_device.device,
hal_device.queue.as_ref(),
self,
desc,
trace_path,
instance_flags,
) {
let device = Arc::new(device);
let queue = Arc::new(Queue::new(device.clone(), Box::new(hal_device.queue)));
let queue = Arc::new(Queue::new(device.clone(), hal_device.queue));
device.set_queue(&queue);
return Ok((device, queue));
}
@ -456,85 +467,42 @@ impl Global {
) -> Result<SurfaceId, CreateSurfaceError> {
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<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 errors = HashMap::default();
let mut surface_per_backend = HashMap::default();
for (backend, instance) in &self.instance.instance_per_backend {
match unsafe {
instance
.as_ref()
.create_surface(display_handle, window_handle)
} {
Ok(raw) => {
surface_per_backend.insert(*backend, raw);
}
})
Err(err) => {
log::debug!(
"Instance::create_surface: failed to create surface for {:?}: {:?}",
backend,
err
);
errors.insert(*backend, err);
}
}
}
let mut errors = HashMap::default();
let mut any_created = false;
let surface = Surface {
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
#[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,
),
};
if any_created {
#[allow(clippy::arc_with_non_send_sync)]
let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
} else {
if surface_per_backend.is_empty() {
Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend(
errors,
))
} else {
let surface = Surface {
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
surface_per_backend,
};
#[allow(clippy::arc_with_non_send_sync)]
let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
Ok(id)
}
}
@ -549,33 +517,31 @@ impl Global {
) -> Result<SurfaceId, CreateSurfaceError> {
profiling::scope!("Instance::create_surface_metal");
let instance = self
.instance
.raw(Backend::Metal)
.ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
let instance_metal: &hal::metal::Instance = instance.as_any().downcast_ref().unwrap();
let layer = layer.cast();
// SAFETY: We do this cast and deref. (rather than using `metal` to get the
// object we want) to avoid direct coupling on the `metal` crate.
//
// To wit, this pointer…
//
// - …is properly aligned.
// - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
// field.
// - …points to an _initialized_ `MetalLayerRef`.
// - …is only ever aliased via an immutable reference that lives within this
// lexical scope.
let layer = unsafe { &*layer };
let raw_surface: Box<dyn hal::DynSurface> =
Box::new(instance_metal.create_surface_from_layer(layer));
let surface = Surface {
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),
metal: Some(self.instance.metal.as_ref().map_or(
Err(CreateSurfaceError::BackendNotEnabled(Backend::Metal)),
|inst| {
let layer = layer.cast();
// SAFETY: We do this cast and deref. (rather than using `metal` to get the
// object we want) to avoid direct coupling on the `metal` crate.
//
// To wit, this pointer…
//
// - …is properly aligned.
// - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
// field.
// - …points to an _initialized_ `MetalLayerRef`.
// - …is only ever aliased via an immutable reference that lives within this
// lexical scope.
let layer = unsafe { &*layer };
Ok(inst.create_surface_from_layer(layer))
},
)?),
#[cfg(dx12)]
dx12: None,
#[cfg(vulkan)]
vulkan: None,
#[cfg(gles)]
gl: None,
surface_per_backend: std::iter::once((Backend::Metal, raw_surface)).collect(),
};
let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
@ -586,22 +552,18 @@ impl Global {
fn instance_create_surface_dx12(
&self,
id_in: Option<SurfaceId>,
create_surface_func: impl FnOnce(&HalInstance<hal::api::Dx12>) -> HalSurface<hal::api::Dx12>,
create_surface_func: impl FnOnce(&hal::dx12::Instance) -> hal::dx12::Surface,
) -> Result<SurfaceId, CreateSurfaceError> {
let instance = self
.instance
.raw(Backend::Dx12)
.ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Dx12))?;
let instance_dx12 = instance.as_any().downcast_ref().unwrap();
let surface: Box<dyn hal::DynSurface> = Box::new(create_surface_func(instance_dx12));
let surface = Surface {
presentation: Mutex::new(rank::SURFACE_PRESENTATION, 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,
surface_per_backend: std::iter::once((Backend::Dx12, surface)).collect(),
};
let id = self.surfaces.prepare(id_in).assign(Arc::new(surface));
@ -658,11 +620,10 @@ impl Global {
api_log!("Surface::drop {id:?}");
fn unconfigure<A: HalApi>(surface: &Option<HalSurface<A>>, present: &Presentation) {
if let Some(surface) = surface {
fn unconfigure<A: HalApi>(surface: &Surface, present: &Presentation) {
if let Some(surface) = surface.raw(A::VARIANT) {
if let Some(device) = present.device.downcast_ref::<A>() {
use hal::Surface;
unsafe { surface.unconfigure(device.raw().as_any().downcast_ref().unwrap()) };
unsafe { surface.unconfigure(device.raw()) };
}
}
}
@ -672,27 +633,31 @@ impl Global {
.expect("Surface cannot be destroyed because is still in use");
if let Some(present) = surface.presentation.lock().take() {
// TODO(#5124): Becomes a loop once we use Arc<Device>
#[cfg(vulkan)]
unconfigure::<hal::api::Vulkan>(&surface.vulkan, &present);
unconfigure::<hal::api::Vulkan>(&surface, &present);
#[cfg(metal)]
unconfigure::<hal::api::Metal>(&surface.metal, &present);
unconfigure::<hal::api::Metal>(&surface, &present);
#[cfg(dx12)]
unconfigure::<hal::api::Dx12>(&surface.dx12, &present);
unconfigure::<hal::api::Dx12>(&surface, &present);
#[cfg(gles)]
unconfigure::<hal::api::Gles>(&surface.gl, &present);
unconfigure::<hal::api::Gles>(&surface, &present);
}
drop(surface)
}
fn enumerate<A: HalApi>(
&self,
_: A,
instance: &Option<A::Instance>,
inputs: &AdapterInputs<markers::Adapter>,
list: &mut Vec<AdapterId>,
) {
let inst = match *instance {
Some(ref inst) => inst,
let inst = match self
.instance
.instance_per_backend
.iter()
.find(|(backend, _)| backend == &A::VARIANT)
{
Some((_, inst)) => inst.as_ref(),
None => return,
};
let id_backend = match inputs.find(A::VARIANT) {
@ -700,8 +665,8 @@ impl Global {
None => return,
};
profiling::scope!("enumerating", &*format!("{:?}", A::VARIANT));
let hub = HalApi::hub(self);
profiling::scope!("enumerating", &*format!("{:?}", backend));
let hub: &crate::hub::Hub<A> = HalApi::hub(self);
let hal_adapters = unsafe { inst.enumerate_adapters(None) };
for raw in hal_adapters {
@ -719,23 +684,13 @@ impl Global {
let mut adapters = Vec::new();
#[cfg(vulkan)]
self.enumerate(
hal::api::Vulkan,
&self.instance.vulkan,
&inputs,
&mut adapters,
);
self.enumerate::<hal::vulkan::Api>(&inputs, &mut adapters);
#[cfg(metal)]
self.enumerate(
hal::api::Metal,
&self.instance.metal,
&inputs,
&mut adapters,
);
self.enumerate::<hal::metal::Api>(&inputs, &mut adapters);
#[cfg(dx12)]
self.enumerate(hal::api::Dx12, &self.instance.dx12, &inputs, &mut adapters);
self.enumerate::<hal::dx12::Api>(&inputs, &mut adapters);
#[cfg(gles)]
self.enumerate(hal::api::Gles, &self.instance.gl, &inputs, &mut adapters);
self.enumerate::<hal::gles::Api>(&inputs, &mut adapters);
adapters
}
@ -744,7 +699,7 @@ impl Global {
&self,
selected: &mut usize,
new_id: Option<AdapterId>,
mut list: Vec<hal::ExposedAdapter<A>>,
mut list: Vec<hal::DynExposedAdapter>,
) -> Option<AdapterId> {
match selected.checked_sub(list.len()) {
Some(left) => {
@ -752,7 +707,7 @@ impl Global {
None
}
None => {
let adapter = Adapter::new(list.swap_remove(*selected));
let adapter = Adapter::<A>::new(list.swap_remove(*selected));
log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info);
let id = HalApi::hub(self)
.adapters
@ -771,26 +726,27 @@ impl Global {
profiling::scope!("Instance::request_adapter");
api_log!("Instance::request_adapter");
fn gather<A: HalApi>(
_: A,
instance: Option<&A::Instance>,
fn gather(
backend: Backend,
instance: &Instance,
inputs: &AdapterInputs<markers::Adapter>,
compatible_surface: Option<&Surface>,
force_software: bool,
device_types: &mut Vec<wgt::DeviceType>,
) -> (Option<Id<markers::Adapter>>, Vec<hal::ExposedAdapter<A>>) {
let id = inputs.find(A::VARIANT);
match (id, instance) {
) -> (Option<Id<markers::Adapter>>, Vec<hal::DynExposedAdapter>) {
let id = inputs.find(backend);
match (id, instance.raw(backend)) {
(Some(id), Some(inst)) => {
let compatible_hal_surface =
compatible_surface.and_then(|surface| A::surface_as_hal(surface));
compatible_surface.and_then(|surface| surface.raw(backend));
let mut adapters = unsafe { inst.enumerate_adapters(compatible_hal_surface) };
if force_software {
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
}
if let Some(surface) = compatible_surface {
adapters
.retain(|exposed| surface.get_capabilities_with_raw(exposed).is_ok());
adapters.retain(|exposed| {
surface.get_capabilities_with_raw(backend, exposed).is_ok()
});
}
device_types.extend(adapters.iter().map(|ad| ad.info.device_type));
(id, adapters)
@ -812,8 +768,8 @@ impl Global {
#[cfg(vulkan)]
let (id_vulkan, adapters_vk) = gather(
hal::api::Vulkan,
self.instance.vulkan.as_ref(),
Backend::Vulkan,
&self.instance,
&inputs,
compatible_surface,
desc.force_fallback_adapter,
@ -821,8 +777,8 @@ impl Global {
);
#[cfg(metal)]
let (id_metal, adapters_metal) = gather(
hal::api::Metal,
self.instance.metal.as_ref(),
Backend::Metal,
&self.instance,
&inputs,
compatible_surface,
desc.force_fallback_adapter,
@ -830,8 +786,8 @@ impl Global {
);
#[cfg(dx12)]
let (id_dx12, adapters_dx12) = gather(
hal::api::Dx12,
self.instance.dx12.as_ref(),
Backend::Dx12,
&self.instance,
&inputs,
compatible_surface,
desc.force_fallback_adapter,
@ -839,8 +795,8 @@ impl Global {
);
#[cfg(gles)]
let (id_gl, adapters_gl) = gather(
hal::api::Gles,
self.instance.gl.as_ref(),
Backend::Gl,
&self.instance,
&inputs,
compatible_surface,
desc.force_fallback_adapter,
@ -899,19 +855,19 @@ impl Global {
let mut selected = preferred_gpu.unwrap_or(0);
#[cfg(vulkan)]
if let Some(id) = self.select(&mut selected, id_vulkan, adapters_vk) {
if let Some(id) = self.select::<hal::api::Vulkan>(&mut selected, id_vulkan, adapters_vk) {
return Ok(id);
}
#[cfg(metal)]
if let Some(id) = self.select(&mut selected, id_metal, adapters_metal) {
if let Some(id) = self.select::<hal::api::Metal>(&mut selected, id_metal, adapters_metal) {
return Ok(id);
}
#[cfg(dx12)]
if let Some(id) = self.select(&mut selected, id_dx12, adapters_dx12) {
if let Some(id) = self.select::<hal::api::Dx12>(&mut selected, id_dx12, adapters_dx12) {
return Ok(id);
}
#[cfg(gles)]
if let Some(id) = self.select(&mut selected, id_gl, adapters_gl) {
if let Some(id) = self.select::<hal::api::Gles>(&mut selected, id_gl, adapters_gl) {
return Ok(id);
}
let _ = selected;
@ -925,7 +881,7 @@ impl Global {
/// `hal_adapter` must be created from this global internal instance handle.
pub unsafe fn create_adapter_from_hal<A: HalApi>(
&self,
hal_adapter: hal::ExposedAdapter<A>,
hal_adapter: hal::DynExposedAdapter,
input: Option<AdapterId>,
) -> AdapterId {
profiling::scope!("Instance::create_adapter_from_hal");
@ -934,13 +890,13 @@ impl Global {
let id = match A::VARIANT {
#[cfg(vulkan)]
Backend::Vulkan => fid.assign(Arc::new(Adapter::new(hal_adapter))),
Backend::Vulkan => fid.assign(Arc::new(Adapter::<A>::new(hal_adapter))),
#[cfg(metal)]
Backend::Metal => fid.assign(Arc::new(Adapter::new(hal_adapter))),
Backend::Metal => fid.assign(Arc::new(Adapter::<A>::new(hal_adapter))),
#[cfg(dx12)]
Backend::Dx12 => fid.assign(Arc::new(Adapter::new(hal_adapter))),
Backend::Dx12 => fid.assign(Arc::new(Adapter::<A>::new(hal_adapter))),
#[cfg(gles)]
Backend::Gl => fid.assign(Arc::new(Adapter::new(hal_adapter))),
Backend::Gl => fid.assign(Arc::new(Adapter::<A>::new(hal_adapter))),
_ => unreachable!(),
};
resource_log!("Created Adapter {:?}", id);
@ -1076,7 +1032,7 @@ impl Global {
pub unsafe fn create_device_from_hal<A: HalApi>(
&self,
adapter_id: AdapterId,
hal_device: OpenDevice<A>,
hal_device: hal::DynOpenDevice,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
device_id_in: Option<DeviceId>,

View File

@ -30,7 +30,7 @@ const FRAME_TIMEOUT_MS: u32 = 1000;
#[derive(Debug)]
pub(crate) struct Presentation {
pub(crate) device: AnyDevice,
pub(crate) device: AnyDevice, // TODO(#5124): use device: Arc<Device>
pub(crate) config: wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
pub(crate) acquired_texture: Option<id::TextureId>,
}
@ -153,10 +153,9 @@ impl Global {
let fence = device.fence.read();
let suf = A::surface_as_hal(surface.as_ref());
let suf = surface.raw(A::VARIANT).unwrap();
let (texture_id, status) = match unsafe {
use hal::DynSurface;
suf.unwrap().acquire_texture(
suf.acquire_texture(
Some(std::time::Duration::from_millis(FRAME_TIMEOUT_MS as u64)),
fence.as_ref(),
)
@ -304,7 +303,7 @@ impl Global {
.lock()
.textures
.remove(texture.tracker_index());
let suf = A::surface_as_hal(&surface);
let suf = surface.raw(A::VARIANT).unwrap();
let exclusive_snatch_guard = device.snatchable_lock.write();
match texture.inner.snatch(exclusive_snatch_guard).unwrap() {
resource::TextureInner::Surface { raw, parent_id } => {
@ -312,7 +311,7 @@ impl Global {
log::error!("Presented frame is from a different surface");
Err(hal::SurfaceError::Lost)
} else {
unsafe { queue.raw().present(suf.unwrap(), raw) }
unsafe { queue.raw().present(suf, raw) }
}
}
_ => unreachable!(),
@ -379,12 +378,11 @@ impl Global {
.lock()
.textures
.remove(texture.tracker_index());
let suf = A::surface_as_hal(&surface);
let suf = surface.raw(A::VARIANT);
let exclusive_snatch_guard = device.snatchable_lock.write();
match texture.inner.snatch(exclusive_snatch_guard).unwrap() {
resource::TextureInner::Surface { raw, parent_id } => {
if surface_id == parent_id {
use hal::DynSurface;
unsafe { suf.unwrap().discard_texture(raw) };
} else {
log::warn!("Surface texture is outdated");

View File

@ -1271,7 +1271,10 @@ impl Global {
let hub = A::hub(self);
let adapter = hub.adapters.get(id).ok();
let hal_adapter = adapter.as_ref().map(|adapter| &adapter.raw.adapter);
let hal_adapter = adapter
.as_ref()
.map(|adapter| &adapter.raw.adapter)
.and_then(|adapter| adapter.as_any().downcast_ref());
hal_adapter_callback(hal_adapter)
}
@ -1328,7 +1331,8 @@ impl Global {
let surface = self.surfaces.get(id).ok();
let hal_surface = surface
.as_ref()
.and_then(|surface| A::surface_as_hal(surface));
.and_then(|surface| surface.raw(A::VARIANT))
.and_then(|surface| surface.as_any().downcast_ref());
hal_surface_callback(hal_surface)
}

View File

@ -1,4 +1,6 @@
use crate::{Adapter, DeviceError, SurfaceCapabilities, TextureFormatCapabilities};
use crate::{
Adapter, Api, DeviceError, OpenDevice, SurfaceCapabilities, TextureFormatCapabilities,
};
use super::{DynDevice, DynQueue, DynResource, DynResourceExt, DynSurface};
@ -7,6 +9,15 @@ pub struct DynOpenDevice {
pub queue: Box<dyn DynQueue>,
}
impl<A: Api> From<OpenDevice<A>> for DynOpenDevice {
fn from(open_device: OpenDevice<A>) -> Self {
Self {
device: Box::new(open_device.device),
queue: Box::new(open_device.queue),
}
}
}
pub trait DynAdapter: DynResource {
unsafe fn open(
&self,

View File

@ -1,7 +1,7 @@
// Box casts are needed, alternative would be a temporaries which are more verbose and not more expressive.
#![allow(trivial_casts)]
use crate::{Capabilities, Instance, InstanceError};
use crate::{Api, Capabilities, ExposedAdapter, Instance, InstanceError};
use super::{DynAdapter, DynResource, DynResourceExt as _, DynSurface};
@ -12,6 +12,17 @@ pub struct DynExposedAdapter {
pub capabilities: Capabilities,
}
impl<A: Api> From<ExposedAdapter<A>> for DynExposedAdapter {
fn from(exposed_adapter: ExposedAdapter<A>) -> Self {
Self {
adapter: Box::new(exposed_adapter.adapter),
info: exposed_adapter.info,
features: exposed_adapter.features,
capabilities: exposed_adapter.capabilities,
}
}
}
pub trait DynInstance: DynResource {
unsafe fn create_surface(
&self,

View File

@ -72,7 +72,10 @@ impl ContextWgpuCore {
&self,
hal_adapter: hal::ExposedAdapter<A>,
) -> wgc::id::AdapterId {
unsafe { self.0.create_adapter_from_hal(hal_adapter, None) }
unsafe {
self.0
.create_adapter_from_hal::<A>(hal_adapter.into(), None)
}
}
pub unsafe fn adapter_as_hal<
@ -109,9 +112,9 @@ impl ContextWgpuCore {
log::error!("Feature 'trace' has been removed temporarily, see https://github.com/gfx-rs/wgpu/issues/5974");
}
let (device_id, queue_id, error) = unsafe {
self.0.create_device_from_hal(
self.0.create_device_from_hal::<A>(
*adapter,
hal_device,
hal_device.into(),
&desc.map_label(|l| l.map(Borrowed)),
None,
None,