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
use std::fmt;
use std::ops;
use std::rc::Rc;

#[allow(clippy::all)]
mod gl {
    include!(concat!(env!("OUT_DIR"), "/opengl-bindings.rs"));
}

pub use gl::*;

mod miru {
    include!(concat!(env!("OUT_DIR"), "/miru-pinned-opengl-version.rs"));
}

/// Wrapper around Gl type that should be used instead of [`Gl`][1].
///
/// This transparent wrapper allows to safely share and use OpenGL functions
/// without risk of them being called before they're loaded.
///
/// \![`Send`][2] nature of [`Rc<T>`][3] also guarantees that context won't be
/// transferred across thread boundaries, ensuring that functions of a context
/// can only be called in the same thread they were loaded in.
///
/// [1]: struct.Gl.html
/// [2]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [3]: https://doc.rust-lang.org/std/rc/struct.Rc.html
#[derive(Clone)]
pub struct MiruGl {
    inner: Rc<Gl>,
}

impl MiruGl {
    /// Loads OpenGL functions and returns shared handle.
    ///
    /// # Examples
    ///
    /// ~~~ignore
    /// // the supplied function must be of the type:
    /// // `&fn(symbol: &'static str) -> *const std::ffi::c_void`
    /// let gl = miru_gl::MiruGl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
    /// ~~~
    #[cfg_attr(tarpaulin, skip)]
    pub fn load_with<F>(loadfn: F) -> MiruGl
    where
        F: FnMut(&'static str) -> *const std::ffi::c_void,
    {
        MiruGl {
            inner: Rc::new(Gl::load_with(loadfn)),
        }
    }

    /// Returns OpenGL version used by Miru.
    ///
    /// # Examples
    ///
    /// ~~~ignore
    /// let (major, minor) = gl.version();
    /// ~~~
    #[cfg_attr(tarpaulin, skip)]
    pub fn version(&self) -> (u8, u8) {
        miru::OPENGL_VERSION
    }
}

impl fmt::Debug for MiruGl {
    #[cfg_attr(tarpaulin, skip)]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (major, minor) = self.version();
        write!(
            f,
            "MiruGl: Shared OpenGL {}.{} (Core Profile) api handle",
            major, minor
        )
    }
}

impl ops::Deref for MiruGl {
    type Target = Gl;

    #[cfg_attr(tarpaulin, skip)]
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}