1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* SPDX-License-Identifier: LGPL-2.1-or-later

Copyright (c) 2022 Purism, SPC
*/

/*! Minimal glium backend. Tested with EGL+gbm context. */

use crate::ContextRef;
use crate::egl::EglContext;
use std::cell::RefCell;
use std::ffi::c_void;
use std::rc::Rc;

/// A simple backend for GBM buffers used via an EGL context.
///
/// Contrary to a typical backend (?), this one does not assume a default buffer. It's meant to be used to draw to random surfaces. (TODO: is there a reason to attach it to every GBM surface?).
///
/// Not very safe. Do your own swapbuffers.
/// Prints debug info.
pub struct Backend{
    ctx: ContextRef,
    size: Rc<RefCell<(u32, u32)>>,
}

impl Backend {
    fn new(ctx: ContextRef, size: (u32, u32)) -> Self {
        Backend { ctx, size: Rc::new(RefCell::new(size)) }
    }
    pub unsafe fn get_proc_address(name: &str) -> *const c_void {
        ContextRef::get_proc_address(name)
    }
}

unsafe impl glium::backend::Backend for Backend {
    fn swap_buffers(&self) -> Result<(), glium::SwapBuffersError> { Ok(()) }
    unsafe fn get_proc_address(&self, name: &str) -> *const c_void {
        Backend::get_proc_address(name)
    }

    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        let _ = *self.size.borrow();
        unimplemented!("There is no default framebuffer. Use an explicit surface.");
    }

    fn is_current(&self) -> bool { false }
    unsafe fn make_current(&self) {
        unsafe { self.ctx.force_make_current() }
    }

    fn resize(&self, new_size:(u32, u32)) {
        *self.size.borrow_mut() = new_size;
        unimplemented!("There is no default framebuffer. Use an explicit surface.");
    }
}

/// The context for glium operations.
/// For EGL operations, use the EGL context directly.
pub struct Facade {
    ctx: Rc<glium::backend::Context>,
    egl: ContextRef,
}

impl glium::backend::Facade for Facade {
    fn get_context(&self) -> &Rc<glium::backend::Context> { &self.ctx }
}

impl Facade {
    pub fn new(ctx: ContextRef, size: (u32, u32)) -> Self {
        Self {
            ctx: {
                // Backend::new calls Backend::make_current, but we pretend w don't know it.
                let _current_lock = ctx.make_current();
                unsafe {
                    glium::backend::Context::new(
                        Backend::new(ctx.clone(), size),
                        false,
                        glium::debug::DebugCallbackBehavior::PrintAll
                    )
                }.unwrap()
            },
            egl: ctx,
        }
    }

    pub fn get_egl_context(&self) -> &ContextRef {
        &self.egl
    }
    
    // TODO: does the size even matter for this use case?
    // The size describes the default frame buffer.
    // We don't have and never write to the default frame buffer, after all.
    pub fn new_unsized(ctx: ContextRef) -> Self {
        Self::new(ctx, (0, 0))
    }
}