[retro-gtk] Add and use GL autocleanup



commit 1736b0a90050576493ccad2a5ce4e76295c701d2
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Sun May 24 09:34:05 2020 +0200

    Add and use GL autocleanup
    
    This makes the code safer and more concise.

 retro-gtk/retro-gl-display.c     | 10 +++----
 retro-gtk/retro-glsl-shader.c    | 31 +++++++------------
 retro-runner/retro-gl-renderer.c | 18 +++--------
 shared/retro-gl-private.h        | 65 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 41 deletions(-)
---
diff --git a/retro-gtk/retro-gl-display.c b/retro-gtk/retro-gl-display.c
index b105926..dff5c71 100644
--- a/retro-gtk/retro-gl-display.c
+++ b/retro-gtk/retro-gl-display.c
@@ -11,6 +11,7 @@
 
 #include <epoxy/gl.h>
 #include "retro-error-private.h"
+#include "retro-gl-private.h"
 #include "retro-glsl-filter-private.h"
 #include "retro-pixbuf.h"
 #include "retro-pixdata.h"
@@ -254,8 +255,7 @@ realize (RetroGLDisplay *self)
                                              (const GLvoid *) offsetof (RetroVertex, texture_coordinates));
   }
 
-  glDeleteTextures (1, &self->texture);
-  self->texture = 0;
+  retro_gl_clear_object_n (&self->texture, 1, glDeleteTextures);
   glGenTextures (1, &self->texture);
   glBindTexture (GL_TEXTURE_2D, self->texture);
 
@@ -276,8 +276,7 @@ unrealize (RetroGLDisplay *self)
 {
   gtk_gl_area_make_current (GTK_GL_AREA (self));
 
-  glDeleteTextures (1, &self->texture);
-  self->texture = 0;
+  retro_gl_clear_object_n (&self->texture, 1, glDeleteTextures);
   for (RetroVideoFilter filter = 0; filter < RETRO_VIDEO_FILTER_COUNT; filter++)
     g_clear_object (&self->glsl_filter[filter]);
 }
@@ -310,8 +309,7 @@ retro_gl_display_finalize (GObject *object)
 {
   RetroGLDisplay *self = (RetroGLDisplay *) object;
 
-  glDeleteTextures (1, &self->texture);
-  self->texture = 0;
+  retro_gl_clear_object_n (&self->texture, 1, glDeleteTextures);
   for (RetroVideoFilter filter = 0; filter < RETRO_VIDEO_FILTER_COUNT; filter++)
     g_clear_object (&self->glsl_filter[filter]);
   g_clear_object (&self->core);
diff --git a/retro-gtk/retro-glsl-shader.c b/retro-gtk/retro-glsl-shader.c
index b606c1b..df5630c 100644
--- a/retro-gtk/retro-glsl-shader.c
+++ b/retro-gtk/retro-glsl-shader.c
@@ -3,6 +3,7 @@
 #include "retro-glsl-shader-private.h"
 
 #include "retro-error-private.h"
+#include "retro-gl-private.h"
 
 struct _RetroGLSLShader
 {
@@ -32,7 +33,7 @@ create_shader (GBytes  *source_bytes,
 {
   const gchar *source;
   gint size;
-  GLuint shader;
+  retro_gl_autodelete_shader GLuint shader = 0;
   gint status;
 
   source = g_bytes_get_data (source_bytes, NULL);
@@ -55,12 +56,10 @@ create_shader (GBytes  *source_bytes,
                  shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
                  buffer);
 
-    glDeleteShader (shader);
-
     return 0;
   }
 
-  return shader;
+  return retro_gl_steal_object (&shader);
 }
 
 static void
@@ -68,10 +67,7 @@ retro_glsl_shader_finalize (GObject *object)
 {
   RetroGLSLShader *self = (RetroGLSLShader *) object;
 
-  if (self->program != 0) {
-    glDeleteProgram (self->program);
-    self->program = 0;
-  }
+  retro_gl_clear_object (&self->program, glDeleteProgram);
 
   G_OBJECT_CLASS (retro_glsl_shader_parent_class)->finalize (object);
 }
@@ -98,8 +94,8 @@ retro_glsl_shader_new (GBytes  *vertex,
 {
   g_autoptr (RetroGLSLShader) self = NULL;
   gint status = 0;
-  GLuint vertex_shader;
-  GLuint fragment_shader;
+  retro_gl_autodelete_shader GLuint vertex_shader = 0;
+  retro_gl_autodelete_shader GLuint fragment_shader = 0;
 
   g_return_val_if_fail (vertex != NULL, NULL);
   g_return_val_if_fail (fragment != NULL, NULL);
@@ -117,13 +113,9 @@ retro_glsl_shader_new (GBytes  *vertex,
     vertex_shader = create_shader (self->vertex, GL_VERTEX_SHADER, &catch);
   }, catch, error, NULL);
 
-  retro_try ({
+  retro_try_propagate_val ({
     fragment_shader = create_shader (self->fragment, GL_FRAGMENT_SHADER, &catch);
-  }, catch, {
-    glDeleteShader (vertex_shader);
-
-    return NULL;
-  });
+  }, catch, error, NULL);
 
   self->program = glCreateProgram ();
   glAttachShader (self->program, vertex_shader);
@@ -142,14 +134,11 @@ retro_glsl_shader_new (GBytes  *vertex,
     g_set_error (error, RETRO_GLSL_SHADER_ERROR, RETRO_GLSL_SHADER_ERROR_COULDNT_LINK,
                  "Linking failure in program: %s", buffer);
 
-    glDeleteShader (vertex_shader);
-    glDeleteShader (fragment_shader);
-
     return NULL;
   }
 
-  glDetachShader (self->program, vertex_shader);
-  glDetachShader (self->program, fragment_shader);
+  glDetachShader (self->program, retro_gl_steal_object (&vertex_shader));
+  glDetachShader (self->program, retro_gl_steal_object (&fragment_shader));
 
   return g_steal_pointer (&self);
 }
diff --git a/retro-runner/retro-gl-renderer.c b/retro-runner/retro-gl-renderer.c
index f096606..7de5109 100644
--- a/retro-runner/retro-gl-renderer.c
+++ b/retro-runner/retro-gl-renderer.c
@@ -4,6 +4,7 @@
 
 #include <gio/gio.h>
 #include "epoxy/egl.h"
+#include "retro-gl-private.h"
 
 #define MAX_EGL_ATTRS 30
 
@@ -189,20 +190,9 @@ retro_gl_renderer_finalize (GObject *object)
    * so that it actually has a chance to run */
   self->callback->context_destroy ();
 
-  if (self->texture) {
-    glDeleteTextures (1, &self->texture);
-    self->texture = 0;
-  }
-
-  if (self->renderbuffer) {
-    glDeleteRenderbuffers (1, &self->renderbuffer);
-    self->renderbuffer = 0;
-  }
-
-  if (self->framebuffer) {
-    glDeleteFramebuffers (1, &self->framebuffer);
-    self->framebuffer = 0;
-  }
+  retro_gl_clear_object_n (&self->texture, 1, glDeleteTextures);
+  retro_gl_clear_object_n (&self->renderbuffer, 1, glDeleteRenderbuffers);
+  retro_gl_clear_object_n (&self->framebuffer, 1, glDeleteFramebuffers);
 
   eglDestroyContext (self->display, self->context);
   self->context = EGL_NO_CONTEXT;
diff --git a/shared/retro-gl-private.h b/shared/retro-gl-private.h
new file mode 100644
index 0000000..22bc254
--- /dev/null
+++ b/shared/retro-gl-private.h
@@ -0,0 +1,65 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#pragma once
+
+#if !defined(__RETRO_GTK_INSIDE__) && !defined(RETRO_GTK_COMPILATION)
+# error "Only <retro-gtk.h> can be included directly."
+#endif
+
+#include <epoxy/gl.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef void (*RetroGlDestroyFunc) (GLuint object);
+
+typedef void (*RetroGlArrayDestroyFunc) (GLsizei       n_objects,
+                                         const GLuint *objects);
+
+static inline GLuint
+retro_gl_steal_object (GLuint *object_p)
+{
+  GLuint object = *object_p;
+
+  *object_p = 0;
+
+  return object;
+}
+
+static inline void
+retro_gl_clear_object (GLuint             *object_p,
+                       RetroGlDestroyFunc  destroy)
+{
+  GLuint object = *object_p;
+
+  if (object) {
+    *object_p = 0;
+    destroy (object);
+  }
+}
+
+static inline void
+retro_gl_clear_object_n (GLuint                  *objects_p,
+                         GLsizei                  n_objects,
+                         RetroGlArrayDestroyFunc  destroy)
+{
+  GLuint objects = *objects_p;
+
+  if (objects) {
+    *objects_p = 0;
+    destroy (n_objects, &objects);
+  }
+}
+
+static inline void
+retro_gl_autocleanup_delete_shader (GLuint *object_p)
+{
+  if (*object_p == 0)
+    return;
+
+  glDeleteShader (*object_p);
+}
+
+#define retro_gl_autodelete_shader __attribute__((cleanup(retro_gl_autocleanup_delete_shader)))
+
+G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]