surfman/mesa_surfaceless/
device.rs1use super::connection::{Connection, NativeConnectionWrapper};
4use super::surface::SurfaceDataGuard;
5use crate::base::egl::context::{self, CurrentContextGuard, EGLBackedContext};
6use crate::base::egl::surface::EGLBackedSurface;
7use crate::context::ContextID;
8use crate::egl;
9use crate::egl::types::EGLint;
10use crate::gl;
11use crate::mesa_surfaceless::context::{Context, ContextDescriptor, NativeContext};
12use crate::mesa_surfaceless::surface::{NativeWidget, Surface, SurfaceTexture};
13use crate::{ContextAttributes, Gl, SurfaceInfo};
14use crate::{Error, GLApi, SurfaceAccess, SurfaceType};
15use euclid::default::Size2D;
16use glow::Texture;
17use std::env;
18use std::os::raw::c_void;
19use std::sync::Arc;
20
21static MESA_SOFTWARE_RENDERING_ENV_VAR: &str = "LIBGL_ALWAYS_SOFTWARE";
22static MESA_DRI_PRIME_ENV_VAR: &str = "DRI_PRIME";
23
24const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D;
26
27#[derive(Clone, Debug)]
31pub enum Adapter {
32 #[doc(hidden)]
33 Hardware,
34 #[doc(hidden)]
35 HardwarePrime,
36 #[doc(hidden)]
37 Software,
38}
39
40impl Adapter {
41 #[inline]
42 pub(crate) fn hardware() -> Adapter {
43 Adapter::HardwarePrime
44 }
45
46 #[inline]
47 pub(crate) fn low_power() -> Adapter {
48 Adapter::Hardware
49 }
50
51 #[inline]
52 pub(crate) fn software() -> Adapter {
53 Adapter::Software
54 }
55
56 pub(crate) fn set_environment_variables(&self) {
57 match *self {
58 Adapter::Hardware | Adapter::HardwarePrime => {
59 env::remove_var(MESA_SOFTWARE_RENDERING_ENV_VAR);
60 }
61 Adapter::Software => {
62 env::set_var(MESA_SOFTWARE_RENDERING_ENV_VAR, "1");
63 }
64 }
65
66 match *self {
67 Adapter::Software => {}
68 Adapter::Hardware => {
69 env::remove_var(MESA_DRI_PRIME_ENV_VAR);
70 }
71 Adapter::HardwarePrime => {
72 env::set_var(MESA_DRI_PRIME_ENV_VAR, "1");
73 }
74 }
75 }
76}
77
78pub struct Device {
82 pub(crate) native_connection: Arc<NativeConnectionWrapper>,
83 pub(crate) adapter: Adapter,
84}
85
86#[derive(Clone)]
90pub struct NativeDevice {
91 pub adapter: Adapter,
93}
94
95impl Device {
96 #[inline]
97 pub(crate) fn new(connection: &Connection, adapter: &Adapter) -> Result<Device, Error> {
98 Ok(Device {
99 native_connection: connection.native_connection.clone(),
100 adapter: (*adapter).clone(),
101 })
102 }
103
104 #[inline]
109 pub fn native_device(&self) -> NativeDevice {
110 NativeDevice {
111 adapter: self.adapter(),
112 }
113 }
114
115 #[inline]
117 pub fn connection(&self) -> Connection {
118 Connection {
119 native_connection: self.native_connection.clone(),
120 }
121 }
122
123 #[inline]
125 pub fn adapter(&self) -> Adapter {
126 self.adapter.clone()
127 }
128
129 #[inline]
131 pub fn gl_api(&self) -> GLApi {
132 GLApi::GL
133 }
134
135 #[inline]
139 pub fn create_context_descriptor(
140 &self,
141 attributes: &ContextAttributes,
142 ) -> Result<ContextDescriptor, Error> {
143 self.adapter.set_environment_variables();
145
146 unsafe {
147 ContextDescriptor::new(
148 self.native_connection.egl_display,
149 attributes,
150 &[
151 egl::SURFACE_TYPE as EGLint,
152 egl::PBUFFER_BIT as EGLint,
153 egl::RENDERABLE_TYPE as EGLint,
154 egl::OPENGL_BIT as EGLint,
155 egl::COLOR_BUFFER_TYPE as EGLint,
156 egl::RGB_BUFFER as EGLint,
157 ],
158 )
159 }
160 }
161
162 #[inline]
167 pub fn create_context(
168 &self,
169 descriptor: &ContextDescriptor,
170 share_with: Option<&Context>,
171 ) -> Result<Context, Error> {
172 unsafe {
173 let context = EGLBackedContext::new(
174 self.native_connection.egl_display,
175 descriptor,
176 share_with.map(|ctx| &ctx.0),
177 self.gl_api(),
178 )?;
179 context.make_current(self.native_connection.egl_display)?;
180 Ok(Context(
181 context,
182 Gl::from_loader_function(context::get_proc_address),
183 ))
184 }
185 }
186
187 #[inline]
193 pub unsafe fn create_context_from_native_context(
194 &self,
195 native_context: NativeContext,
196 ) -> Result<Context, Error> {
197 Ok(Context(
198 EGLBackedContext::from_native_context(native_context),
199 Gl::from_loader_function(context::get_proc_address),
200 ))
201 }
202
203 pub fn destroy_context(&self, context: &mut Context) -> Result<(), Error> {
207 if let Ok(Some(mut surface)) = self.unbind_surface_from_context(context) {
208 self.destroy_surface(context, &mut surface)?;
209 }
210
211 unsafe {
212 context.0.destroy(self.native_connection.egl_display);
213 Ok(())
214 }
215 }
216
217 #[inline]
219 pub fn native_context(&self, context: &Context) -> NativeContext {
220 context.0.native_context()
221 }
222
223 #[inline]
225 pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor {
226 unsafe {
227 ContextDescriptor::from_egl_context(
228 &context.1,
229 self.native_connection.egl_display,
230 context.0.egl_context,
231 )
232 }
233 }
234
235 #[inline]
239 pub fn make_context_current(&self, context: &Context) -> Result<(), Error> {
240 unsafe { context.0.make_current(self.native_connection.egl_display) }
241 }
242
243 #[inline]
248 pub fn make_no_context_current(&self) -> Result<(), Error> {
249 unsafe { context::make_no_context_current(self.native_connection.egl_display) }
250 }
251
252 #[inline]
253 pub(crate) fn temporarily_make_context_current(
254 &self,
255 context: &Context,
256 ) -> Result<CurrentContextGuard, Error> {
257 let guard = CurrentContextGuard::new();
258 self.make_context_current(context)?;
259 Ok(guard)
260 }
261
262 #[inline]
264 pub fn context_descriptor_attributes(
265 &self,
266 context_descriptor: &ContextDescriptor,
267 ) -> ContextAttributes {
268 unsafe { context_descriptor.attributes(self.native_connection.egl_display) }
269 }
270
271 #[inline]
279 pub fn get_proc_address(&self, _: &Context, symbol_name: &str) -> *const c_void {
280 context::get_proc_address(symbol_name)
281 }
282
283 #[inline]
294 pub fn bind_surface_to_context(
295 &self,
296 context: &mut Context,
297 surface: Surface,
298 ) -> Result<(), (Error, Surface)> {
299 unsafe {
300 context
301 .0
302 .bind_surface(self.native_connection.egl_display, surface.0)
303 .map_err(|(err, surface)| (err, Surface(surface)))
304 }
305 }
306
307 pub fn unbind_surface_from_context(
312 &self,
313 context: &mut Context,
314 ) -> Result<Option<Surface>, Error> {
315 unsafe {
316 context
317 .0
318 .unbind_surface(&context.1, self.native_connection.egl_display)
319 .map(|maybe_surface| maybe_surface.map(Surface))
320 }
321 }
322
323 pub fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> {
329 context
330 .0
331 .present_bound_surface(self.native_connection.egl_display)
332 }
333
334 pub fn resize_bound_surface(
336 &self,
337 context: &mut Context,
338 size: Size2D<i32>,
339 ) -> Result<(), Error> {
340 context.0.resize_bound_surface(size)
341 }
342
343 #[inline]
348 pub fn context_id(&self, context: &Context) -> ContextID {
349 context.0.id
350 }
351
352 #[inline]
356 pub fn context_surface_info(&self, context: &Context) -> Result<Option<SurfaceInfo>, Error> {
357 context.0.surface_info()
358 }
359
360 pub fn create_surface(
365 &self,
366 context: &Context,
367 _: SurfaceAccess,
368 surface_type: SurfaceType<NativeWidget>,
369 ) -> Result<Surface, Error> {
370 match surface_type {
371 SurfaceType::Generic { size } => self.create_generic_surface(context, &size),
372 SurfaceType::Widget { .. } => Err(Error::UnsupportedOnThisPlatform),
373 }
374 }
375
376 fn create_generic_surface(
377 &self,
378 context: &Context,
379 size: &Size2D<i32>,
380 ) -> Result<Surface, Error> {
381 let _guard = self.temporarily_make_context_current(context)?;
382 let context_descriptor = self.context_descriptor(context);
383 let context_attributes = self.context_descriptor_attributes(&context_descriptor);
384
385 Ok(Surface(EGLBackedSurface::new_generic(
386 &context.1,
387 self.native_connection.egl_display,
388 context.0.egl_context,
389 context.0.id,
390 &context_attributes,
391 size,
392 )))
393 }
394
395 pub fn create_surface_texture(
406 &self,
407 context: &mut Context,
408 surface: Surface,
409 ) -> Result<SurfaceTexture, (Error, Surface)> {
410 let _guard = match self.temporarily_make_context_current(context) {
411 Ok(guard) => guard,
412 Err(err) => return Err((err, surface)),
413 };
414
415 match surface.0.to_surface_texture(&context.1) {
416 Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)),
417 Err((err, surface)) => Err((err, Surface(surface))),
418 }
419 }
420
421 pub fn destroy_surface(
429 &self,
430 context: &mut Context,
431 surface: &mut Surface,
432 ) -> Result<(), Error> {
433 let egl_display = self.native_connection.egl_display;
434 let window = surface.0.destroy(&context.1, egl_display, context.0.id)?;
435 debug_assert!(window.is_none());
436 Ok(())
437 }
438
439 pub fn destroy_surface_texture(
447 &self,
448 context: &mut Context,
449 surface_texture: SurfaceTexture,
450 ) -> Result<Surface, (Error, SurfaceTexture)> {
451 match self.temporarily_make_context_current(context) {
452 Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))),
453 Err(err) => Err((err, surface_texture)),
454 }
455 }
456
457 pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> {
465 surface
466 .0
467 .present(self.native_connection.egl_display, context.0.egl_context)
468 }
469
470 pub fn resize_surface(
472 &self,
473 _context: &Context,
474 surface: &mut Surface,
475 size: Size2D<i32>,
476 ) -> Result<(), Error> {
477 surface.0.size = size;
478 Ok(())
479 }
480
481 #[inline]
483 pub fn lock_surface_data<'s>(&self, _: &'s mut Surface) -> Result<SurfaceDataGuard<'s>, Error> {
484 Err(Error::Unimplemented)
485 }
486
487 #[inline]
491 pub fn surface_gl_texture_target(&self) -> u32 {
492 SURFACE_GL_TEXTURE_TARGET
493 }
494
495 pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
502 surface.0.info()
503 }
504
505 #[inline]
509 pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option<Texture> {
510 surface_texture.0.texture_object
511 }
512}