1use super::connection::{Connection, NativeConnectionWrapper};
4use super::context::{Context, ContextDescriptor, NativeContext};
5use super::surface::Surface;
6use crate::base::egl::{
7 context::{self, CurrentContextGuard, EGLBackedContext},
8 surface::EGLBackedSurface,
9};
10use crate::context::ContextID;
11use crate::egl::types::EGLint;
12use crate::gl;
13pub use crate::mesa_surfaceless::device::Adapter;
14use crate::x11::surface::{NativeWidget, SurfaceDataGuard, SurfaceTexture};
15use crate::{egl, ContextAttributes, Error, GLApi, Gl, SurfaceAccess, SurfaceInfo, SurfaceType};
16use euclid::default::Size2D;
17use glow::Texture;
18use std::os::raw::c_void;
19use std::sync::Arc;
20use x11_dl::xlib::Window;
21
22const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D;
24
25pub struct Device {
29 pub(crate) native_connection: Arc<NativeConnectionWrapper>,
30 pub(crate) adapter: Adapter,
31}
32
33#[derive(Clone)]
37pub struct NativeDevice {
38 pub adapter: Adapter,
40}
41
42impl Device {
43 #[inline]
44 pub(crate) fn new(connection: &Connection, adapter: &Adapter) -> Result<Device, Error> {
45 Ok(Device {
46 native_connection: connection.native_connection.clone(),
47 adapter: (*adapter).clone(),
48 })
49 }
50
51 #[inline]
56 pub fn native_device(&self) -> NativeDevice {
57 NativeDevice {
58 adapter: self.adapter(),
59 }
60 }
61
62 #[inline]
64 pub fn connection(&self) -> Connection {
65 Connection {
66 native_connection: self.native_connection.clone(),
67 }
68 }
69
70 #[inline]
72 pub fn adapter(&self) -> Adapter {
73 self.adapter.clone()
74 }
75
76 #[inline]
78 pub fn gl_api(&self) -> GLApi {
79 GLApi::GL
80 }
81
82 #[inline]
86 pub fn create_context_descriptor(
87 &self,
88 attributes: &ContextAttributes,
89 ) -> Result<ContextDescriptor, Error> {
90 self.adapter.set_environment_variables();
92
93 unsafe {
94 ContextDescriptor::new(
95 self.native_connection.egl_display,
96 attributes,
97 &[
98 egl::SURFACE_TYPE as EGLint,
99 egl::WINDOW_BIT as EGLint,
100 egl::RENDERABLE_TYPE as EGLint,
101 egl::OPENGL_BIT as EGLint,
102 ],
103 )
104 }
105 }
106
107 #[inline]
112 pub fn create_context(
113 &self,
114 descriptor: &ContextDescriptor,
115 share_with: Option<&Context>,
116 ) -> Result<Context, Error> {
117 unsafe {
118 let context = EGLBackedContext::new(
119 self.native_connection.egl_display,
120 descriptor,
121 share_with.map(|ctx| &ctx.0),
122 self.gl_api(),
123 )?;
124 context.make_current(self.native_connection.egl_display)?;
125 Ok(Context(
126 context,
127 Gl::from_loader_function(context::get_proc_address),
128 ))
129 }
130 }
131
132 #[inline]
138 pub unsafe fn create_context_from_native_context(
139 &self,
140 native_context: NativeContext,
141 ) -> Result<Context, Error> {
142 Ok(Context(
143 EGLBackedContext::from_native_context(native_context),
144 Gl::from_loader_function(context::get_proc_address),
145 ))
146 }
147
148 pub fn destroy_context(&self, context: &mut Context) -> Result<(), Error> {
152 if let Ok(Some(mut surface)) = self.unbind_surface_from_context(context) {
153 self.destroy_surface(context, &mut surface)?;
154 }
155
156 unsafe {
157 context.0.destroy(self.native_connection.egl_display);
158 Ok(())
159 }
160 }
161
162 #[inline]
164 pub fn native_context(&self, context: &Context) -> NativeContext {
165 context.0.native_context()
166 }
167
168 #[inline]
170 pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor {
171 unsafe {
172 ContextDescriptor::from_egl_context(
173 &context.1,
174 self.native_connection.egl_display,
175 context.0.egl_context,
176 )
177 }
178 }
179
180 #[inline]
184 pub fn make_context_current(&self, context: &Context) -> Result<(), Error> {
185 unsafe { context.0.make_current(self.native_connection.egl_display) }
186 }
187
188 #[inline]
193 pub fn make_no_context_current(&self) -> Result<(), Error> {
194 unsafe { context::make_no_context_current(self.native_connection.egl_display) }
195 }
196
197 #[inline]
198 pub(crate) fn temporarily_make_context_current(
199 &self,
200 context: &Context,
201 ) -> Result<CurrentContextGuard, Error> {
202 let guard = CurrentContextGuard::new();
203 self.make_context_current(context)?;
204 Ok(guard)
205 }
206
207 #[inline]
209 pub fn context_descriptor_attributes(
210 &self,
211 context_descriptor: &ContextDescriptor,
212 ) -> ContextAttributes {
213 unsafe { context_descriptor.attributes(self.native_connection.egl_display) }
214 }
215
216 #[inline]
224 pub fn get_proc_address(&self, _: &Context, symbol_name: &str) -> *const c_void {
225 context::get_proc_address(symbol_name)
226 }
227
228 #[inline]
239 pub fn bind_surface_to_context(
240 &self,
241 context: &mut Context,
242 surface: Surface,
243 ) -> Result<(), (Error, Surface)> {
244 unsafe {
245 context
246 .0
247 .bind_surface(self.native_connection.egl_display, surface.0)
248 .map_err(|(err, surface)| (err, Surface(surface)))
249 }
250 }
251
252 pub fn unbind_surface_from_context(
257 &self,
258 context: &mut Context,
259 ) -> Result<Option<Surface>, Error> {
260 unsafe {
261 context
262 .0
263 .unbind_surface(&context.1, self.native_connection.egl_display)
264 .map(|maybe_surface| maybe_surface.map(Surface))
265 }
266 }
267
268 pub fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> {
274 context
275 .0
276 .present_bound_surface(self.native_connection.egl_display)
277 }
278
279 pub fn resize_bound_surface(
281 &self,
282 context: &mut Context,
283 size: Size2D<i32>,
284 ) -> Result<(), Error> {
285 context.0.resize_bound_surface(size)
286 }
287
288 #[inline]
293 pub fn context_id(&self, context: &Context) -> ContextID {
294 context.0.id
295 }
296
297 #[inline]
301 pub fn context_surface_info(&self, context: &Context) -> Result<Option<SurfaceInfo>, Error> {
302 context.0.surface_info()
303 }
304
305 pub fn create_surface(
310 &self,
311 context: &Context,
312 _: SurfaceAccess,
313 surface_type: SurfaceType<NativeWidget>,
314 ) -> Result<Surface, Error> {
315 match surface_type {
316 SurfaceType::Generic { size } => self.create_generic_surface(context, &size),
317 SurfaceType::Widget { native_widget } => unsafe {
318 self.create_window_surface(context, native_widget.window)
319 },
320 }
321 }
322
323 fn create_generic_surface(
324 &self,
325 context: &Context,
326 size: &Size2D<i32>,
327 ) -> Result<Surface, Error> {
328 let _guard = self.temporarily_make_context_current(context)?;
329 let context_descriptor = self.context_descriptor(context);
330 let context_attributes = self.context_descriptor_attributes(&context_descriptor);
331
332 Ok(Surface(EGLBackedSurface::new_generic(
333 &context.1,
334 self.native_connection.egl_display,
335 context.0.egl_context,
336 context.0.id,
337 &context_attributes,
338 size,
339 )))
340 }
341
342 unsafe fn create_window_surface(
343 &self,
344 context: &Context,
345 mut x11_window: Window,
346 ) -> Result<Surface, Error> {
347 let egl_config_id = context::get_context_attr(
348 self.native_connection.egl_display,
349 context.0.egl_context,
350 egl::CONFIG_ID as EGLint,
351 );
352 let egl_config =
353 context::egl_config_from_id(self.native_connection.egl_display, egl_config_id);
354
355 let display_guard = self.native_connection.lock_display();
356 let (mut root_window, mut x, mut y, mut width, mut height) = (0, 0, 0, 0, 0);
357 let (mut border_width, mut depth) = (0, 0);
358 (self.native_connection.xlib.XGetGeometry)(
359 display_guard.display(),
360 x11_window,
361 &mut root_window,
362 &mut x,
363 &mut y,
364 &mut width,
365 &mut height,
366 &mut border_width,
367 &mut depth,
368 );
369 let size = Size2D::new(width as i32, height as i32);
370
371 Ok(Surface(EGLBackedSurface::new_window(
372 self.native_connection.egl_display,
373 egl_config,
374 &mut x11_window as *mut Window as *mut c_void,
375 context.0.id,
376 &size,
377 )))
378 }
379
380 pub fn create_surface_texture(
391 &self,
392 context: &mut Context,
393 surface: Surface,
394 ) -> Result<SurfaceTexture, (Error, Surface)> {
395 let _guard = match self.temporarily_make_context_current(context) {
396 Ok(guard) => guard,
397 Err(err) => return Err((err, surface)),
398 };
399
400 match surface.0.to_surface_texture(&context.1) {
401 Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)),
402 Err((err, surface)) => Err((err, Surface(surface))),
403 }
404 }
405
406 pub fn destroy_surface(
414 &self,
415 context: &mut Context,
416 surface: &mut Surface,
417 ) -> Result<(), Error> {
418 let egl_display = self.native_connection.egl_display;
419 surface.0.destroy(&context.1, egl_display, context.0.id)?;
420 Ok(())
421 }
422
423 pub fn destroy_surface_texture(
431 &self,
432 context: &mut Context,
433 surface_texture: SurfaceTexture,
434 ) -> Result<Surface, (Error, SurfaceTexture)> {
435 match self.temporarily_make_context_current(context) {
436 Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))),
437 Err(err) => Err((err, surface_texture)),
438 }
439 }
440
441 pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> {
449 surface
450 .0
451 .present(self.native_connection.egl_display, context.0.egl_context)
452 }
453
454 pub fn resize_surface(
456 &self,
457 _context: &Context,
458 surface: &mut Surface,
459 size: Size2D<i32>,
460 ) -> Result<(), Error> {
461 surface.0.resize(size);
462 Ok(())
463 }
464
465 #[inline]
467 pub fn lock_surface_data<'s>(&self, _: &'s mut Surface) -> Result<SurfaceDataGuard<'s>, Error> {
468 Err(Error::Unimplemented)
469 }
470
471 #[inline]
475 pub fn surface_gl_texture_target(&self) -> u32 {
476 SURFACE_GL_TEXTURE_TARGET
477 }
478
479 pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
486 surface.0.info()
487 }
488
489 #[inline]
493 pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option<Texture> {
494 surface_texture.0.texture_object
495 }
496}