1use std::collections::HashSet;
4use std::ffi::{self, CStr};
5use std::fmt;
6use std::ops::Deref;
7use std::sync::atomic::Ordering;
8use std::sync::Arc;
9
10use glutin_glx_sys::glx;
11use glutin_glx_sys::glx::types::Display as GLXDisplay;
12use raw_window_handle::RawDisplayHandle;
13
14use crate::config::ConfigTemplate;
15use crate::context::Version;
16use crate::display::{AsRawDisplay, DisplayFeatures, GetDisplayExtensions, RawDisplay};
17use crate::error::{ErrorKind, Result};
18use crate::prelude::*;
19use crate::private::Sealed;
20use crate::surface::{PbufferSurface, PixmapSurface, SurfaceAttributes, WindowSurface};
21
22use super::config::Config;
23use super::context::NotCurrentContext;
24use super::surface::Surface;
25use super::{Glx, GlxExtra, XlibErrorHookRegistrar, GLX, GLX_BASE_ERROR, GLX_EXTRA};
26
27#[derive(Debug, Clone)]
29pub struct Display {
30 pub(crate) inner: Arc<DisplayInner>,
31}
32
33impl Display {
34 pub unsafe fn new(
42 display: RawDisplayHandle,
43 error_hook_registrar: XlibErrorHookRegistrar,
44 ) -> Result<Self> {
45 let (display, screen) = match display {
47 RawDisplayHandle::Xlib(handle) => match handle.display {
48 Some(display) => (GlxDisplay(display.as_ptr() as *mut _), handle.screen as i32),
49 None => return Err(ErrorKind::BadDisplay.into()),
50 },
51 _ => {
52 return Err(
53 ErrorKind::NotSupported("provided native display isn't supported").into()
54 )
55 },
56 };
57
58 let glx = match GLX.as_ref() {
59 Some(glx) => glx,
60 None => return Err(ErrorKind::NotFound.into()),
61 };
62
63 unsafe {
65 let mut error_base = 0;
66 let mut event_base = 0;
67 if glx.QueryExtension(display.0, &mut error_base, &mut event_base) == 0 {
68 return Err(ErrorKind::InitializationFailed.into());
70 }
71 GLX_BASE_ERROR.store(error_base, Ordering::Relaxed);
72 }
73
74 let version = unsafe {
83 let (mut major, mut minor) = (0, 0);
84 if glx.QueryVersion(display.0, &mut major, &mut minor) == 0 {
85 return Err(ErrorKind::InitializationFailed.into());
86 }
87 Version::new(major as u8, minor as u8)
88 };
89
90 if version < Version::new(1, 3) {
91 return Err(ErrorKind::NotSupported("the glx below 1.3 isn't supported").into());
92 }
93
94 error_hook_registrar(Box::new(super::glx_error_hook));
96
97 let client_extensions = get_extensions(glx, display);
98 let features = Self::extract_display_features(&client_extensions, version);
99
100 let inner = Arc::new(DisplayInner {
101 raw: display,
102 glx,
103 glx_extra: GLX_EXTRA.as_ref(),
104 version,
105 screen,
106 features,
107 client_extensions,
108 });
109
110 Ok(Self { inner })
111 }
112
113 pub fn glx(&self) -> &'static Glx {
115 self.inner.glx
116 }
117
118 fn extract_display_features(
119 extensions: &HashSet<&'static str>,
120 version: Version,
121 ) -> DisplayFeatures {
122 let mut features = DisplayFeatures::empty();
123
124 features.set(
125 DisplayFeatures::MULTISAMPLING_PIXEL_FORMATS,
126 version >= Version::new(1, 4) || extensions.contains("GLX_ARB_multisample"),
127 );
128
129 features.set(
130 DisplayFeatures::FLOAT_PIXEL_FORMAT,
131 extensions.contains("GLX_ARB_fbconfig_float"),
132 );
133
134 features.set(
135 DisplayFeatures::SRGB_FRAMEBUFFERS,
136 extensions.contains("GLX_ARB_framebuffer_sRGB")
137 || extensions.contains("GLX_EXT_framebuffer_sRGB"),
138 );
139
140 features.set(
141 DisplayFeatures::CREATE_ES_CONTEXT,
142 extensions.contains("GLX_EXT_create_context_es2_profile")
143 || extensions.contains("GLX_EXT_create_context_es_profile"),
144 );
145
146 features.set(
147 DisplayFeatures::SWAP_CONTROL,
148 extensions.contains("GLX_EXT_swap_control")
149 || extensions.contains("GLX_SGI_swap_control")
150 || extensions.contains("GLX_MESA_swap_control"),
151 );
152
153 features.set(
154 DisplayFeatures::CONTEXT_ROBUSTNESS,
155 extensions.contains("GLX_ARB_create_context_robustness"),
156 );
157
158 features.set(
159 DisplayFeatures::CONTEXT_RELEASE_BEHAVIOR,
160 extensions.contains("GLX_ARB_context_flush_control"),
161 );
162
163 features.set(
164 DisplayFeatures::CONTEXT_NO_ERROR,
165 extensions.contains("GLX_ARB_create_context_no_error"),
166 );
167
168 features
169 }
170}
171
172impl GlDisplay for Display {
173 type Config = Config;
174 type NotCurrentContext = NotCurrentContext;
175 type PbufferSurface = Surface<PbufferSurface>;
176 type PixmapSurface = Surface<PixmapSurface>;
177 type WindowSurface = Surface<WindowSurface>;
178
179 unsafe fn find_configs(
180 &self,
181 template: ConfigTemplate,
182 ) -> Result<Box<dyn Iterator<Item = Self::Config> + '_>> {
183 unsafe { Self::find_configs(self, template) }
184 }
185
186 unsafe fn create_window_surface(
187 &self,
188 config: &Self::Config,
189 surface_attributes: &SurfaceAttributes<WindowSurface>,
190 ) -> Result<Self::WindowSurface> {
191 unsafe { Self::create_window_surface(self, config, surface_attributes) }
192 }
193
194 unsafe fn create_pbuffer_surface(
195 &self,
196 config: &Self::Config,
197 surface_attributes: &SurfaceAttributes<PbufferSurface>,
198 ) -> Result<Self::PbufferSurface> {
199 unsafe { Self::create_pbuffer_surface(self, config, surface_attributes) }
200 }
201
202 unsafe fn create_context(
203 &self,
204 config: &Self::Config,
205 context_attributes: &crate::context::ContextAttributes,
206 ) -> Result<Self::NotCurrentContext> {
207 unsafe { Self::create_context(self, config, context_attributes) }
208 }
209
210 unsafe fn create_pixmap_surface(
211 &self,
212 config: &Self::Config,
213 surface_attributes: &SurfaceAttributes<PixmapSurface>,
214 ) -> Result<Self::PixmapSurface> {
215 unsafe { Self::create_pixmap_surface(self, config, surface_attributes) }
216 }
217
218 fn get_proc_address(&self, addr: &CStr) -> *const ffi::c_void {
219 unsafe { self.inner.glx.GetProcAddress(addr.as_ptr() as *const _) as *const _ }
220 }
221
222 fn version_string(&self) -> String {
223 format!("GLX {}.{}", self.inner.version.major, self.inner.version.minor)
224 }
225
226 fn supported_features(&self) -> DisplayFeatures {
227 self.inner.features
228 }
229}
230
231impl GetDisplayExtensions for Display {
232 fn extensions(&self) -> &HashSet<&'static str> {
233 &self.inner.client_extensions
234 }
235}
236
237impl AsRawDisplay for Display {
238 fn raw_display(&self) -> RawDisplay {
239 RawDisplay::Glx(self.inner.raw.cast())
240 }
241}
242
243impl Sealed for Display {}
244
245pub(crate) struct DisplayInner {
246 pub(crate) glx: &'static Glx,
247 pub(crate) glx_extra: Option<&'static GlxExtra>,
248 pub(crate) raw: GlxDisplay,
249 pub(crate) screen: i32,
250 pub(crate) version: Version,
251 pub(crate) features: DisplayFeatures,
252 pub(crate) client_extensions: HashSet<&'static str>,
254}
255
256impl fmt::Debug for DisplayInner {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 f.debug_struct("Display")
259 .field("raw", &self.raw)
260 .field("version", &self.version)
261 .field("screen", &self.screen)
262 .field("features", &self.features)
263 .field("extensions", &self.client_extensions)
264 .finish()
265 }
266}
267
268#[derive(Debug, Clone, Copy)]
269pub(crate) struct GlxDisplay(*mut GLXDisplay);
270
271unsafe impl Send for GlxDisplay {}
272unsafe impl Sync for GlxDisplay {}
273
274impl Deref for GlxDisplay {
275 type Target = *mut GLXDisplay;
276
277 fn deref(&self) -> &Self::Target {
278 &self.0
279 }
280}
281
282fn get_extensions(glx: &Glx, display: GlxDisplay) -> HashSet<&'static str> {
284 unsafe {
285 let extensions = glx.GetClientString(display.0, glx::EXTENSIONS as i32);
286 if extensions.is_null() {
287 return HashSet::new();
288 }
289
290 if let Ok(extensions) = CStr::from_ptr(extensions).to_str() {
291 extensions.split(' ').collect::<HashSet<_>>()
292 } else {
293 HashSet::new()
294 }
295 }
296}