chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0)
1//! Integration for using [`glow`] on top of smithays OpenGL ES 2 renderer
2use tracing::warn;
3
4#[cfg(feature = "wayland_frontend")]
5use crate::backend::renderer::{ImportDmaWl, ImportMemWl};
6#[cfg(all(
7 feature = "wayland_frontend",
8 feature = "backend_egl",
9 feature = "use_system_lib"
10))]
11use crate::backend::{egl::display::EGLBufferReader, renderer::ImportEgl};
12use crate::{
13 backend::{
14 allocator::{dmabuf::Dmabuf, format::FormatSet, Format, Fourcc},
15 egl::EGLContext,
16 renderer::{
17 element::UnderlyingStorage,
18 gles::{element::*, *},
19 sync, Bind, Blit, BlitFrame, Color32F, DebugFlags, ExportMem, ImportDma, ImportMem, Offscreen,
20 Renderer, RendererSuper, TextureFilter,
21 },
22 },
23 utils::{Buffer as BufferCoord, Physical, Rectangle, Size, Transform},
24};
25
26#[cfg(feature = "wayland_frontend")]
27use wayland_server::protocol::{wl_buffer, wl_shm};
28
29use glow::Context;
30use std::{
31 borrow::{Borrow, BorrowMut},
32 sync::Arc,
33};
34
35use super::{element::RenderElement, ContextId, Frame};
36
37#[derive(Debug)]
38/// A renderer utilizing OpenGL ES 2 and [`glow`] on top for easier custom rendering.
39pub struct GlowRenderer {
40 gl: GlesRenderer,
41 glow: Arc<Context>,
42}
43
44#[derive(Debug)]
45/// [`Frame`] implementation of a [`GlowRenderer`].
46///
47/// Leaking the frame will cause the same problems as leaking a [`GlesFrame`].
48pub struct GlowFrame<'frame, 'buffer> {
49 frame: Option<GlesFrame<'frame, 'buffer>>,
50 glow: Arc<Context>,
51}
52
53impl GlowRenderer {
54 /// Get the supported [`Capabilities`](Capability) of the renderer
55 ///
56 /// # Safety
57 ///
58 /// This operation will cause undefined behavior if the given EGLContext is active in another thread.
59 pub unsafe fn supported_capabilities(context: &EGLContext) -> Result<Vec<Capability>, GlesError> {
60 GlesRenderer::supported_capabilities(context)
61 }
62
63 /// Creates a new OpenGL ES 2 + Glow renderer from a given [`EGLContext`]
64 /// with all [`supported capabilities`](Self::supported_capabilities).
65 ///
66 /// # Safety
67 ///
68 /// This operation will cause undefined behavior if the given EGLContext is active in another thread.
69 ///
70 /// See: [`with_capabilities`](Self::with_capabilities) for more information
71 pub unsafe fn new(context: EGLContext) -> Result<GlowRenderer, GlesError> {
72 let supported_capabilities = Self::supported_capabilities(&context)?;
73 Self::with_capabilities(context, supported_capabilities)
74 }
75
76 /// Creates a new OpenGL ES 2 + Glow renderer from a given [`EGLContext`]
77 /// with the specified [`Capabilities`](Capability). If a requested [`Capability`] is not supported an
78 /// error will be returned.
79 ///
80 /// # Safety
81 ///
82 /// This operation will cause undefined behavior if the given EGLContext is active in another thread.
83 ///
84 /// # Implementation details
85 ///
86 /// - Texture handles created by the resulting renderer are valid for every rendered created with an
87 /// `EGLContext` shared with the given one (see `EGLContext::new_shared`) and can be used on
88 /// any of these renderers.
89 /// - This renderer has no default framebuffer, use `Bind::bind` before rendering.
90 /// - Binding a new target, while another one is already bound, will replace the current target.
91 /// - Shm buffers can be released after a successful import, without the texture handle becoming invalid.
92 /// - Texture filtering starts with Linear-downscaling and Linear-upscaling
93 pub unsafe fn with_capabilities(
94 context: EGLContext,
95 capabilities: impl IntoIterator<Item = Capability>,
96 ) -> Result<GlowRenderer, GlesError> {
97 let glow = {
98 context.make_current()?;
99 Context::from_loader_function(|s| crate::backend::egl::get_proc_address(s) as *const _)
100 };
101 let gl = GlesRenderer::with_capabilities(context, capabilities)?;
102
103 Ok(GlowRenderer {
104 gl,
105 glow: Arc::new(glow),
106 })
107 }
108
109 /// Get access to the underlying [`EGLContext`].
110 ///
111 /// *Note*: Modifying the context state, might result in rendering issues.
112 /// The context state is considerd an implementation detail
113 /// and no guarantee is made about what can or cannot be changed.
114 /// To make sure a certain modification does not interfere with
115 /// the renderer's behaviour, check the source.
116 pub fn egl_context(&self) -> &EGLContext {
117 self.gl.egl_context()
118 }
119
120 /// Run custom code in the GL context owned by this renderer.
121 ///
122 /// The OpenGL state of the renderer is considered an implementation detail
123 /// and no guarantee is made about what can or cannot be changed,
124 /// as such you should reset everything you change back to its previous value
125 /// or check the source code of the version of Smithay you are using to ensure
126 /// your changes don't interfere with the renderer's behavior.
127 /// Doing otherwise can lead to rendering errors while using other functions of this renderer.
128 pub fn with_context<F, R>(&mut self, func: F) -> Result<R, GlesError>
129 where
130 F: FnOnce(&Arc<Context>) -> R,
131 {
132 unsafe {
133 self.gl.egl_context().make_current()?;
134 }
135 Ok(func(&self.glow))
136 }
137}
138
139impl GlowFrame<'_, '_> {
140 /// Run custom code in the GL context owned by this renderer.
141 ///
142 /// The OpenGL state of the renderer is considered an implementation detail
143 /// and no guarantee is made about what can or cannot be changed,
144 /// as such you should reset everything you change back to its previous value
145 /// or check the source code of the version of Smithay you are using to ensure
146 /// your changes don't interfere with the renderer's behavior.
147 /// Doing otherwise can lead to rendering errors while using other functions of this renderer.
148 pub fn with_context<F, R>(&mut self, func: F) -> Result<R, GlesError>
149 where
150 F: FnOnce(&Arc<Context>) -> R,
151 {
152 Ok(func(&self.glow))
153 }
154}
155
156// TODO: When GAT, use TryFrom and be generic over the Error,
157// so `TryFrom<GlesRenderer, Error=Infaillable> for GlesRenderer` qualifies
158// just as `TryFrom<GlesRenderer, Error=GlesError> for GlowRenderer`
159impl From<GlesRenderer> for GlowRenderer {
160 #[inline]
161 fn from(renderer: GlesRenderer) -> GlowRenderer {
162 let glow = unsafe {
163 renderer.egl_context().make_current().unwrap();
164 Context::from_loader_function(|s| crate::backend::egl::get_proc_address(s) as *const _)
165 };
166
167 GlowRenderer {
168 gl: renderer,
169 glow: Arc::new(glow),
170 }
171 }
172}
173
174impl Borrow<GlesRenderer> for GlowRenderer {
175 #[inline]
176 fn borrow(&self) -> &GlesRenderer {
177 &self.gl
178 }
179}
180
181impl BorrowMut<GlesRenderer> for GlowRenderer {
182 #[inline]
183 fn borrow_mut(&mut self) -> &mut GlesRenderer {
184 &mut self.gl
185 }
186}
187
188impl<'frame, 'buffer> Borrow<GlesFrame<'frame, 'buffer>> for GlowFrame<'frame, 'buffer> {
189 #[inline]
190 fn borrow(&self) -> &GlesFrame<'frame, 'buffer> {
191 self.frame.as_ref().unwrap()
192 }
193}
194
195impl<'frame, 'buffer> BorrowMut<GlesFrame<'frame, 'buffer>> for GlowFrame<'frame, 'buffer> {
196 #[inline]
197 fn borrow_mut(&mut self) -> &mut GlesFrame<'frame, 'buffer> {
198 self.frame.as_mut().unwrap()
199 }
200}
201
202impl RendererSuper for GlowRenderer {
203 type Error = GlesError;
204 type TextureId = GlesTexture;
205 type Framebuffer<'buffer> = GlesTarget<'buffer>;
206 type Frame<'frame, 'buffer>
207 = GlowFrame<'frame, 'buffer>
208 where
209 'buffer: 'frame,
210 Self: 'frame;
211}
212
213impl Renderer for GlowRenderer {
214 fn context_id(&self) -> ContextId<GlesTexture> {
215 self.gl.context_id()
216 }
217
218 fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
219 self.gl.downscale_filter(filter)
220 }
221 fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Self::Error> {
222 self.gl.upscale_filter(filter)
223 }
224
225 fn set_debug_flags(&mut self, flags: DebugFlags) {
226 self.gl.set_debug_flags(flags)
227 }
228 fn debug_flags(&self) -> DebugFlags {
229 self.gl.debug_flags()
230 }
231
232 #[profiling::function]
233 fn render<'frame, 'buffer>(
234 &'frame mut self,
235 target: &'frame mut GlesTarget<'buffer>,
236 output_size: Size<i32, Physical>,
237 transform: Transform,
238 ) -> Result<GlowFrame<'frame, 'buffer>, Self::Error>
239 where
240 'buffer: 'frame,
241 {
242 let glow = self.glow.clone();
243 let frame = self.gl.render(target, output_size, transform)?;
244 Ok(GlowFrame {
245 frame: Some(frame),
246 glow,
247 })
248 }
249
250 #[profiling::function]
251 fn wait(&mut self, sync: &sync::SyncPoint) -> Result<(), Self::Error> {
252 self.gl.wait(sync)
253 }
254
255 #[profiling::function]
256 fn cleanup_texture_cache(&mut self) -> Result<(), Self::Error> {
257 self.gl.cleanup_texture_cache()
258 }
259}
260
261impl Frame for GlowFrame<'_, '_> {
262 type Error = GlesError;
263 type TextureId = GlesTexture;
264
265 fn context_id(&self) -> ContextId<GlesTexture> {
266 self.frame.as_ref().unwrap().context_id()
267 }
268
269 #[profiling::function]
270 fn clear(&mut self, color: Color32F, at: &[Rectangle<i32, Physical>]) -> Result<(), Self::Error> {
271 self.frame.as_mut().unwrap().clear(color, at)
272 }
273
274 #[profiling::function]
275 fn draw_solid(
276 &mut self,
277 dst: Rectangle<i32, Physical>,
278 damage: &[Rectangle<i32, Physical>],
279 color: Color32F,
280 ) -> Result<(), Self::Error> {
281 self.frame.as_mut().unwrap().draw_solid(dst, damage, color)
282 }
283
284 #[profiling::function]
285 fn render_texture_from_to(
286 &mut self,
287 texture: &Self::TextureId,
288 src: Rectangle<f64, BufferCoord>,
289 dst: Rectangle<i32, Physical>,
290 damage: &[Rectangle<i32, Physical>],
291 opaque_regions: &[Rectangle<i32, Physical>],
292 src_transform: Transform,
293 alpha: f32,
294 ) -> Result<(), Self::Error> {
295 Frame::render_texture_from_to(
296 self.frame.as_mut().unwrap(),
297 texture,
298 src,
299 dst,
300 damage,
301 opaque_regions,
302 src_transform,
303 alpha,
304 )
305 }
306
307 fn transformation(&self) -> Transform {
308 self.frame.as_ref().unwrap().transformation()
309 }
310
311 #[profiling::function]
312 fn render_texture_at(
313 &mut self,
314 texture: &Self::TextureId,
315 pos: crate::utils::Point<i32, Physical>,
316 texture_scale: i32,
317 output_scale: impl Into<crate::utils::Scale<f64>>,
318 src_transform: Transform,
319 damage: &[Rectangle<i32, Physical>],
320 opaque_regions: &[Rectangle<i32, Physical>],
321 alpha: f32,
322 ) -> Result<(), Self::Error> {
323 self.frame.as_mut().unwrap().render_texture_at(
324 texture,
325 pos,
326 texture_scale,
327 output_scale,
328 src_transform,
329 damage,
330 opaque_regions,
331 alpha,
332 )
333 }
334
335 #[profiling::function]
336 fn wait(&mut self, sync: &sync::SyncPoint) -> Result<(), Self::Error> {
337 self.frame.as_mut().unwrap().wait(sync)
338 }
339
340 #[profiling::function]
341 fn finish(mut self) -> Result<sync::SyncPoint, Self::Error> {
342 self.finish_internal()
343 }
344}
345
346impl GlowFrame<'_, '_> {
347 #[profiling::function]
348 fn finish_internal(&mut self) -> Result<sync::SyncPoint, GlesError> {
349 if let Some(frame) = self.frame.take() {
350 frame.finish()
351 } else {
352 Ok(sync::SyncPoint::default())
353 }
354 }
355}
356
357impl Drop for GlowFrame<'_, '_> {
358 fn drop(&mut self) {
359 if let Err(err) = self.finish_internal() {
360 warn!("Ignored error finishing GlowFrame on drop: {}", err);
361 }
362 }
363}
364
365#[cfg(feature = "wayland_frontend")]
366impl ImportMemWl for GlowRenderer {
367 #[profiling::function]
368 fn import_shm_buffer(
369 &mut self,
370 buffer: &wl_buffer::WlBuffer,
371 surface: Option<&crate::wayland::compositor::SurfaceData>,
372 damage: &[Rectangle<i32, BufferCoord>],
373 ) -> Result<GlesTexture, GlesError> {
374 self.gl.import_shm_buffer(buffer, surface, damage)
375 }
376
377 fn shm_formats(&self) -> Box<dyn Iterator<Item = wl_shm::Format>> {
378 self.gl.shm_formats()
379 }
380}
381
382impl ImportMem for GlowRenderer {
383 #[profiling::function]
384 fn import_memory(
385 &mut self,
386 data: &[u8],
387 format: Fourcc,
388 size: Size<i32, BufferCoord>,
389 flipped: bool,
390 ) -> Result<GlesTexture, GlesError> {
391 self.gl.import_memory(data, format, size, flipped)
392 }
393
394 #[profiling::function]
395 fn update_memory(
396 &mut self,
397 texture: &Self::TextureId,
398 data: &[u8],
399 region: Rectangle<i32, BufferCoord>,
400 ) -> Result<(), Self::Error> {
401 self.gl.update_memory(texture, data, region)
402 }
403
404 fn mem_formats(&self) -> Box<dyn Iterator<Item = Fourcc>> {
405 self.gl.mem_formats()
406 }
407}
408
409#[cfg(all(
410 feature = "wayland_frontend",
411 feature = "backend_egl",
412 feature = "use_system_lib"
413))]
414impl ImportEgl for GlowRenderer {
415 fn bind_wl_display(
416 &mut self,
417 display: &wayland_server::DisplayHandle,
418 ) -> Result<(), crate::backend::egl::Error> {
419 self.gl.bind_wl_display(display)
420 }
421
422 fn unbind_wl_display(&mut self) {
423 self.gl.unbind_wl_display()
424 }
425
426 fn egl_reader(&self) -> Option<&EGLBufferReader> {
427 self.gl.egl_reader()
428 }
429
430 #[profiling::function]
431 fn import_egl_buffer(
432 &mut self,
433 buffer: &wl_buffer::WlBuffer,
434 surface: Option<&crate::wayland::compositor::SurfaceData>,
435 damage: &[Rectangle<i32, BufferCoord>],
436 ) -> Result<GlesTexture, GlesError> {
437 self.gl.import_egl_buffer(buffer, surface, damage)
438 }
439}
440
441impl ImportDma for GlowRenderer {
442 #[profiling::function]
443 fn import_dmabuf(
444 &mut self,
445 buffer: &Dmabuf,
446 damage: Option<&[Rectangle<i32, BufferCoord>]>,
447 ) -> Result<GlesTexture, GlesError> {
448 self.gl.import_dmabuf(buffer, damage)
449 }
450 fn dmabuf_formats(&self) -> FormatSet {
451 self.gl.dmabuf_formats()
452 }
453 fn has_dmabuf_format(&self, format: Format) -> bool {
454 self.gl.has_dmabuf_format(format)
455 }
456}
457
458#[cfg(feature = "wayland_frontend")]
459impl ImportDmaWl for GlowRenderer {}
460
461impl ExportMem for GlowRenderer {
462 type TextureMapping = GlesMapping;
463
464 #[profiling::function]
465 fn copy_framebuffer(
466 &mut self,
467 from: &GlesTarget<'_>,
468 region: Rectangle<i32, BufferCoord>,
469 format: Fourcc,
470 ) -> Result<Self::TextureMapping, Self::Error> {
471 self.gl.copy_framebuffer(from, region, format)
472 }
473
474 #[profiling::function]
475 fn copy_texture(
476 &mut self,
477 texture: &Self::TextureId,
478 region: Rectangle<i32, BufferCoord>,
479 format: Fourcc,
480 ) -> Result<Self::TextureMapping, Self::Error> {
481 self.gl.copy_texture(texture, region, format)
482 }
483
484 fn can_read_texture(&mut self, texture: &Self::TextureId) -> Result<bool, Self::Error> {
485 self.gl.can_read_texture(texture)
486 }
487
488 #[profiling::function]
489 fn map_texture<'a>(
490 &mut self,
491 texture_mapping: &'a Self::TextureMapping,
492 ) -> Result<&'a [u8], Self::Error> {
493 self.gl.map_texture(texture_mapping)
494 }
495}
496
497impl<T> Bind<T> for GlowRenderer
498where
499 GlesRenderer: Bind<T>,
500{
501 #[profiling::function]
502 fn bind<'a>(&mut self, target: &'a mut T) -> Result<GlesTarget<'a>, GlesError> {
503 self.gl.bind(target)
504 }
505 fn supported_formats(&self) -> Option<FormatSet> {
506 self.gl.supported_formats()
507 }
508}
509
510impl<T> Offscreen<T> for GlowRenderer
511where
512 GlesRenderer: Offscreen<T>,
513{
514 #[profiling::function]
515 fn create_buffer(&mut self, format: Fourcc, size: Size<i32, BufferCoord>) -> Result<T, GlesError> {
516 self.gl.create_buffer(format, size)
517 }
518}
519
520impl<'buffer> BlitFrame<GlesTarget<'buffer>> for GlowFrame<'_, 'buffer> {
521 fn blit_to(
522 &mut self,
523 to: &mut GlesTarget<'buffer>,
524 src: Rectangle<i32, Physical>,
525 dst: Rectangle<i32, Physical>,
526 filter: TextureFilter,
527 ) -> Result<(), Self::Error> {
528 self.frame.as_mut().unwrap().blit_to(to, src, dst, filter)
529 }
530
531 fn blit_from(
532 &mut self,
533 from: &GlesTarget<'buffer>,
534 src: Rectangle<i32, Physical>,
535 dst: Rectangle<i32, Physical>,
536 filter: TextureFilter,
537 ) -> Result<(), Self::Error> {
538 self.frame.as_mut().unwrap().blit_from(from, src, dst, filter)
539 }
540}
541
542impl Blit for GlowRenderer {
543 #[profiling::function]
544 fn blit(
545 &mut self,
546 from: &GlesTarget<'_>,
547 to: &mut GlesTarget<'_>,
548 src: Rectangle<i32, Physical>,
549 dst: Rectangle<i32, Physical>,
550 filter: TextureFilter,
551 ) -> Result<(), GlesError> {
552 self.gl.blit(from, to, src, dst, filter)
553 }
554}
555
556impl RenderElement<GlowRenderer> for PixelShaderElement {
557 #[profiling::function]
558 fn draw(
559 &self,
560 frame: &mut GlowFrame<'_, '_>,
561 src: Rectangle<f64, BufferCoord>,
562 dst: Rectangle<i32, Physical>,
563 damage: &[Rectangle<i32, Physical>],
564 opaque_regions: &[Rectangle<i32, Physical>],
565 ) -> Result<(), GlesError> {
566 RenderElement::<GlesRenderer>::draw(self, frame.borrow_mut(), src, dst, damage, opaque_regions)
567 }
568
569 fn underlying_storage(&self, renderer: &mut GlowRenderer) -> Option<UnderlyingStorage<'_>> {
570 RenderElement::<GlesRenderer>::underlying_storage(self, renderer.borrow_mut())
571 }
572}
573
574impl RenderElement<GlowRenderer> for TextureShaderElement {
575 #[profiling::function]
576 fn draw(
577 &self,
578 frame: &mut GlowFrame<'_, '_>,
579 src: Rectangle<f64, BufferCoord>,
580 dst: Rectangle<i32, Physical>,
581 damage: &[Rectangle<i32, Physical>],
582 opaque_regions: &[Rectangle<i32, Physical>],
583 ) -> Result<(), GlesError> {
584 RenderElement::<GlesRenderer>::draw(self, frame.borrow_mut(), src, dst, damage, opaque_regions)
585 }
586
587 fn underlying_storage(&self, renderer: &mut GlowRenderer) -> Option<UnderlyingStorage<'_>> {
588 RenderElement::<GlesRenderer>::underlying_storage(self, renderer.borrow_mut())
589 }
590}