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
use glib::{prelude::*, translate::*};

use crate::{GLFramebuffer, GLMemoryRef};

mod sealed {
    pub trait Sealed {}
    impl<T: super::IsA<super::GLFramebuffer>> Sealed for T {}
}

pub trait GLFramebufferExtManual: sealed::Sealed + IsA<GLFramebuffer> + 'static {
    /// Perform the steps necessary to have the output of a glDraw* command in
    /// `func` update the contents of `mem`.
    ///
    /// Note: this function does not map `mem` for writing with OpenGL and that must
    /// be done manually by the caller using any of the mapping functions such as
    /// [`gst::Memory::map()`][crate::gst::Memory::map()] with the map flags `GST_MAP_WRITE` | `GST_MAP_GL`.
    ///
    /// Must be called with the same OpenGL context current that `self` was created
    /// with.
    /// ## `mem`
    /// the [`GLMemory`][crate::GLMemory] to draw to
    /// ## `func`
    /// the function to run
    ///
    /// # Returns
    ///
    /// the result of executing `func`
    #[doc(alias = "gst_gl_framebuffer_draw_to_texture")]
    fn draw_to_texture<F: FnOnce()>(&self, mem: &mut GLMemoryRef, func: F) {
        let mut func = std::mem::ManuallyDrop::new(func);
        let user_data: *mut F = &mut *func;

        unsafe extern "C" fn trampoline<F: FnOnce()>(
            data: glib::ffi::gpointer,
        ) -> glib::ffi::gboolean {
            let func = std::ptr::read(data as *mut F);
            func();
            glib::ffi::GTRUE
        }

        unsafe {
            ffi::gst_gl_framebuffer_draw_to_texture(
                self.as_ref().to_glib_none().0,
                mem.as_mut_ptr(),
                Some(trampoline::<F>),
                user_data as glib::ffi::gpointer,
            );
        }
    }
}

impl<O: IsA<GLFramebuffer>> GLFramebufferExtManual for O {}