gioser

tawasuyu/mirada

Sovereign tiling Wayland compositor + window manager in Rust, on Llimphi.

Rust 50Markdown 30TOML 211282 Definitions

⎇ main vendor/smithay/src/backend/renderer/glow.rs Rust · 590 lines · 18.0 KB History Who touched what raw

chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0) a91da3fea · Sergio ·

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}