mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 14:55:05 +00:00
[wgpu-hal] require a Surface
to be passed to Instance.enumerate_adapters()
on WebGL2
Also makes wgpu's `enumerate_adapters()` native only.
This commit is contained in:
parent
37f283688a
commit
7910fd8059
10
CHANGELOG.md
10
CHANGELOG.md
@ -129,6 +129,16 @@ Platform support:
|
|||||||
|
|
||||||
By @atlv24 in [#5383](https://github.com/gfx-rs/wgpu/pull/5383)
|
By @atlv24 in [#5383](https://github.com/gfx-rs/wgpu/pull/5383)
|
||||||
|
|
||||||
|
#### A compatible surface is now required for `request_adapter()` on WebGL2 + `enumerate_adapters()` is now native only.
|
||||||
|
|
||||||
|
When targeting WebGL2, it has always been the case that a surface had to be created before calling `request_adapter()`.
|
||||||
|
We now make this requirement explicit.
|
||||||
|
|
||||||
|
Calling `enumerate_adapters()` when targeting WebGPU used to return an empty `Vec` and since we now require users
|
||||||
|
to pass a compatible surface when targeting WebGL2, having `enumerate_adapters()` doesn't make sense.
|
||||||
|
|
||||||
|
By @teoxoy in [#5901](https://github.com/gfx-rs/wgpu/pull/5901)
|
||||||
|
|
||||||
### New features
|
### New features
|
||||||
#### Vulkan
|
#### Vulkan
|
||||||
|
|
||||||
|
@ -41,15 +41,17 @@ pub fn initialize_instance() -> Instance {
|
|||||||
pub async fn initialize_adapter(adapter_index: usize) -> (Instance, Adapter, Option<SurfaceGuard>) {
|
pub async fn initialize_adapter(adapter_index: usize) -> (Instance, Adapter, Option<SurfaceGuard>) {
|
||||||
let instance = initialize_instance();
|
let instance = initialize_instance();
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let _surface: wgpu::Surface;
|
let surface: Option<wgpu::Surface>;
|
||||||
let surface_guard: Option<SurfaceGuard>;
|
let surface_guard: Option<SurfaceGuard>;
|
||||||
|
|
||||||
// Create a canvas iff we need a WebGL2RenderingContext to have a working device.
|
#[allow(unused_assignments)]
|
||||||
|
// Create a canvas if we need a WebGL2RenderingContext to have a working device.
|
||||||
#[cfg(not(all(
|
#[cfg(not(all(
|
||||||
target_arch = "wasm32",
|
target_arch = "wasm32",
|
||||||
any(target_os = "emscripten", feature = "webgl")
|
any(target_os = "emscripten", feature = "webgl")
|
||||||
)))]
|
)))]
|
||||||
{
|
{
|
||||||
|
surface = None;
|
||||||
surface_guard = None;
|
surface_guard = None;
|
||||||
}
|
}
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
@ -60,15 +62,17 @@ pub async fn initialize_adapter(adapter_index: usize) -> (Instance, Adapter, Opt
|
|||||||
// On wasm, append a canvas to the document body for initializing the adapter
|
// On wasm, append a canvas to the document body for initializing the adapter
|
||||||
let canvas = initialize_html_canvas();
|
let canvas = initialize_html_canvas();
|
||||||
|
|
||||||
_surface = instance
|
surface = Some(
|
||||||
|
instance
|
||||||
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
|
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
|
||||||
.expect("could not create surface from canvas");
|
.expect("could not create surface from canvas"),
|
||||||
|
);
|
||||||
|
|
||||||
surface_guard = Some(SurfaceGuard { canvas });
|
surface_guard = Some(SurfaceGuard { canvas });
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))] {
|
if #[cfg(not(target_arch = "wasm32"))] {
|
||||||
let adapter_iter = instance.enumerate_adapters(wgpu::Backends::all());
|
let adapter_iter = instance.enumerate_adapters(wgpu::Backends::all());
|
||||||
let adapter_count = adapter_iter.len();
|
let adapter_count = adapter_iter.len();
|
||||||
let adapter = adapter_iter.into_iter()
|
let adapter = adapter_iter.into_iter()
|
||||||
@ -76,7 +80,10 @@ pub async fn initialize_adapter(adapter_index: usize) -> (Instance, Adapter, Opt
|
|||||||
.unwrap_or_else(|| panic!("Tried to get index {adapter_index} adapter, but adapter list was only {adapter_count} long. Is .gpuconfig out of date?"));
|
.unwrap_or_else(|| panic!("Tried to get index {adapter_index} adapter, but adapter list was only {adapter_count} long. Is .gpuconfig out of date?"));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(adapter_index, 0);
|
assert_eq!(adapter_index, 0);
|
||||||
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await.unwrap();
|
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
compatible_surface: surface.as_ref(),
|
||||||
|
..Default::default()
|
||||||
|
}).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,7 +717,7 @@ impl Global {
|
|||||||
profiling::scope!("enumerating", &*format!("{:?}", A::VARIANT));
|
profiling::scope!("enumerating", &*format!("{:?}", A::VARIANT));
|
||||||
let hub = HalApi::hub(self);
|
let hub = HalApi::hub(self);
|
||||||
|
|
||||||
let hal_adapters = unsafe { inst.enumerate_adapters() };
|
let hal_adapters = unsafe { inst.enumerate_adapters(None) };
|
||||||
for raw in hal_adapters {
|
for raw in hal_adapters {
|
||||||
let adapter = Adapter::new(raw);
|
let adapter = Adapter::new(raw);
|
||||||
log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info);
|
log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info);
|
||||||
@ -796,7 +796,9 @@ impl Global {
|
|||||||
let id = inputs.find(A::VARIANT);
|
let id = inputs.find(A::VARIANT);
|
||||||
match (id, instance) {
|
match (id, instance) {
|
||||||
(Some(id), Some(inst)) => {
|
(Some(id), Some(inst)) => {
|
||||||
let mut adapters = unsafe { inst.enumerate_adapters() };
|
let compatible_hal_surface =
|
||||||
|
compatible_surface.and_then(|surface| A::surface_as_hal(surface));
|
||||||
|
let mut adapters = unsafe { inst.enumerate_adapters(compatible_hal_surface) };
|
||||||
if force_software {
|
if force_software {
|
||||||
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
|
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ impl<A: hal::Api> Example<A> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (adapter, capabilities) = unsafe {
|
let (adapter, capabilities) = unsafe {
|
||||||
let mut adapters = instance.enumerate_adapters();
|
let mut adapters = instance.enumerate_adapters(Some(&surface));
|
||||||
if adapters.is_empty() {
|
if adapters.is_empty() {
|
||||||
return Err("no adapters found".into());
|
return Err("no adapters found".into());
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ impl<A: hal::Api> Example<A> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (adapter, features) = unsafe {
|
let (adapter, features) = unsafe {
|
||||||
let mut adapters = instance.enumerate_adapters();
|
let mut adapters = instance.enumerate_adapters(Some(&surface));
|
||||||
if adapters.is_empty() {
|
if adapters.is_empty() {
|
||||||
panic!("No adapters found");
|
panic!("No adapters found");
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,10 @@ impl crate::Instance for super::Instance {
|
|||||||
// just drop
|
// just drop
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
_surface_hint: Option<&super::Surface>,
|
||||||
|
) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||||
let adapters = auxil::dxgi::factory::enumerate_adapters(self.factory.clone());
|
let adapters = auxil::dxgi::factory::enumerate_adapters(self.factory.clone());
|
||||||
|
|
||||||
adapters
|
adapters
|
||||||
|
@ -54,7 +54,10 @@ impl crate::Instance for Context {
|
|||||||
Ok(Context)
|
Ok(Context)
|
||||||
}
|
}
|
||||||
unsafe fn destroy_surface(&self, surface: Context) {}
|
unsafe fn destroy_surface(&self, surface: Context) {}
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
_surface_hint: Option<&Context>,
|
||||||
|
) -> Vec<crate::ExposedAdapter<Api>> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1001,7 +1001,10 @@ impl crate::Instance for Instance {
|
|||||||
|
|
||||||
unsafe fn destroy_surface(&self, _surface: Surface) {}
|
unsafe fn destroy_surface(&self, _surface: Surface) {}
|
||||||
|
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
_surface_hint: Option<&Surface>,
|
||||||
|
) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
inner.egl.make_current();
|
inner.egl.make_current();
|
||||||
|
|
||||||
|
@ -24,10 +24,7 @@ impl AdapterContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Instance {
|
pub struct Instance;
|
||||||
/// Set when a canvas is provided, and used to implement [`Instance::enumerate_adapters()`].
|
|
||||||
webgl2_context: Mutex<Option<web_sys::WebGl2RenderingContext>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
pub fn create_surface_from_canvas(
|
pub fn create_surface_from_canvas(
|
||||||
@ -85,10 +82,6 @@ impl Instance {
|
|||||||
.dyn_into()
|
.dyn_into()
|
||||||
.expect("canvas context is not a WebGl2RenderingContext");
|
.expect("canvas context is not a WebGl2RenderingContext");
|
||||||
|
|
||||||
// It is not inconsistent to overwrite an existing context, because the only thing that
|
|
||||||
// `self.webgl2_context` is used for is producing the response to `enumerate_adapters()`.
|
|
||||||
*self.webgl2_context.lock() = Some(webgl2_context.clone());
|
|
||||||
|
|
||||||
Ok(Surface {
|
Ok(Surface {
|
||||||
canvas,
|
canvas,
|
||||||
webgl2_context,
|
webgl2_context,
|
||||||
@ -121,21 +114,22 @@ impl crate::Instance for Instance {
|
|||||||
|
|
||||||
unsafe fn init(_desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
unsafe fn init(_desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
|
||||||
profiling::scope!("Init OpenGL (WebGL) Backend");
|
profiling::scope!("Init OpenGL (WebGL) Backend");
|
||||||
Ok(Instance {
|
Ok(Instance)
|
||||||
webgl2_context: Mutex::new(None),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
let context_guard = self.webgl2_context.lock();
|
&self,
|
||||||
let gl = match *context_guard {
|
surface_hint: Option<&Surface>,
|
||||||
Some(ref webgl2_context) => glow::Context::from_webgl2_context(webgl2_context.clone()),
|
) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||||
None => return Vec::new(),
|
if let Some(surface_hint) = surface_hint {
|
||||||
};
|
let gl = glow::Context::from_webgl2_context(surface_hint.webgl2_context.clone());
|
||||||
|
|
||||||
unsafe { super::Adapter::expose(AdapterContext { glow_context: gl }) }
|
unsafe { super::Adapter::expose(AdapterContext { glow_context: gl }) }
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect()
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_surface(
|
unsafe fn create_surface(
|
||||||
@ -172,15 +166,7 @@ impl crate::Instance for Instance {
|
|||||||
self.create_surface_from_canvas(canvas)
|
self.create_surface_from_canvas(canvas)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn destroy_surface(&self, surface: Surface) {
|
unsafe fn destroy_surface(&self, _surface: Surface) {}
|
||||||
let mut context_option_ref = self.webgl2_context.lock();
|
|
||||||
|
|
||||||
if let Some(context) = context_option_ref.as_ref() {
|
|
||||||
if context == &surface.webgl2_context {
|
|
||||||
*context_option_ref = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -558,7 +558,10 @@ impl crate::Instance for Instance {
|
|||||||
}
|
}
|
||||||
unsafe fn destroy_surface(&self, _surface: Surface) {}
|
unsafe fn destroy_surface(&self, _surface: Surface) {}
|
||||||
|
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
_surface_hint: Option<&Surface>,
|
||||||
|
) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
super::Adapter::expose(AdapterContext {
|
super::Adapter::expose(AdapterContext {
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
|
@ -447,7 +447,11 @@ pub trait Instance: Sized + WasmNotSendSync {
|
|||||||
window_handle: raw_window_handle::RawWindowHandle,
|
window_handle: raw_window_handle::RawWindowHandle,
|
||||||
) -> Result<<Self::A as Api>::Surface, InstanceError>;
|
) -> Result<<Self::A as Api>::Surface, InstanceError>;
|
||||||
unsafe fn destroy_surface(&self, surface: <Self::A as Api>::Surface);
|
unsafe fn destroy_surface(&self, surface: <Self::A as Api>::Surface);
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<ExposedAdapter<Self::A>>;
|
/// `surface_hint` is only used by the GLES backend targeting WebGL2
|
||||||
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
surface_hint: Option<&<Self::A as Api>::Surface>,
|
||||||
|
) -> Vec<ExposedAdapter<Self::A>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Surface: WasmNotSendSync {
|
pub trait Surface: WasmNotSendSync {
|
||||||
|
@ -121,7 +121,10 @@ impl crate::Instance for Instance {
|
|||||||
unsafe { surface.dispose() };
|
unsafe { surface.dispose() };
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
_surface_hint: Option<&Surface>,
|
||||||
|
) -> Vec<crate::ExposedAdapter<Api>> {
|
||||||
let devices = metal::Device::all();
|
let devices = metal::Device::all();
|
||||||
let mut adapters: Vec<crate::ExposedAdapter<Api>> = devices
|
let mut adapters: Vec<crate::ExposedAdapter<Api>> = devices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -884,7 +884,10 @@ impl crate::Instance for super::Instance {
|
|||||||
unsafe { surface.functor.destroy_surface(surface.raw, None) };
|
unsafe { surface.functor.destroy_surface(surface.raw, None) };
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
|
unsafe fn enumerate_adapters(
|
||||||
|
&self,
|
||||||
|
_surface_hint: Option<&super::Surface>,
|
||||||
|
) -> Vec<crate::ExposedAdapter<super::Api>> {
|
||||||
use crate::auxil::db;
|
use crate::auxil::db;
|
||||||
|
|
||||||
let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
|
let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
|
||||||
|
@ -61,6 +61,7 @@ impl ContextWgpuCore {
|
|||||||
Self(unsafe { wgc::global::Global::from_instance(core_instance) })
|
Self(unsafe { wgc::global::Global::from_instance(core_instance) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(native)]
|
||||||
pub fn enumerate_adapters(&self, backends: wgt::Backends) -> Vec<wgc::id::AdapterId> {
|
pub fn enumerate_adapters(&self, backends: wgt::Backends) -> Vec<wgc::id::AdapterId> {
|
||||||
self.0
|
self.0
|
||||||
.enumerate_adapters(wgc::instance::AdapterInputs::Mask(backends, |_| None))
|
.enumerate_adapters(wgc::instance::AdapterInputs::Mask(backends, |_| None))
|
||||||
|
@ -2369,13 +2369,10 @@ impl Instance {
|
|||||||
|
|
||||||
/// Retrieves all available [`Adapter`]s that match the given [`Backends`].
|
/// Retrieves all available [`Adapter`]s that match the given [`Backends`].
|
||||||
///
|
///
|
||||||
/// Always returns an empty vector if the instance decided upon creation to
|
|
||||||
/// target WebGPU since adapter creation is always async on WebGPU.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `backends` - Backends from which to enumerate adapters.
|
/// - `backends` - Backends from which to enumerate adapters.
|
||||||
#[cfg(wgpu_core)]
|
#[cfg(native)]
|
||||||
pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
|
pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
|
||||||
let context = Arc::clone(&self.context);
|
let context = Arc::clone(&self.context);
|
||||||
self.context
|
self.context
|
||||||
@ -2391,7 +2388,7 @@ impl Instance {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
|
/// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
|
||||||
@ -2399,6 +2396,8 @@ impl Instance {
|
|||||||
/// Some options are "soft", so treated as non-mandatory. Others are "hard".
|
/// Some options are "soft", so treated as non-mandatory. Others are "hard".
|
||||||
///
|
///
|
||||||
/// If no adapters are found that suffice all the "hard" options, `None` is returned.
|
/// If no adapters are found that suffice all the "hard" options, `None` is returned.
|
||||||
|
///
|
||||||
|
/// A `compatible_surface` is required when targeting WebGL2.
|
||||||
pub fn request_adapter(
|
pub fn request_adapter(
|
||||||
&self,
|
&self,
|
||||||
options: &RequestAdapterOptions<'_, '_>,
|
options: &RequestAdapterOptions<'_, '_>,
|
||||||
|
Loading…
Reference in New Issue
Block a user