Skip to content

Commit 3389cb5

Browse files
committed
gles/egl: Require surface before creating instance / query adapter on Wayland
1 parent 96ef5ec commit 3389cb5

File tree

4 files changed

+61
-26
lines changed

4 files changed

+61
-26
lines changed

examples/features/src/framework.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,16 @@ impl SurfaceWrapper {
141141
/// On wasm, we need to create the surface here, as the WebGL backend needs
142142
/// a surface (and hence a canvas) to be present to create the adapter.
143143
///
144+
/// On Wayland our context creation (both inside the [`Instance`] and [`Adapter`]) requires
145+
/// access to the `RawDisplayHandle`. Since this is currently not provided, a compatible
146+
/// context is set up via the surface instead.
147+
///
144148
/// We cannot unconditionally create a surface here, as Android requires
145-
/// us to wait until we receive the `Resumed` event to do so.
149+
/// us to wait until we receive [`Event::Resumed`] to do so.
146150
fn pre_adapter(&mut self, instance: &Instance, window: Arc<Window>) {
147-
if cfg!(target_arch = "wasm32") {
151+
// XXX: Also needed for EGL+Wayland!
152+
// if cfg!(target_arch = "wasm32") {
153+
if !cfg!(target_os = "android") {
148154
self.surface = Some(instance.create_surface(window).unwrap());
149155
}
150156
}
@@ -153,6 +159,8 @@ impl SurfaceWrapper {
153159
fn start_condition(e: &Event<()>) -> bool {
154160
match e {
155161
// On all other platforms, we can create the surface immediately.
162+
// XXX: winit was improved to consistently emit a Resumed event on all platforms, which
163+
// is the right place to create surfaces... Most platforms emit it right after Init.
156164
Event::NewEvents(StartCause::Init) => !cfg!(target_os = "android"),
157165
// On android we need to wait for a resumed event to create the surface.
158166
Event::Resumed => cfg!(target_os = "android"),
@@ -174,13 +182,9 @@ impl SurfaceWrapper {
174182
log::info!("Surface resume {window_size:?}");
175183

176184
// We didn't create the surface in pre_adapter, so we need to do so now.
177-
if !cfg!(target_arch = "wasm32") {
178-
self.surface = Some(context.instance.create_surface(window).unwrap());
179-
}
180-
181-
// From here on, self.surface should be Some.
182-
183-
let surface = self.surface.as_ref().unwrap();
185+
let surface = self
186+
.surface
187+
.get_or_insert_with(|| context.instance.create_surface(window).unwrap());
184188

185189
// Get the default configuration,
186190
let mut config = surface

examples/features/src/utils.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,24 +203,29 @@ pub(crate) async fn get_adapter_with_capabilities_or_from_env(
203203
);
204204
adapter
205205
} else {
206-
let adapters = instance.enumerate_adapters(Backends::all());
207-
208206
let mut chosen_adapter = None;
209-
for adapter in adapters {
210-
if let Some(surface) = surface {
211-
if !adapter.is_surface_supported(surface) {
207+
208+
if let Some(surface) = surface {
209+
chosen_adapter = instance
210+
.request_adapter(&wgpu::RequestAdapterOptionsBase {
211+
compatible_surface: Some(surface),
212+
..Default::default()
213+
})
214+
.await
215+
.ok();
216+
} else {
217+
let adapters = instance.enumerate_adapters(Backends::all());
218+
219+
for adapter in adapters {
220+
let required_features = *required_features;
221+
let adapter_features = adapter.features();
222+
if !adapter_features.contains(required_features) {
212223
continue;
224+
} else {
225+
chosen_adapter = Some(adapter);
226+
break;
213227
}
214228
}
215-
216-
let required_features = *required_features;
217-
let adapter_features = adapter.features();
218-
if !adapter_features.contains(required_features) {
219-
continue;
220-
} else {
221-
chosen_adapter = Some(adapter);
222-
break;
223-
}
224229
}
225230

226231
chosen_adapter.expect("No suitable GPU adapters found on the system!")

wgpu-hal/src/gles/egl.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,12 @@ struct EglContext {
291291

292292
impl EglContext {
293293
fn make_current(&self) {
294+
log::trace!(
295+
"Make current on {:?} {:?} {:?}",
296+
self.display,
297+
self.pbuffer,
298+
self.raw
299+
);
294300
self.instance
295301
.make_current(self.display, self.pbuffer, self.pbuffer, Some(self.raw))
296302
.unwrap();
@@ -697,6 +703,7 @@ impl Inner {
697703
version,
698704
supports_native_window,
699705
config,
706+
// Will in some scenarios be overwritten by the caller after this function returns.
700707
wl_display: None,
701708
srgb_kind,
702709
force_gles_minor_version,
@@ -839,7 +846,10 @@ impl crate::Instance for Instance {
839846

840847
let (display, display_owner, wsi_kind) =
841848
if let (Some(library), Some(egl)) = (wayland_library, egl1_5) {
842-
log::info!("Using Wayland platform");
849+
// XXX: Drop this code and convert `Inner` to an `Option` so that we can
850+
// force-initialize this whenever the "RawDisplayHandle" is available (currently
851+
// only via the surface)...
852+
log::error!("Using Wayland platform, creating nonfunctional bogus display first");
843853
let display_attributes = [khronos_egl::ATTRIB_NONE];
844854
let display = unsafe {
845855
egl.get_platform_display(
@@ -969,6 +979,7 @@ impl crate::Instance for Instance {
969979
)
970980
.unwrap();
971981

982+
// TODO: Why?
972983
let ret = unsafe {
973984
ndk_sys::ANativeWindow_setBuffersGeometry(
974985
handle
@@ -1013,6 +1024,7 @@ impl crate::Instance for Instance {
10131024
.unwrap()
10141025
.get_platform_display(
10151026
EGL_PLATFORM_WAYLAND_KHR,
1027+
// khronos_egl::DEFAULT_DISPLAY,
10161028
display_handle.display.as_ptr(),
10171029
&display_attributes,
10181030
)
@@ -1056,9 +1068,22 @@ impl crate::Instance for Instance {
10561068

10571069
unsafe fn enumerate_adapters(
10581070
&self,
1059-
_surface_hint: Option<&Surface>,
1071+
surface_hint: Option<&Surface>,
10601072
) -> Vec<crate::ExposedAdapter<super::Api>> {
10611073
let inner = self.inner.lock();
1074+
1075+
if let Some(surface) = surface_hint {
1076+
assert_eq!(surface.egl.raw, inner.egl.raw);
1077+
} else
1078+
// if inner.??? == Wayland
1079+
{
1080+
// This is a trick from Web, but it's too restrictive and not needed if the user
1081+
// initializes in the right order.
1082+
// TODO: We can probably also allow the user through if inner.wl_surface is not NULL?
1083+
log::info!("Returning zero adapters on Wayland unless a surface is passed");
1084+
return vec![];
1085+
}
1086+
10621087
inner.egl.make_current();
10631088

10641089
let mut gl = unsafe {
@@ -1313,6 +1338,7 @@ impl crate::Surface for Surface {
13131338
let wl_egl_window_create: libloading::Symbol<WlEglWindowCreateFun> =
13141339
unsafe { library.get(c"wl_egl_window_create".to_bytes()) }.unwrap();
13151340
let window =
1341+
// XXX: Why hardocde a random size here, over using config.extent?
13161342
unsafe { wl_egl_window_create(handle.surface.as_ptr(), 640, 480) }
13171343
.cast();
13181344
wl_window = Some(window);

wgpu-types/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ pub struct RequestAdapterOptions<S> {
361361
pub force_fallback_adapter: bool,
362362
/// Surface that is required to be presentable with the requested adapter. This does not
363363
/// create the surface, only guarantees that the adapter can present to said surface.
364-
/// For WebGL, this is strictly required, as an adapter can not be created without a surface.
364+
/// For WebGL and Wayland, this is strictly required, as an adapter can not be created without a surface.
365365
pub compatible_surface: Option<S>,
366366
}
367367

0 commit comments

Comments
 (0)