1 | //! Everything related to `EGLSurface`. |
2 | |
3 | use std::marker::PhantomData; |
4 | use std::num::NonZeroU32; |
5 | use std::{ffi, fmt}; |
6 | |
7 | use glutin_egl_sys::egl; |
8 | use glutin_egl_sys::egl::types::{EGLAttrib, EGLSurface, EGLint}; |
9 | use raw_window_handle::RawWindowHandle; |
10 | #[cfg (wayland_platform)] |
11 | use wayland_sys::{egl::*, ffi_dispatch}; |
12 | |
13 | use crate::api::egl::display::EglDisplay; |
14 | use crate::config::GetGlConfig; |
15 | use crate::display::GetGlDisplay; |
16 | use crate::error::{ErrorKind, Result}; |
17 | use crate::prelude::*; |
18 | use crate::private::Sealed; |
19 | use crate::surface::{ |
20 | AsRawSurface, NativePixmap, PbufferSurface, PixmapSurface, RawSurface, Rect, SurfaceAttributes, |
21 | SurfaceTypeTrait, SwapInterval, WindowSurface, |
22 | }; |
23 | |
24 | use super::config::Config; |
25 | use super::context::PossiblyCurrentContext; |
26 | use super::display::Display; |
27 | |
28 | /// Hint for the attribute list size. |
29 | const ATTR_SIZE_HINT: usize = 8; |
30 | |
31 | impl Display { |
32 | pub(crate) unsafe fn create_pbuffer_surface( |
33 | &self, |
34 | config: &Config, |
35 | surface_attributes: &SurfaceAttributes<PbufferSurface>, |
36 | ) -> Result<Surface<PbufferSurface>> { |
37 | let width = surface_attributes.width.unwrap(); |
38 | let height = surface_attributes.height.unwrap(); |
39 | |
40 | // XXX Window surface is using `EGLAttrib` and not `EGLint`. |
41 | let mut attrs = Vec::<EGLint>::with_capacity(ATTR_SIZE_HINT); |
42 | |
43 | // Add dimensions. |
44 | attrs.push(egl::WIDTH as EGLint); |
45 | attrs.push(width.get() as EGLint); |
46 | |
47 | attrs.push(egl::HEIGHT as EGLint); |
48 | attrs.push(height.get() as EGLint); |
49 | |
50 | // Push `egl::NONE` to terminate the list. |
51 | attrs.push(egl::NONE as EGLint); |
52 | |
53 | let config = config.clone(); |
54 | let surface = unsafe { |
55 | Self::check_surface_error(self.inner.egl.CreatePbufferSurface( |
56 | *self.inner.raw, |
57 | *config.inner.raw, |
58 | attrs.as_ptr(), |
59 | ))? |
60 | }; |
61 | |
62 | Ok(Surface { |
63 | display: self.clone(), |
64 | native_window: None, |
65 | config, |
66 | raw: surface, |
67 | _ty: PhantomData, |
68 | }) |
69 | } |
70 | |
71 | pub(crate) unsafe fn create_pixmap_surface( |
72 | &self, |
73 | config: &Config, |
74 | surface_attributes: &SurfaceAttributes<PixmapSurface>, |
75 | ) -> Result<Surface<PixmapSurface>> { |
76 | let native_pixmap = surface_attributes.native_pixmap.as_ref().unwrap(); |
77 | |
78 | let mut attrs = Vec::<EGLAttrib>::with_capacity(ATTR_SIZE_HINT); |
79 | |
80 | if surface_attributes.srgb.is_some() && config.srgb_capable() { |
81 | attrs.push(egl::GL_COLORSPACE as EGLAttrib); |
82 | let colorspace = match surface_attributes.srgb { |
83 | Some(true) => egl::GL_COLORSPACE_SRGB as EGLAttrib, |
84 | _ => egl::GL_COLORSPACE_LINEAR as EGLAttrib, |
85 | }; |
86 | attrs.push(colorspace); |
87 | } |
88 | |
89 | // Push `egl::NONE` to terminate the list. |
90 | attrs.push(egl::NONE as EGLAttrib); |
91 | |
92 | let config = config.clone(); |
93 | let surface = match self.inner.raw { |
94 | EglDisplay::Khr(display) => { |
95 | let platform_pixmap = native_pixmap.as_platform_pixmap(); |
96 | if platform_pixmap.is_null() { |
97 | return Err(ErrorKind::BadNativePixmap.into()); |
98 | } |
99 | unsafe { |
100 | self.inner.egl.CreatePlatformPixmapSurface( |
101 | display, |
102 | *config.inner.raw, |
103 | platform_pixmap, |
104 | attrs.as_ptr(), |
105 | ) |
106 | } |
107 | }, |
108 | EglDisplay::Ext(display) => { |
109 | let platform_pixmap = native_pixmap.as_platform_pixmap(); |
110 | if platform_pixmap.is_null() { |
111 | return Err(ErrorKind::BadNativePixmap.into()); |
112 | } |
113 | unsafe { |
114 | let attrs: Vec<EGLint> = attrs.into_iter().map(|attr| attr as EGLint).collect(); |
115 | self.inner.egl.CreatePlatformPixmapSurfaceEXT( |
116 | display, |
117 | *config.inner.raw, |
118 | platform_pixmap, |
119 | attrs.as_ptr(), |
120 | ) |
121 | } |
122 | }, |
123 | EglDisplay::Legacy(display) => { |
124 | let native_pixmap = native_pixmap.as_native_pixmap(); |
125 | |
126 | #[cfg (not(windows))] |
127 | if native_pixmap.is_null() { |
128 | return Err(ErrorKind::BadNativePixmap.into()); |
129 | } |
130 | |
131 | #[cfg (windows)] |
132 | if native_pixmap == 0 { |
133 | return Err(ErrorKind::BadNativePixmap.into()); |
134 | } |
135 | |
136 | unsafe { |
137 | // This call accepts raw value, instead of pointer. |
138 | let attrs: Vec<EGLint> = attrs.into_iter().map(|attr| attr as EGLint).collect(); |
139 | self.inner.egl.CreatePixmapSurface( |
140 | display, |
141 | *config.inner.raw, |
142 | native_pixmap, |
143 | attrs.as_ptr(), |
144 | ) |
145 | } |
146 | }, |
147 | }; |
148 | |
149 | let surface = Self::check_surface_error(surface)?; |
150 | |
151 | Ok(Surface { |
152 | display: self.clone(), |
153 | config, |
154 | native_window: None, |
155 | raw: surface, |
156 | _ty: PhantomData, |
157 | }) |
158 | } |
159 | |
160 | pub(crate) unsafe fn create_window_surface( |
161 | &self, |
162 | config: &Config, |
163 | surface_attributes: &SurfaceAttributes<WindowSurface>, |
164 | ) -> Result<Surface<WindowSurface>> { |
165 | // Create native window. |
166 | let native_window = NativeWindow::new( |
167 | surface_attributes.width.unwrap(), |
168 | surface_attributes.height.unwrap(), |
169 | surface_attributes.raw_window_handle.as_ref().unwrap(), |
170 | )?; |
171 | |
172 | // XXX Window surface is using `EGLAttrib` and not `EGLint`. |
173 | let mut attrs = Vec::<EGLAttrib>::with_capacity(ATTR_SIZE_HINT); |
174 | |
175 | // Add information about render buffer. |
176 | attrs.push(egl::RENDER_BUFFER as EGLAttrib); |
177 | let buffer = |
178 | if surface_attributes.single_buffer { egl::SINGLE_BUFFER } else { egl::BACK_BUFFER } |
179 | as EGLAttrib; |
180 | attrs.push(buffer); |
181 | |
182 | // // Add colorspace if the extension is present. |
183 | if surface_attributes.srgb.is_some() && config.srgb_capable() { |
184 | attrs.push(egl::GL_COLORSPACE as EGLAttrib); |
185 | let colorspace = match surface_attributes.srgb { |
186 | Some(true) => egl::GL_COLORSPACE_SRGB as EGLAttrib, |
187 | _ => egl::GL_COLORSPACE_LINEAR as EGLAttrib, |
188 | }; |
189 | attrs.push(colorspace); |
190 | } |
191 | |
192 | // Push `egl::NONE` to terminate the list. |
193 | attrs.push(egl::NONE as EGLAttrib); |
194 | |
195 | let config = config.clone(); |
196 | |
197 | let surface = match self.inner.raw { |
198 | EglDisplay::Khr(display) => unsafe { |
199 | self.inner.egl.CreatePlatformWindowSurface( |
200 | display, |
201 | *config.inner.raw, |
202 | native_window.as_platform_window(), |
203 | attrs.as_ptr(), |
204 | ) |
205 | }, |
206 | EglDisplay::Ext(display) => unsafe { |
207 | let attrs: Vec<EGLint> = attrs.into_iter().map(|attr| attr as EGLint).collect(); |
208 | self.inner.egl.CreatePlatformWindowSurfaceEXT( |
209 | display, |
210 | *config.inner.raw, |
211 | native_window.as_platform_window(), |
212 | attrs.as_ptr(), |
213 | ) |
214 | }, |
215 | EglDisplay::Legacy(display) => unsafe { |
216 | let attrs: Vec<EGLint> = attrs.into_iter().map(|attr| attr as EGLint).collect(); |
217 | self.inner.egl.CreateWindowSurface( |
218 | display, |
219 | *config.inner.raw, |
220 | native_window.as_native_window(), |
221 | attrs.as_ptr(), |
222 | ) |
223 | }, |
224 | }; |
225 | |
226 | let surface = Self::check_surface_error(surface)?; |
227 | |
228 | Ok(Surface { |
229 | display: self.clone(), |
230 | config, |
231 | native_window: Some(native_window), |
232 | raw: surface, |
233 | _ty: PhantomData, |
234 | }) |
235 | } |
236 | |
237 | fn check_surface_error(surface: EGLSurface) -> Result<EGLSurface> { |
238 | if surface == egl::NO_SURFACE { |
239 | Err(super::check_error().err().unwrap()) |
240 | } else { |
241 | Ok(surface) |
242 | } |
243 | } |
244 | } |
245 | |
246 | /// A wrapper around `EGLSurface`. |
247 | pub struct Surface<T: SurfaceTypeTrait> { |
248 | display: Display, |
249 | config: Config, |
250 | pub(crate) raw: EGLSurface, |
251 | native_window: Option<NativeWindow>, |
252 | _ty: PhantomData<T>, |
253 | } |
254 | |
255 | // Impl only `Send` for Surface. |
256 | unsafe impl<T: SurfaceTypeTrait> Send for Surface<T> {} |
257 | |
258 | impl<T: SurfaceTypeTrait> Surface<T> { |
259 | /// Swaps the underlying back buffers when the surface is not single |
260 | /// buffered and pass the [`Rect`] information to the system |
261 | /// compositor. Providing empty slice will damage the entire surface. |
262 | /// |
263 | /// When the underlying extensions are not supported the function acts like |
264 | /// [`Self::swap_buffers`]. |
265 | /// |
266 | /// This Api doesn't do any partial rendering, it just provides hints for |
267 | /// the system compositor. |
268 | pub fn swap_buffers_with_damage( |
269 | &self, |
270 | context: &PossiblyCurrentContext, |
271 | rects: &[Rect], |
272 | ) -> Result<()> { |
273 | context.inner.bind_api(); |
274 | |
275 | let res = unsafe { |
276 | if self.display.inner.display_extensions.contains("EGL_KHR_swap_buffers_with_damage" ) { |
277 | self.display.inner.egl.SwapBuffersWithDamageKHR( |
278 | *self.display.inner.raw, |
279 | self.raw, |
280 | rects.as_ptr() as *mut _, |
281 | rects.len() as _, |
282 | ) |
283 | } else if self |
284 | .display |
285 | .inner |
286 | .display_extensions |
287 | .contains("EGL_EXT_swap_buffers_with_damage" ) |
288 | { |
289 | self.display.inner.egl.SwapBuffersWithDamageEXT( |
290 | *self.display.inner.raw, |
291 | self.raw, |
292 | rects.as_ptr() as *mut _, |
293 | rects.len() as _, |
294 | ) |
295 | } else { |
296 | self.display.inner.egl.SwapBuffers(*self.display.inner.raw, self.raw) |
297 | } |
298 | }; |
299 | |
300 | if res == egl::FALSE { |
301 | super::check_error() |
302 | } else { |
303 | Ok(()) |
304 | } |
305 | } |
306 | |
307 | /// # Safety |
308 | /// |
309 | /// The caller must ensure that the attribute could be present. |
310 | unsafe fn raw_attribute(&self, attr: EGLint) -> EGLint { |
311 | unsafe { |
312 | let mut value = 0; |
313 | self.display.inner.egl.QuerySurface( |
314 | *self.display.inner.raw, |
315 | self.raw, |
316 | attr, |
317 | &mut value, |
318 | ); |
319 | value |
320 | } |
321 | } |
322 | } |
323 | |
324 | impl<T: SurfaceTypeTrait> Drop for Surface<T> { |
325 | fn drop(&mut self) { |
326 | unsafe { |
327 | self.display.inner.egl.DestroySurface(*self.display.inner.raw, self.raw); |
328 | } |
329 | } |
330 | } |
331 | |
332 | impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> { |
333 | type Context = PossiblyCurrentContext; |
334 | type SurfaceType = T; |
335 | |
336 | fn buffer_age(&self) -> u32 { |
337 | self.display |
338 | .inner |
339 | .display_extensions |
340 | .contains("EGL_EXT_buffer_age" ) |
341 | .then(|| unsafe { self.raw_attribute(egl::BUFFER_AGE_EXT as EGLint) }) |
342 | .unwrap_or(0) as u32 |
343 | } |
344 | |
345 | fn width(&self) -> Option<u32> { |
346 | unsafe { Some(self.raw_attribute(egl::WIDTH as EGLint) as u32) } |
347 | } |
348 | |
349 | fn height(&self) -> Option<u32> { |
350 | unsafe { Some(self.raw_attribute(egl::HEIGHT as EGLint) as u32) } |
351 | } |
352 | |
353 | fn is_single_buffered(&self) -> bool { |
354 | unsafe { self.raw_attribute(egl::RENDER_BUFFER as EGLint) == egl::SINGLE_BUFFER as i32 } |
355 | } |
356 | |
357 | fn swap_buffers(&self, context: &Self::Context) -> Result<()> { |
358 | unsafe { |
359 | context.inner.bind_api(); |
360 | |
361 | if self.display.inner.egl.SwapBuffers(*self.display.inner.raw, self.raw) == egl::FALSE { |
362 | super::check_error() |
363 | } else { |
364 | Ok(()) |
365 | } |
366 | } |
367 | } |
368 | |
369 | fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()> { |
370 | unsafe { |
371 | context.inner.bind_api(); |
372 | |
373 | let interval = match interval { |
374 | SwapInterval::DontWait => 0, |
375 | SwapInterval::Wait(interval) => interval.get() as EGLint, |
376 | }; |
377 | if self.display.inner.egl.SwapInterval(*self.display.inner.raw, interval) == egl::FALSE |
378 | { |
379 | super::check_error() |
380 | } else { |
381 | Ok(()) |
382 | } |
383 | } |
384 | } |
385 | |
386 | fn is_current(&self, context: &Self::Context) -> bool { |
387 | self.is_current_draw(context) && self.is_current_read(context) |
388 | } |
389 | |
390 | fn is_current_draw(&self, context: &Self::Context) -> bool { |
391 | unsafe { |
392 | context.inner.bind_api(); |
393 | self.display.inner.egl.GetCurrentSurface(egl::DRAW as EGLint) == self.raw |
394 | } |
395 | } |
396 | |
397 | fn is_current_read(&self, context: &Self::Context) -> bool { |
398 | unsafe { |
399 | context.inner.bind_api(); |
400 | self.display.inner.egl.GetCurrentSurface(egl::READ as EGLint) == self.raw |
401 | } |
402 | } |
403 | |
404 | fn resize(&self, _context: &Self::Context, width: NonZeroU32, height: NonZeroU32) { |
405 | self.native_window.as_ref().unwrap().resize(width, height) |
406 | } |
407 | } |
408 | |
409 | impl<T: SurfaceTypeTrait> GetGlConfig for Surface<T> { |
410 | type Target = Config; |
411 | |
412 | fn config(&self) -> Self::Target { |
413 | self.config.clone() |
414 | } |
415 | } |
416 | |
417 | impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> { |
418 | type Target = Display; |
419 | |
420 | fn display(&self) -> Self::Target { |
421 | self.display.clone() |
422 | } |
423 | } |
424 | |
425 | impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> { |
426 | fn raw_surface(&self) -> RawSurface { |
427 | RawSurface::Egl(self.raw) |
428 | } |
429 | } |
430 | |
431 | impl<T: SurfaceTypeTrait> fmt::Debug for Surface<T> { |
432 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
433 | f&mut DebugStruct<'_, '_>.debug_struct("Surface" ) |
434 | .field("display" , &self.display.inner.raw) |
435 | .field("config" , &self.config.inner.raw) |
436 | .field("raw" , &self.raw) |
437 | .field("native_window" , &self.native_window) |
438 | .field(name:"type" , &T::surface_type()) |
439 | .finish() |
440 | } |
441 | } |
442 | |
443 | impl<T: SurfaceTypeTrait> Sealed for Surface<T> {} |
444 | |
445 | #[derive (Debug)] |
446 | enum NativeWindow { |
447 | #[cfg (wayland_platform)] |
448 | Wayland(*mut ffi::c_void), |
449 | |
450 | #[cfg (x11_platform)] |
451 | Xlib(std::os::raw::c_ulong), |
452 | |
453 | #[cfg (x11_platform)] |
454 | Xcb(u32), |
455 | |
456 | #[cfg (android_platform)] |
457 | Android(*mut ffi::c_void), |
458 | |
459 | #[cfg (windows)] |
460 | Win32(isize), |
461 | |
462 | #[cfg (free_unix)] |
463 | Gbm(*mut ffi::c_void), |
464 | } |
465 | |
466 | impl NativeWindow { |
467 | fn new( |
468 | _width: NonZeroU32, |
469 | _height: NonZeroU32, |
470 | raw_window_handle: &RawWindowHandle, |
471 | ) -> Result<Self> { |
472 | let native_window = match raw_window_handle { |
473 | #[cfg (wayland_platform)] |
474 | RawWindowHandle::Wayland(window_handle) => unsafe { |
475 | if window_handle.surface.is_null() { |
476 | return Err(ErrorKind::BadNativeWindow.into()); |
477 | } |
478 | |
479 | let ptr = ffi_dispatch!( |
480 | wayland_egl_handle(), |
481 | wl_egl_window_create, |
482 | window_handle.surface.cast(), |
483 | _width.get() as _, |
484 | _height.get() as _ |
485 | ); |
486 | if ptr.is_null() { |
487 | return Err(ErrorKind::OutOfMemory.into()); |
488 | } |
489 | Self::Wayland(ptr.cast()) |
490 | }, |
491 | #[cfg (x11_platform)] |
492 | RawWindowHandle::Xlib(window_handle) => { |
493 | if window_handle.window == 0 { |
494 | return Err(ErrorKind::BadNativeWindow.into()); |
495 | } |
496 | |
497 | Self::Xlib(window_handle.window as _) |
498 | }, |
499 | #[cfg (x11_platform)] |
500 | RawWindowHandle::Xcb(window_handle) => { |
501 | if window_handle.window == 0 { |
502 | return Err(ErrorKind::BadNativeWindow.into()); |
503 | } |
504 | |
505 | Self::Xcb(window_handle.window as _) |
506 | }, |
507 | #[cfg (android_platform)] |
508 | RawWindowHandle::AndroidNdk(window_handle) => { |
509 | if window_handle.a_native_window.is_null() { |
510 | return Err(ErrorKind::BadNativeWindow.into()); |
511 | } |
512 | |
513 | Self::Android(window_handle.a_native_window) |
514 | }, |
515 | #[cfg (windows)] |
516 | RawWindowHandle::Win32(window_handle) => { |
517 | if window_handle.hwnd.is_null() { |
518 | return Err(ErrorKind::BadNativeWindow.into()); |
519 | } |
520 | |
521 | Self::Win32(window_handle.hwnd as _) |
522 | }, |
523 | #[cfg (free_unix)] |
524 | RawWindowHandle::Gbm(window_handle) => { |
525 | if window_handle.gbm_surface.is_null() { |
526 | return Err(ErrorKind::BadNativeWindow.into()); |
527 | } |
528 | |
529 | Self::Gbm(window_handle.gbm_surface) |
530 | }, |
531 | _ => { |
532 | return Err( |
533 | ErrorKind::NotSupported("provided native window is not supported" ).into() |
534 | ) |
535 | }, |
536 | }; |
537 | |
538 | Ok(native_window) |
539 | } |
540 | |
541 | fn resize(&self, _width: NonZeroU32, _height: NonZeroU32) { |
542 | #[cfg (wayland_platform)] |
543 | if let Self::Wayland(wl_egl_surface) = self { |
544 | unsafe { |
545 | ffi_dispatch!( |
546 | wayland_egl_handle(), |
547 | wl_egl_window_resize, |
548 | *wl_egl_surface as _, |
549 | _width.get() as _, |
550 | _height.get() as _, |
551 | 0, |
552 | 0 |
553 | ) |
554 | } |
555 | } |
556 | } |
557 | |
558 | /// Returns the underlying handle value. |
559 | fn as_native_window(&self) -> egl::NativeWindowType { |
560 | match *self { |
561 | #[cfg (wayland_platform)] |
562 | Self::Wayland(wl_egl_surface) => wl_egl_surface, |
563 | #[cfg (x11_platform)] |
564 | Self::Xlib(window_id) => window_id as egl::NativeWindowType, |
565 | #[cfg (x11_platform)] |
566 | Self::Xcb(window_id) => window_id as egl::NativeWindowType, |
567 | #[cfg (windows)] |
568 | Self::Win32(hwnd) => hwnd, |
569 | #[cfg (android_platform)] |
570 | Self::Android(a_native_window) => a_native_window, |
571 | #[cfg (free_unix)] |
572 | Self::Gbm(gbm_surface) => gbm_surface, |
573 | } |
574 | } |
575 | |
576 | /// Returns a pointer to the underlying handle value on X11, |
577 | /// the raw underlying handle value on all other platforms. |
578 | /// |
579 | /// This exists because of a discrepancy in the new |
580 | /// `eglCreatePlatformWindowSurface*` functions which take a pointer to the |
581 | /// `window_id` on X11 and Xlib, in contrast to the legacy |
582 | /// `eglCreateWindowSurface` which always takes the raw value. |
583 | /// |
584 | /// See also: |
585 | /// <https://gitlab.freedesktop.org/mesa/mesa/-/blob/4de9a4b2b8c41864aadae89be705ef125a745a0a/src/egl/main/eglapi.c#L1102-1127> |
586 | /// |
587 | /// # Safety |
588 | /// |
589 | /// On X11 the returned pointer is a cast of the `&self` borrow. |
590 | fn as_platform_window(&self) -> *mut ffi::c_void { |
591 | match self { |
592 | #[cfg (wayland_platform)] |
593 | Self::Wayland(wl_egl_surface) => *wl_egl_surface, |
594 | #[cfg (x11_platform)] |
595 | Self::Xlib(window_id) => window_id as *const _ as *mut ffi::c_void, |
596 | #[cfg (x11_platform)] |
597 | Self::Xcb(window_id) => window_id as *const _ as *mut ffi::c_void, |
598 | #[cfg (windows)] |
599 | Self::Win32(hwnd) => *hwnd as *const ffi::c_void as *mut _, |
600 | #[cfg (android_platform)] |
601 | Self::Android(a_native_window) => *a_native_window, |
602 | #[cfg (free_unix)] |
603 | Self::Gbm(gbm_surface) => *gbm_surface, |
604 | } |
605 | } |
606 | } |
607 | |
608 | #[cfg (wayland_platform)] |
609 | impl Drop for NativeWindow { |
610 | fn drop(&mut self) { |
611 | unsafe { |
612 | if let Self::Wayland(wl_egl_window: &mut *mut c_void) = self { |
613 | ffi_dispatch!(wayland_egl_handle(), wl_egl_window_destroy, wl_egl_window.cast()); |
614 | } |
615 | } |
616 | } |
617 | } |
618 | |
619 | impl NativePixmap { |
620 | /// Returns the underlying handle value. |
621 | fn as_native_pixmap(&self) -> egl::NativePixmapType { |
622 | match *self { |
623 | Self::XlibPixmap(xid) => xid as egl::NativePixmapType, |
624 | Self::XcbPixmap(xid) => xid as egl::NativePixmapType, |
625 | Self::WindowsPixmap(hbitmap) => hbitmap as egl::NativePixmapType, |
626 | } |
627 | } |
628 | |
629 | /// Returns a pointer to the underlying handle value on X11, |
630 | /// the raw underlying handle value on all other platforms. |
631 | /// |
632 | /// This exists because of a discrepancy in the new |
633 | /// `eglCreatePlatformPixmapSurface*` functions which take a pointer to the |
634 | /// `xid` on X11 and Xlib, in contrast to the legacy |
635 | /// `eglCreatePixmapSurface` which always takes the raw value. |
636 | /// |
637 | /// See also: |
638 | /// <https://gitlab.freedesktop.org/mesa/mesa/-/blob/4de9a4b2b8c41864aadae89be705ef125a745a0a/src/egl/main/eglapi.c#L1166-1190> |
639 | /// |
640 | /// # Safety |
641 | /// |
642 | /// On X11 the returned pointer is a cast of the `&self` borrow. |
643 | fn as_platform_pixmap(&self) -> *mut ffi::c_void { |
644 | match self { |
645 | Self::XlibPixmap(xid) => xid as *const _ as *mut _, |
646 | Self::XcbPixmap(xid) => xid as *const _ as *mut _, |
647 | Self::WindowsPixmap(hbitmap) => *hbitmap as *const ffi::c_void as *mut _, |
648 | } |
649 | } |
650 | } |
651 | |