From 3ddbdbd38359fa36adb6ee679744658369c9ed16 Mon Sep 17 00:00:00 2001
From: Anders Hellerup Madsen <ahem@github.com>
Date: Sun, 5 Feb 2023 17:56:47 +0100
Subject: [PATCH] gstreamer-gl: Require object lock in GLDisplay

The methods `gst_gl_display_get_gl_context_for_thread()`,
`gst_gl_display_create_context()`, `gst_gl_display_add_context()` and
`gst_gl_display_remove_context()` now require the display's object lock
to be held when called.

This is required by the C API.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/439

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1212>
---
 gstreamer-gl/Gir.toml               | 18 ++++---
 gstreamer-gl/src/auto/gl_display.rs | 61 +----------------------
 gstreamer-gl/src/gl_display.rs      | 77 +++++++++++++++++++++++++++++
 gstreamer-gl/src/lib.rs             |  1 +
 4 files changed, 90 insertions(+), 67 deletions(-)
 create mode 100644 gstreamer-gl/src/gl_display.rs

diff --git a/gstreamer-gl/Gir.toml b/gstreamer-gl/Gir.toml
index cdb13e09f..5793ab748 100644
--- a/gstreamer-gl/Gir.toml
+++ b/gstreamer-gl/Gir.toml
@@ -338,19 +338,23 @@ status = "generate"
 
     [[object.function]]
     name = "get_gl_context_for_thread"
-    # glib::Thread not found in `glib`
-    ignore = true
+    # require object lock
+    manual = true
 
     [[object.function]]
     name = "create_context"
-        [[object.function.parameter]]
-        name = "other_context"
-        nullable = true
+    # require object lock
+    manual = true
 
     [[object.function]]
     name = "add_context"
-        [object.function.return]
-        bool_return_is_error = "Failed to add OpenGL context"
+    # require object lock
+    manual = true
+
+    [[object.function]]
+    name = "remove_context"
+    # require object lock
+    manual = true
 
     [[object.function]]
     name = "remove_window"
diff --git a/gstreamer-gl/src/auto/gl_display.rs b/gstreamer-gl/src/auto/gl_display.rs
index a0cc68736..0e2c67dfe 100644
--- a/gstreamer-gl/src/auto/gl_display.rs
+++ b/gstreamer-gl/src/auto/gl_display.rs
@@ -9,7 +9,7 @@ use glib::{
     signal::{connect_raw, SignalHandlerId},
     translate::*,
 };
-use std::{boxed::Box as Box_, mem::transmute, ptr};
+use std::{boxed::Box as Box_, mem::transmute};
 
 glib::wrapper! {
     #[doc(alias = "GstGLDisplay")]
@@ -49,15 +49,6 @@ unsafe impl Send for GLDisplay {}
 unsafe impl Sync for GLDisplay {}
 
 pub trait GLDisplayExt: 'static {
-    #[doc(alias = "gst_gl_display_add_context")]
-    fn add_context(&self, context: &impl IsA<GLContext>) -> Result<(), glib::error::BoolError>;
-
-    #[doc(alias = "gst_gl_display_create_context")]
-    fn create_context(
-        &self,
-        other_context: Option<&impl IsA<GLContext>>,
-    ) -> Result<GLContext, glib::Error>;
-
     #[doc(alias = "gst_gl_display_create_window")]
     fn create_window(&self) -> Result<GLWindow, glib::BoolError>;
 
@@ -76,11 +67,6 @@ pub trait GLDisplayExt: 'static {
     #[doc(alias = "get_handle_type")]
     fn handle_type(&self) -> GLDisplayType;
 
-    #[cfg(any(feature = "v1_18", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
-    #[doc(alias = "gst_gl_display_remove_context")]
-    fn remove_context(&self, context: &impl IsA<GLContext>);
-
     #[doc(alias = "gst_gl_display_remove_window")]
     fn remove_window(&self, window: &impl IsA<GLWindow>) -> Result<(), glib::error::BoolError>;
 
@@ -99,40 +85,6 @@ pub trait GLDisplayExt: 'static {
 }
 
 impl<O: IsA<GLDisplay>> GLDisplayExt for O {
-    fn add_context(&self, context: &impl IsA<GLContext>) -> Result<(), glib::error::BoolError> {
-        unsafe {
-            glib::result_from_gboolean!(
-                ffi::gst_gl_display_add_context(
-                    self.as_ref().to_glib_none().0,
-                    context.as_ref().to_glib_none().0
-                ),
-                "Failed to add OpenGL context"
-            )
-        }
-    }
-
-    fn create_context(
-        &self,
-        other_context: Option<&impl IsA<GLContext>>,
-    ) -> Result<GLContext, glib::Error> {
-        unsafe {
-            let mut p_context = ptr::null_mut();
-            let mut error = ptr::null_mut();
-            let is_ok = ffi::gst_gl_display_create_context(
-                self.as_ref().to_glib_none().0,
-                other_context.map(|p| p.as_ref()).to_glib_none().0,
-                &mut p_context,
-                &mut error,
-            );
-            debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
-            if error.is_null() {
-                Ok(from_glib_full(p_context))
-            } else {
-                Err(from_glib_full(error))
-            }
-        }
-    }
-
     fn create_window(&self) -> Result<GLWindow, glib::BoolError> {
         unsafe {
             Option::<_>::from_glib_full(ffi::gst_gl_display_create_window(
@@ -172,17 +124,6 @@ impl<O: IsA<GLDisplay>> GLDisplayExt for O {
         }
     }
 
-    #[cfg(any(feature = "v1_18", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
-    fn remove_context(&self, context: &impl IsA<GLContext>) {
-        unsafe {
-            ffi::gst_gl_display_remove_context(
-                self.as_ref().to_glib_none().0,
-                context.as_ref().to_glib_none().0,
-            );
-        }
-    }
-
     fn remove_window(&self, window: &impl IsA<GLWindow>) -> Result<(), glib::error::BoolError> {
         unsafe {
             glib::result_from_gboolean!(
diff --git a/gstreamer-gl/src/gl_display.rs b/gstreamer-gl/src/gl_display.rs
new file mode 100644
index 000000000..d1755153c
--- /dev/null
+++ b/gstreamer-gl/src/gl_display.rs
@@ -0,0 +1,77 @@
+use crate::{GLContext, GLDisplay};
+
+use glib::prelude::*;
+use glib::translate::*;
+
+impl GLDisplay {
+    #[doc(alias = "gst_gl_display_get_gl_context_for_thread")]
+    pub fn get_gl_context_for_current_thread(
+        display: &gst::ObjectLockGuard<GLDisplay>,
+    ) -> Option<GLContext> {
+        skip_assert_initialized!();
+        unsafe {
+            let ctx = ffi::gst_gl_display_get_gl_context_for_thread(
+                display.as_ref().to_glib_none().0,
+                std::ptr::null_mut(),
+            );
+            from_glib_full(ctx)
+        }
+    }
+
+    #[doc(alias = "gst_gl_display_create_context")]
+    pub fn create_context(
+        display: &gst::ObjectLockGuard<GLDisplay>,
+        other_context: Option<&impl IsA<GLContext>>,
+    ) -> Result<GLContext, glib::Error> {
+        skip_assert_initialized!();
+        unsafe {
+            let mut p_context = std::ptr::null_mut();
+            let mut error = std::ptr::null_mut();
+            let is_ok = ffi::gst_gl_display_create_context(
+                display.as_ref().to_glib_none().0,
+                other_context.map(|p| p.as_ref()).to_glib_none().0,
+                &mut p_context,
+                &mut error,
+            );
+            debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
+            if error.is_null() {
+                Ok(from_glib_full(p_context))
+            } else {
+                Err(from_glib_full(error))
+            }
+        }
+    }
+
+    #[doc(alias = "gst_gl_display_add_context")]
+    pub fn add_context(
+        display: &gst::ObjectLockGuard<GLDisplay>,
+        context: &impl IsA<GLContext>,
+    ) -> Result<(), glib::error::BoolError> {
+        skip_assert_initialized!();
+        unsafe {
+            glib::result_from_gboolean!(
+                ffi::gst_gl_display_add_context(
+                    display.as_ref().to_glib_none().0,
+                    context.as_ref().to_glib_none().0
+                ),
+                "Failed to add OpenGL context"
+            )
+        }
+    }
+
+    #[cfg(any(feature = "v1_18", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))]
+    #[doc(alias = "gst_gl_display_remove_context")]
+    pub fn remove_context(
+        display: &gst::ObjectLockGuard<GLDisplay>,
+        context: &impl IsA<GLContext>,
+    ) {
+        skip_assert_initialized!();
+        unsafe {
+            ffi::gst_gl_display_remove_context(
+                display.as_ref().to_glib_none().0,
+                context.as_ref().to_glib_none().0,
+            );
+        }
+    }
+}
diff --git a/gstreamer-gl/src/lib.rs b/gstreamer-gl/src/lib.rs
index 4bd6f12f0..93bd68398 100644
--- a/gstreamer-gl/src/lib.rs
+++ b/gstreamer-gl/src/lib.rs
@@ -40,6 +40,7 @@ mod context;
 pub mod functions;
 pub use crate::functions::*;
 mod gl_context;
+mod gl_display;
 mod gl_sync_meta;
 mod gl_video_frame;
 pub use crate::gl_sync_meta::*;