1use super::connection::{Connection, NativeConnectionWrapper};
4use super::context::{Context, ContextDescriptor, NativeContext};
5use super::surface::{NativeWidget, Surface, SurfaceDataGuard, SurfaceTexture};
6use crate::base::egl::context::{self, CurrentContextGuard, EGLBackedContext};
7use crate::base::egl::surface::EGLBackedSurface;
8use crate::context::ContextID;
9use crate::egl;
10use crate::egl::types::EGLint;
11use crate::gl;
12pub use crate::mesa_surfaceless::device::Adapter;
13use crate::surface::Framebuffer;
14use crate::{ContextAttributes, Gl, SurfaceInfo};
15use crate::{Error, GLApi, SurfaceAccess, SurfaceType};
16use euclid::default::Size2D;
17use glow::Texture;
18use std::os::raw::c_void;
19use std::sync::Arc;
20use wayland_sys::client::wl_proxy;
21use wayland_sys::egl::{wayland_egl_handle, wl_egl_window};
22
23const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D;
25
26pub struct Device {
30 pub(crate) native_connection: Arc<NativeConnectionWrapper>,
31 pub(crate) adapter: Adapter,
32}
33
34#[derive(Clone)]
38pub struct NativeDevice {
39 pub adapter: Adapter,
41}
42
43impl Device {
44 #[inline]
45 pub(crate) fn new(connection: &Connection, adapter: &Adapter) -> Result<Device, Error> {
46 Ok(Device {
47 native_connection: connection.native_connection.clone(),
48 adapter: (*adapter).clone(),
49 })
50 }
51
52 #[inline]
57 pub fn native_device(&self) -> NativeDevice {
58 NativeDevice {
59 adapter: self.adapter(),
60 }
61 }
62
63 #[inline]
65 pub fn connection(&self) -> Connection {
66 Connection {
67 native_connection: self.native_connection.clone(),
68 }
69 }
70
71 #[inline]
73 pub fn adapter(&self) -> Adapter {
74 self.adapter.clone()
75 }
76
77 #[inline]
79 pub fn gl_api(&self) -> GLApi {
80 if std::env::var("SURFMAN_FORCE_GLES").is_ok() {
81 GLApi::GLES
82 } else {
83 GLApi::GL
84 }
85 }
86
87 #[inline]
91 pub fn create_context_descriptor(
92 &self,
93 attributes: &ContextAttributes,
94 ) -> Result<ContextDescriptor, Error> {
95 self.adapter.set_environment_variables();
97
98 unsafe {
99 ContextDescriptor::new(
100 self.native_connection.egl_display,
101 attributes,
102 &[
103 egl::SURFACE_TYPE as EGLint,
104 egl::WINDOW_BIT as EGLint,
105 egl::RENDERABLE_TYPE as EGLint,
106 egl::OPENGL_BIT as EGLint,
107 ],
108 )
109 }
110 }
111
112 #[inline]
117 pub fn create_context(
118 &self,
119 descriptor: &ContextDescriptor,
120 share_with: Option<&Context>,
121 ) -> Result<Context, Error> {
122 unsafe {
123 let context = EGLBackedContext::new(
124 self.native_connection.egl_display,
125 descriptor,
126 share_with.map(|ctx| &ctx.0),
127 self.gl_api(),
128 )?;
129 context.make_current(self.native_connection.egl_display)?;
130 Ok(Context(
131 context,
132 Gl::from_loader_function(context::get_proc_address),
133 ))
134 }
135 }
136
137 #[inline]
143 pub unsafe fn create_context_from_native_context(
144 &self,
145 native_context: NativeContext,
146 ) -> Result<Context, Error> {
147 Ok(Context(
148 EGLBackedContext::from_native_context(native_context),
149 Gl::from_loader_function(context::get_proc_address),
150 ))
151 }
152
153 pub fn destroy_context(&self, context: &mut Context) -> Result<(), Error> {
157 if let Ok(Some(mut surface)) = self.unbind_surface_from_context(context) {
158 self.destroy_surface(context, &mut surface)?;
159 }
160
161 unsafe {
162 context.0.destroy(self.native_connection.egl_display);
163 Ok(())
164 }
165 }
166
167 #[inline]
169 pub fn native_context(&self, context: &Context) -> NativeContext {
170 context.0.native_context()
171 }
172
173 #[inline]
175 pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor {
176 unsafe {
177 ContextDescriptor::from_egl_context(
178 &context.1,
179 self.native_connection.egl_display,
180 context.0.egl_context,
181 )
182 }
183 }
184
185 #[inline]
189 pub fn make_context_current(&self, context: &Context) -> Result<(), Error> {
190 unsafe { context.0.make_current(self.native_connection.egl_display) }
191 }
192
193 #[inline]
198 pub fn make_no_context_current(&self) -> Result<(), Error> {
199 unsafe { context::make_no_context_current(self.native_connection.egl_display) }
200 }
201
202 #[inline]
203 pub(crate) fn temporarily_make_context_current(
204 &self,
205 context: &Context,
206 ) -> Result<CurrentContextGuard, Error> {
207 let guard = CurrentContextGuard::new();
208 self.make_context_current(context)?;
209 Ok(guard)
210 }
211
212 #[inline]
214 pub fn context_descriptor_attributes(
215 &self,
216 context_descriptor: &ContextDescriptor,
217 ) -> ContextAttributes {
218 unsafe { context_descriptor.attributes(self.native_connection.egl_display) }
219 }
220
221 #[inline]
229 pub fn get_proc_address(&self, _: &Context, symbol_name: &str) -> *const c_void {
230 context::get_proc_address(symbol_name)
231 }
232
233 #[inline]
244 pub fn bind_surface_to_context(
245 &self,
246 context: &mut Context,
247 surface: Surface,
248 ) -> Result<(), (Error, Surface)> {
249 unsafe {
250 context
251 .0
252 .bind_surface(self.native_connection.egl_display, surface.0)
253 .map_err(|(err, surface)| (err, Surface(surface)))
254 }
255 }
256
257 pub fn unbind_surface_from_context(
262 &self,
263 context: &mut Context,
264 ) -> Result<Option<Surface>, Error> {
265 unsafe {
266 context
267 .0
268 .unbind_surface(&context.1, self.native_connection.egl_display)
269 .map(|maybe_surface| maybe_surface.map(Surface))
270 }
271 }
272
273 pub fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> {
279 context
280 .0
281 .present_bound_surface(self.native_connection.egl_display)
282 }
283
284 pub fn resize_bound_surface(
286 &self,
287 context: &mut Context,
288 size: Size2D<i32>,
289 ) -> Result<(), Error> {
290 match &mut context.0.framebuffer {
291 Framebuffer::Surface(surface) => surface.resize_for_wayland(size),
292 _ => Ok(()),
293 }
294 }
295
296 #[inline]
301 pub fn context_id(&self, context: &Context) -> ContextID {
302 context.0.id
303 }
304
305 #[inline]
309 pub fn context_surface_info(&self, context: &Context) -> Result<Option<SurfaceInfo>, Error> {
310 context.0.surface_info()
311 }
312
313 pub fn create_surface(
318 &self,
319 context: &Context,
320 _: SurfaceAccess,
321 surface_type: SurfaceType<NativeWidget>,
322 ) -> Result<Surface, Error> {
323 match surface_type {
324 SurfaceType::Generic { size } => self.create_generic_surface(context, &size),
325 SurfaceType::Widget { native_widget } => unsafe {
326 self.create_window_surface(
327 context,
328 native_widget.wayland_surface,
329 &native_widget.size,
330 )
331 },
332 }
333 }
334
335 fn create_generic_surface(
336 &self,
337 context: &Context,
338 size: &Size2D<i32>,
339 ) -> Result<Surface, Error> {
340 let _guard = self.temporarily_make_context_current(context)?;
341 let context_descriptor = self.context_descriptor(context);
342 let context_attributes = self.context_descriptor_attributes(&context_descriptor);
343
344 Ok(Surface(EGLBackedSurface::new_generic(
345 &context.1,
346 self.native_connection.egl_display,
347 context.0.egl_context,
348 context.0.id,
349 &context_attributes,
350 size,
351 )))
352 }
353
354 unsafe fn create_window_surface(
355 &self,
356 context: &Context,
357 wayland_surface: *mut wl_proxy,
358 size: &Size2D<i32>,
359 ) -> Result<Surface, Error> {
360 let egl_window =
361 (wayland_egl_handle().wl_egl_window_create)(wayland_surface, size.width, size.height);
362 assert!(!egl_window.is_null());
363
364 let context_descriptor = self.context_descriptor(context);
365 let egl_config = context::egl_config_from_id(
366 self.native_connection.egl_display,
367 context_descriptor.egl_config_id,
368 );
369
370 Ok(Surface(EGLBackedSurface::new_window(
371 self.native_connection.egl_display,
372 egl_config,
373 egl_window as *mut c_void,
374 context.0.id,
375 size,
376 )))
377 }
378
379 pub fn create_surface_texture(
390 &self,
391 context: &mut Context,
392 surface: Surface,
393 ) -> Result<SurfaceTexture, (Error, Surface)> {
394 let _guard = match self.temporarily_make_context_current(context) {
395 Ok(guard) => guard,
396 Err(err) => return Err((err, surface)),
397 };
398
399 match surface.0.to_surface_texture(&context.1) {
400 Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)),
401 Err((err, surface)) => Err((err, Surface(surface))),
402 }
403 }
404
405 pub fn destroy_surface(
413 &self,
414 context: &mut Context,
415 surface: &mut Surface,
416 ) -> Result<(), Error> {
417 let egl_display = self.native_connection.egl_display;
418 if let Some(wayland_egl_window) =
419 surface.0.destroy(&context.1, egl_display, context.0.id)?
420 {
421 unsafe {
422 let wayland_egl_window = wayland_egl_window as *mut wl_egl_window;
423 (wayland_egl_handle().wl_egl_window_destroy)(wayland_egl_window);
424 }
425 }
426 Ok(())
427 }
428
429 pub fn destroy_surface_texture(
437 &self,
438 context: &mut Context,
439 surface_texture: SurfaceTexture,
440 ) -> Result<Surface, (Error, SurfaceTexture)> {
441 match self.temporarily_make_context_current(context) {
442 Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))),
443 Err(err) => Err((err, surface_texture)),
444 }
445 }
446
447 pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> {
455 surface
456 .0
457 .present(self.native_connection.egl_display, context.0.egl_context)
458 }
459
460 pub fn resize_surface(
462 &self,
463 _context: &Context,
464 surface: &mut Surface,
465 size: Size2D<i32>,
466 ) -> Result<(), Error> {
467 surface.0.resize_for_wayland(size)
468 }
469
470 #[inline]
472 pub fn lock_surface_data<'s>(&self, _: &'s mut Surface) -> Result<SurfaceDataGuard<'s>, Error> {
473 Err(Error::Unimplemented)
474 }
475
476 #[inline]
480 pub fn surface_gl_texture_target(&self) -> u32 {
481 SURFACE_GL_TEXTURE_TARGET
482 }
483
484 pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
491 surface.0.info()
492 }
493
494 #[inline]
498 pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option<Texture> {
499 surface_texture.0.texture_object
500 }
501}