glutin/api/glx/
surface.rs

1//! Everything related to the GLXWindow.
2
3use std::fmt;
4use std::marker::PhantomData;
5use std::num::NonZeroU32;
6use std::os::raw::{c_int, c_uint};
7
8use glutin_glx_sys::glx::types::GLXWindow;
9use glutin_glx_sys::{glx, glx_extra};
10use raw_window_handle::RawWindowHandle;
11
12use crate::config::GetGlConfig;
13use crate::display::{DisplayFeatures, GetGlDisplay};
14use crate::error::{ErrorKind, Result};
15use crate::private::Sealed;
16use crate::surface::{
17    AsRawSurface, GlSurface, NativePixmap, PbufferSurface, PixmapSurface, RawSurface,
18    SurfaceAttributes, SurfaceType, SurfaceTypeTrait, SwapInterval, WindowSurface,
19};
20
21use super::config::Config;
22use super::context::PossiblyCurrentContext;
23use super::display::Display;
24
25/// Hint for the attributes array.
26const ATTR_SIZE_HINT: usize = 8;
27
28impl Display {
29    pub(crate) unsafe fn create_pixmap_surface(
30        &self,
31        config: &Config,
32        surface_attributes: &SurfaceAttributes<PixmapSurface>,
33    ) -> Result<Surface<PixmapSurface>> {
34        let native_pixmap = surface_attributes.native_pixmap.as_ref().unwrap();
35        let xid = match native_pixmap {
36            NativePixmap::XlibPixmap(xid) => {
37                if *xid == 0 {
38                    return Err(ErrorKind::BadNativePixmap.into());
39                }
40
41                *xid
42            },
43            _ => {
44                return Err(
45                    ErrorKind::NotSupported("provided native pixmap is not supported.").into()
46                )
47            },
48        };
49
50        let mut attrs = Vec::<c_int>::with_capacity(ATTR_SIZE_HINT);
51
52        // Push X11 `None` to terminate the list.
53        attrs.push(0);
54
55        let config = config.clone();
56        let surface = super::last_glx_error(|| unsafe {
57            self.inner.glx.CreatePixmap(
58                self.inner.raw.cast(),
59                *config.inner.raw,
60                xid,
61                attrs.as_ptr(),
62            )
63        })?;
64
65        Ok(Surface {
66            display: self.clone(),
67            config,
68            raw: surface,
69            _nosendsync: PhantomData,
70            _ty: PhantomData,
71        })
72    }
73
74    pub(crate) unsafe fn create_pbuffer_surface(
75        &self,
76        config: &Config,
77        surface_attributes: &SurfaceAttributes<PbufferSurface>,
78    ) -> Result<Surface<PbufferSurface>> {
79        let width = surface_attributes.width.unwrap();
80        let height = surface_attributes.height.unwrap();
81
82        let mut attrs = Vec::<c_int>::with_capacity(ATTR_SIZE_HINT);
83
84        attrs.push(glx::PBUFFER_WIDTH as c_int);
85        attrs.push(width.get() as c_int);
86        attrs.push(glx::PBUFFER_HEIGHT as c_int);
87        attrs.push(height.get() as c_int);
88        attrs.push(glx::LARGEST_PBUFFER as c_int);
89        attrs.push(surface_attributes.largest_pbuffer as c_int);
90
91        // Push X11 `None` to terminate the list.
92        attrs.push(0);
93
94        let config = config.clone();
95        let surface = super::last_glx_error(|| unsafe {
96            self.inner.glx.CreatePbuffer(self.inner.raw.cast(), *config.inner.raw, attrs.as_ptr())
97        })?;
98
99        Ok(Surface {
100            display: self.clone(),
101            config,
102            raw: surface,
103            _nosendsync: PhantomData,
104            _ty: PhantomData,
105        })
106    }
107
108    pub(crate) unsafe fn create_window_surface(
109        &self,
110        config: &Config,
111        surface_attributes: &SurfaceAttributes<WindowSurface>,
112    ) -> Result<Surface<WindowSurface>> {
113        let window = match surface_attributes.raw_window_handle.unwrap() {
114            RawWindowHandle::Xlib(window_handle) => {
115                if window_handle.window == 0 {
116                    return Err(ErrorKind::BadNativeWindow.into());
117                }
118
119                window_handle.window
120            },
121            _ => {
122                return Err(
123                    ErrorKind::NotSupported("provided native window is not supported").into()
124                )
125            },
126        };
127
128        let mut attrs = Vec::<c_int>::with_capacity(ATTR_SIZE_HINT);
129
130        // Push X11 `None` to terminate the list.
131        attrs.push(0);
132
133        let config = config.clone();
134        let surface = super::last_glx_error(|| unsafe {
135            self.inner.glx.CreateWindow(
136                self.inner.raw.cast(),
137                *config.inner.raw,
138                window,
139                attrs.as_ptr() as *const _,
140            )
141        })?;
142
143        Ok(Surface {
144            display: self.clone(),
145            config,
146            raw: surface,
147            _nosendsync: PhantomData,
148            _ty: PhantomData,
149        })
150    }
151}
152
153/// A wrapper around the `GLXWindow`.
154pub struct Surface<T: SurfaceTypeTrait> {
155    display: Display,
156    config: Config,
157    pub(crate) raw: GLXWindow,
158    _nosendsync: PhantomData<*const std::ffi::c_void>,
159    _ty: PhantomData<T>,
160}
161
162// Impl only `Send` for Surface.
163unsafe impl<T: SurfaceTypeTrait> Send for Surface<T> {}
164
165impl<T: SurfaceTypeTrait> Surface<T> {
166    /// # Safety
167    ///
168    /// The caller must ensure that the attribute could be present.
169    unsafe fn raw_attribute(&self, attr: c_int) -> c_uint {
170        unsafe {
171            let mut value = 0;
172            // This shouldn't generate any errors given that we know that the surface is
173            // valid.
174            self.display.inner.glx.QueryDrawable(
175                self.display.inner.raw.cast(),
176                self.raw,
177                attr,
178                &mut value,
179            );
180            value
181        }
182    }
183}
184
185impl<T: SurfaceTypeTrait> Drop for Surface<T> {
186    fn drop(&mut self) {
187        let _ = super::last_glx_error(|| unsafe {
188            match T::surface_type() {
189                SurfaceType::Pbuffer => {
190                    self.display.inner.glx.DestroyPbuffer(self.display.inner.raw.cast(), self.raw);
191                },
192                SurfaceType::Window => {
193                    self.display.inner.glx.DestroyWindow(self.display.inner.raw.cast(), self.raw);
194                },
195                SurfaceType::Pixmap => {
196                    self.display.inner.glx.DestroyPixmap(self.display.inner.raw.cast(), self.raw);
197                },
198            }
199        });
200    }
201}
202
203impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
204    type Context = PossiblyCurrentContext;
205    type SurfaceType = T;
206
207    fn buffer_age(&self) -> u32 {
208        self.display
209            .inner
210            .client_extensions
211            .contains("GLX_EXT_buffer_age")
212            .then(|| unsafe { self.raw_attribute(glx_extra::BACK_BUFFER_AGE_EXT as c_int) })
213            .unwrap_or(0) as u32
214    }
215
216    fn width(&self) -> Option<u32> {
217        unsafe { Some(self.raw_attribute(glx::WIDTH as c_int) as u32) }
218    }
219
220    fn height(&self) -> Option<u32> {
221        unsafe { Some(self.raw_attribute(glx::HEIGHT as c_int) as u32) }
222    }
223
224    fn is_single_buffered(&self) -> bool {
225        self.config.is_single_buffered()
226    }
227
228    fn swap_buffers(&self, _context: &Self::Context) -> Result<()> {
229        super::last_glx_error(|| unsafe {
230            self.display.inner.glx.SwapBuffers(self.display.inner.raw.cast(), self.raw);
231        })
232    }
233
234    fn set_swap_interval(&self, _context: &Self::Context, interval: SwapInterval) -> Result<()> {
235        let extra = match self.display.inner.glx_extra {
236            Some(extra) if self.display.inner.features.contains(DisplayFeatures::SWAP_CONTROL) => {
237                extra
238            },
239            _ => {
240                return Err(
241                    ErrorKind::NotSupported("swap control extensions are not supported").into()
242                );
243            },
244        };
245
246        let interval = match interval {
247            SwapInterval::DontWait => 0,
248            SwapInterval::Wait(n) => n.get(),
249        };
250
251        let mut applied = false;
252
253        // Apply the `EXT` first since it's per window.
254        if !applied && self.display.inner.client_extensions.contains("GLX_EXT_swap_control") {
255            super::last_glx_error(|| unsafe {
256                // Check for error explicitly here, other apis do have indication for failure.
257                extra.SwapIntervalEXT(self.display.inner.raw.cast(), self.raw, interval as _);
258                applied = true;
259            })?;
260        }
261
262        if !applied && self.display.inner.client_extensions.contains("GLX_MESA_swap_control") {
263            unsafe {
264                applied = extra.SwapIntervalMESA(interval as _) != glx::BAD_CONTEXT as _;
265            }
266        }
267
268        if !applied && self.display.inner.client_extensions.contains("GLX_SGI_swap_control") {
269            unsafe {
270                applied = extra.SwapIntervalSGI(interval as _) != glx::BAD_CONTEXT as _;
271            }
272        }
273
274        if applied {
275            Ok(())
276        } else {
277            Err(ErrorKind::BadContext.into())
278        }
279    }
280
281    fn is_current(&self, context: &Self::Context) -> bool {
282        self.is_current_draw(context) && self.is_current_read(context)
283    }
284
285    fn is_current_draw(&self, _context: &Self::Context) -> bool {
286        unsafe { self.display.inner.glx.GetCurrentDrawable() == self.raw }
287    }
288
289    fn is_current_read(&self, _context: &Self::Context) -> bool {
290        unsafe { self.display.inner.glx.GetCurrentReadDrawable() == self.raw }
291    }
292
293    fn resize(&self, _context: &Self::Context, _width: NonZeroU32, _height: NonZeroU32) {
294        // This isn't supported with GLXDrawable.
295    }
296}
297
298impl<T: SurfaceTypeTrait> GetGlConfig for Surface<T> {
299    type Target = Config;
300
301    fn config(&self) -> Self::Target {
302        self.config.clone()
303    }
304}
305
306impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> {
307    type Target = Display;
308
309    fn display(&self) -> Self::Target {
310        self.display.clone()
311    }
312}
313
314impl<T: SurfaceTypeTrait> fmt::Debug for Surface<T> {
315    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316        f.debug_struct("Surface")
317            .field("display", &self.display.inner.raw)
318            .field("config", &self.config.inner.raw)
319            .field("raw", &self.raw)
320            .field("type", &T::surface_type())
321            .finish()
322    }
323}
324
325impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> {
326    fn raw_surface(&self) -> RawSurface {
327        RawSurface::Glx(self.raw as u64)
328    }
329}
330
331impl<T: SurfaceTypeTrait> Sealed for Surface<T> {}