gldebug: implement a delayed debug system
authorMatthew Waters <matthew@centricular.com>
Mon, 11 Jan 2016 06:22:26 +0000 (17:22 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:32:15 +0000 (19:32 +0000)
The messages are stored by gst_gl_async_debug_store_log_msg() and output later
by a corresponding store(), output() or an unset()/free().

Some wrapper macros are provided to avoid callers explicitly using __FILE__,
GST_FUNCTION and __LINE__

gst-libs/gst/gl/gstgldebug.c
gst-libs/gst/gl/gstgldebug.h

index 46833a7..e0e8da7 100644 (file)
 #include "gl.h"
 #include "gstgldebug.h"
 #include <glib/gprintf.h>
+#include <string.h>
 
+#define ASYNC_DEBUG_FILLED (1 << 0)
+#define ASYNC_DEBUG_FROZEN (1 << 1)
+
+/* compatibility defines */
 #ifndef GL_DEBUG_TYPE_ERROR
 #define GL_DEBUG_TYPE_ERROR 0x824C
 #endif
 #define GL_DEBUG_SOURCE_OTHER 0x824B
 #endif
 
-#if !defined(GST_DISABLE_GST_DEBUG)
 GST_DEBUG_CATEGORY_STATIC (gst_performance);
 #define GST_CAT_DEFAULT gst_gl_debug
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+GST_DEBUG_CATEGORY_STATIC (default_debug);
 
 static void
 _init_debug (void)
@@ -93,10 +98,85 @@ _init_debug (void)
   if (g_once_init_enter (&_init)) {
     GST_DEBUG_CATEGORY_GET (gst_performance, "GST_PERFORMANCE");
     GST_DEBUG_CATEGORY_INIT (gst_gl_debug, "gldebug", 0, "OpenGL Debugging");
+    GST_DEBUG_CATEGORY_GET (default_debug, "default");
     g_once_init_leave (&_init, 1);
   }
 }
 
+static void
+_free_async_debug_data (GstGLAsyncDebug * ad)
+{
+  if (ad->debug_msg) {
+    g_free (ad->debug_msg);
+    ad->debug_msg = NULL;
+    if (ad->object)
+      g_object_unref (ad->object);
+    ad->object = NULL;
+    ad->state_flags &= ~ASYNC_DEBUG_FILLED;
+  }
+}
+
+void
+gst_gl_async_debug_init (GstGLAsyncDebug * ad)
+{
+  _init_debug ();
+
+  memset (ad, 0, sizeof (*ad));
+}
+
+void
+gst_gl_async_debug_unset (GstGLAsyncDebug * ad)
+{
+  gst_gl_async_debug_output_log_msg (ad);
+
+  _free_async_debug_data (ad);
+
+  if (ad->notify)
+    ad->notify (ad->user_data);
+}
+
+GstGLAsyncDebug *
+gst_gl_async_debug_new (void)
+{
+  return g_new0 (GstGLAsyncDebug, 1);
+}
+
+void
+gst_gl_async_debug_free (GstGLAsyncDebug * ad)
+{
+  gst_gl_async_debug_unset (ad);
+  g_free (ad);
+}
+
+/**
+ * gst_gl_async_debug_freeze:
+ * @ad: a #GstGLAsyncDebug
+ *
+ * freeze the debug output.  While frozen, any call to
+ * gst_gl_async_debug_output_log_msg() will not output any messages but
+ * subsequent calls to gst_gl_async_debug_store_log_msg() will overwrite previous
+ * messages.
+ */
+void
+gst_gl_async_debug_freeze (GstGLAsyncDebug * ad)
+{
+  ad->state_flags |= ASYNC_DEBUG_FROZEN;
+}
+
+/**
+ * gst_gl_async_debug_thaw:
+ * @ad: a #GstGLAsyncDebug
+ *
+ * unfreeze the debug output.  See gst_gl_async_debug_freeze() for what freezing means
+ */
+void
+gst_gl_async_debug_thaw (GstGLAsyncDebug * ad)
+{
+  ad->state_flags &= ~ASYNC_DEBUG_FROZEN;
+}
+
+#if !defined(GST_DISABLE_GST_DEBUG)
+
 static inline const gchar *
 _debug_severity_to_string (GLenum severity)
 {
@@ -223,4 +303,98 @@ gst_gl_insert_debug_marker (GstGLContext * context, const gchar * format, ...)
 
   g_free (string);
 }
+
+/**
+ * gst_gl_async_debug_store_log_msg_valist:
+ * @ad: the #GstGLAsyncDebug to store the message in
+ * @cat: the #GstDebugCategory to output the message in
+ * @level: the #GstLevel
+ * @file: the file where the debug message originates from
+ * @function: the function where the debug message originates from
+ * @line: the line in @file where the debug message originates from
+ * @object: (allow-none): a #GObject to associate with the debug message
+ * @format: a printf style format string
+ * @varargs: the list of arguments for @format
+ *
+ * Stores a debug message for later output by gst_gl_async_debug_output_log_msg()
+ */
+void
+gst_gl_async_debug_store_log_msg_valist (GstGLAsyncDebug * ad,
+    GstDebugCategory * cat, GstDebugLevel level, const gchar * file,
+    const gchar * function, gint line, GObject * object, const gchar * format,
+    va_list varargs)
+{
+  gst_gl_async_debug_output_log_msg (ad);
+  _free_async_debug_data (ad);
+
+  if (G_UNLIKELY (level <= GST_LEVEL_MAX && level <= _gst_debug_min)) {
+    if (!cat)
+      cat = default_debug;
+
+    ad->cat = cat;
+    ad->level = level;
+    ad->file = file;
+    ad->function = function;
+    ad->line = line;
+    if (object)
+      ad->object = g_object_ref (object);
+    else
+      ad->object = NULL;
+
+    ad->debug_msg = gst_info_strdup_vprintf (format, varargs);
+    ad->state_flags |= ASYNC_DEBUG_FILLED;
+  }
+}
+
+/**
+ * gst_gl_async_debug_output_log_msg:
+ * @ad: the #GstGLAsyncDebug to store the message in
+ *
+ * Outputs a previously stored debug message.
+ */
+void
+gst_gl_async_debug_output_log_msg (GstGLAsyncDebug * ad)
+{
+  if ((ad->state_flags & ASYNC_DEBUG_FILLED) != 0
+      && (ad->state_flags & ASYNC_DEBUG_FROZEN) == 0) {
+    gchar *msg = NULL;
+
+    if (ad->callback)
+      msg = ad->callback (ad->user_data);
+
+    gst_debug_log (ad->cat, ad->level, ad->file, ad->function, ad->line,
+        ad->object, "%s %s", GST_STR_NULL (ad->debug_msg), msg ? msg : "");
+    g_free (msg);
+    _free_async_debug_data (ad);
+  }
+}
+
+/**
+ * gst_gl_async_debug_store_log_msg:
+ * @ad: the #GstGLAsyncDebug to store the message in
+ * @cat: the #GstDebugCategory to output the message in
+ * @level: the #GstLevel
+ * @file: the file where the debug message originates from
+ * @function: the function where the debug message originates from
+ * @line: the line in @file where the debug message originates from
+ * @object: (allow-none): a #GObject to associate with the debug message
+ * @format: a printf style format string
+ * @...: the list of arguments for @format
+ *
+ * Stores a debug message for later output by gst_gl_async_debug_output_log_msg()
+ */
+void
+gst_gl_async_debug_store_log_msg (GstGLAsyncDebug * ad, GstDebugCategory * cat,
+    GstDebugLevel level, const gchar * file, const gchar * function, gint line,
+    GObject * object, const gchar * format, ...)
+{
+  va_list varargs;
+
+  if (G_UNLIKELY (level <= GST_LEVEL_MAX && level <= _gst_debug_min)) {
+    va_start (varargs, format);
+    gst_gl_async_debug_store_log_msg_valist (ad, cat, level, file, function,
+        line, object, format, varargs);
+    va_end (varargs);
+  }
+}
 #endif
index c277825..5b936d0 100644 (file)
 
 G_BEGIN_DECLS
 
+typedef struct _GstGLAsyncDebug GstGLAsyncDebug;
+
+typedef gchar * (*GstGLAsyncDebugLogGetMessage) (gpointer user_data);
+
+/**
+ * GstGLAsyncDebug:
+ *
+ * #GstGLAsyncDebug an opaque structure and should only be accessed through the
+ * provided API.
+ */
+struct _GstGLAsyncDebug
+{
+  /* <private> */
+  guint             state_flags;
+  GstDebugCategory *cat;
+  GstDebugLevel     level;
+  const gchar      *file;
+  const gchar      *function;
+  gint              line;
+  GObject          *object;
+  gchar            *debug_msg;
+
+  /* <protected> */
+  GstGLAsyncDebugLogGetMessage callback;
+  gpointer          user_data;
+  GDestroyNotify    notify;
+};
+
+GstGLAsyncDebug *   gst_gl_async_debug_new                      (void);
+void                gst_gl_async_debug_free                     (GstGLAsyncDebug * ad);
+void                gst_gl_async_debug_init                     (GstGLAsyncDebug * ad);
+void                gst_gl_async_debug_unset                    (GstGLAsyncDebug * ad);
+void                gst_gl_async_debug_freeze                   (GstGLAsyncDebug * ad);
+void                gst_gl_async_debug_thaw                     (GstGLAsyncDebug * ad);
+
+/**
+ * GST_GL_ASYNC_CAT_LEVEL_LOG_valist:
+ * @ad: the #GstGLAsyncDebug to store the message in
+ * @cat: the #GstDebugCategory to output the message in
+ * @level: the #GstLevel
+ * @file: the file where the debug message originates from
+ * @function: the function where the debug message originates from
+ * @line: the line in @file where the debug message originates from
+ * @object: (allow-none): a #GObject to associate with the debug message
+ * @format: a printf style format string
+ * @varargs: the list of arguments for @format
+ *
+ * Stores a debug message in @ad for later output
+ */
+#define GST_GL_ASYNC_CAT_LEVEL_LOG_valist(ad,cat,level,object,format,varargs)   \
+    gst_gl_async_debug_store_log_msg_valist (ad, cat, level, __FILE__,          \
+        GST_FUNCTION, __LINE__, object, format, varargs)
+
+/**
+ * GST_GL_ASYNC_CAT_LEVEL_LOG:
+ * @ad: the #GstGLAsyncDebug to store the message in
+ * @cat: the #GstDebugCategory to output the message in
+ * @level: the #GstLevel
+ * @file: the file where the debug message originates from
+ * @function: the function where the debug message originates from
+ * @line: the line in @file where the debug message originates from
+ * @object: (allow-none): a #GObject to associate with the debug message
+ * @format: a printf style format string
+ * @...: the list of arguments for @format
+ *
+ * Stores a debug message in @ad for later output
+ */
+#if G_HAVE_ISO_VARARGS
+#define GST_GL_ASYNC_CAT_LEVEL_LOG(ad,cat,level,object,format,...)              \
+    gst_gl_async_debug_store_log_msg (ad, cat, level, __FILE__, GST_FUNCTION,   \
+        __LINE__, object, format, __VA_ARGS__)
+#else /* G_HAVE_ISO_VARARGS */
+#if G_HAVE_GNUC_VARARGS
+#define GST_GL_ASYNC_CAT_LEVEL_LOG(ad,cat,level,object,format,args...)          \
+    gst_gl_async_debug_store_log_msg (ad, cat, level, __FILE__, GST_FUNCTION,   \
+        __LINE__, object, format, ##args)
+#else /* G_HAVE_GNUC_VARARGS */
+static inline void
+GST_GL_ASYNC_CAT_LEVEL_LOG(GstGLAsyncDebug * ad, GstDebugCategory * cat,
+    GstDebugLevel level, GObject * object, const gchar * format, ...)
+{
+  va_list varargs;
+
+  va_start (varargs, format);
+  GST_GL_ASYNC_CAT_LEVEL_LOG_valist (ad, cat, level, object, format, varargs);
+  va_end (varargs);
+}
+#endif /* G_HAVE_GNUC_VARARGS */
+#endif /* G_HAVE_ISO_VARARGS */
+
 #if !defined(GST_DISABLE_GST_DEBUG)
-void gst_gl_insert_debug_marker (GstGLContext * context,
-                                 const gchar * format, ...) G_GNUC_PRINTF (2, 3);
+
+void        gst_gl_insert_debug_marker              (GstGLContext * context,
+                                                     const gchar * format, ...) G_GNUC_PRINTF (2, 3);
+void        gst_gl_async_debug_output_log_msg       (GstGLAsyncDebug * ad);
+void        gst_gl_async_debug_store_log_msg        (GstGLAsyncDebug * ad,
+                                                     GstDebugCategory * cat,
+                                                     GstDebugLevel level,
+                                                     const gchar * file,
+                                                     const gchar * function,
+                                                     gint line,
+                                                     GObject * object,
+                                                     const gchar * format, ...) G_GNUC_PRINTF (8, 9);
+void        gst_gl_async_debug_store_log_msg_valist (GstGLAsyncDebug * ad,
+                                                     GstDebugCategory * cat,
+                                                     GstDebugLevel level,
+                                                     const gchar * file,
+                                                     const gchar * function,
+                                                     gint line,
+                                                     GObject * object,
+                                                     const gchar * format,
+                                                     va_list varargs) G_GNUC_PRINTF (8, 0);
+
 #else /* GST_DISABLE_GST_DEBUG */
+
+#define gst_gl_async_debug_output_log_msg(ad) G_STMT_START{ }G_STMT_END
+#define gst_gl_async_debug_store_log_msg_valist(ad,cat,level,file,function,line,object,format,args) G_STMT_START{ }G_STMT_END
+
 #if G_HAVE_ISO_VARARGS
+
 #define gst_gl_insert_debug_marker(...) G_STMT_START{ }G_STMT_END
+#define gst_gl_async_debug_store_log_msg(...) G_STMT_START{ }G_STMT_END
+
 #else /* G_HAVE_ISO_VARARGS */
 #if G_HAVE_GNUC_VARARGS
+
 #define gst_gl_insert_debug_marker(args...) G_STMT_START{ }G_STMT_END
+#define gst_gl_async_debug_store_log_msg(args...) G_STMT_START{ }G_STMT_END
+
 #else /* G_HAVE_GNUC_VARARGS */
+
 static inline void
 gst_gl_insert_debug_marker (GstGLContext * context, const gchar * format, ...)
 {
 }
+
+static inline void
+gst_gl_async_debug_store_log_msg (GstGLAsyncDebug * ad,
+    GstDebugCategory * cat, GstDebugLevel level, const gchar * file,
+    const gchar * function, gint line, GstObject * object,
+    const gchar * format, ...)
+{
+}
+
 #endif /* G_HAVE_GNUC_VARARGS */
 #endif /* G_HAVE_ISO_VARARGS */
 #endif /* GST_DISABLE_GST_DEBUG */