[retro-gtk] glsl-filter: Throw errors on program preparation



commit e2697319c3adba51b73be400ecd8e0b774ab070c
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Thu Nov 16 11:42:35 2017 +0100

    glsl-filter: Throw errors on program preparation
    
    Also clean up the code code a bit more.

 retro-gtk/retro-gl-display.c  |   25 +++++++----
 retro-gtk/retro-glsl-filter.c |  100 ++++++++++++++++++++++++++++++++++++-----
 retro-gtk/retro-glsl-filter.h |    3 +-
 3 files changed, 107 insertions(+), 21 deletions(-)
---
diff --git a/retro-gtk/retro-gl-display.c b/retro-gtk/retro-gl-display.c
index 34f5dc1..95d9f04 100644
--- a/retro-gtk/retro-gl-display.c
+++ b/retro-gtk/retro-gl-display.c
@@ -104,6 +104,7 @@ retro_gl_display_realize (RetroGLDisplay *self)
   GLuint vertex_array_object;
   GLuint element_buffer_object;
   RetroVideoFilter filter;
+  GError *inner_error = NULL;
 
   gtk_gl_area_make_current (GTK_GL_AREA (self));
 
@@ -120,7 +121,16 @@ retro_gl_display_realize (RetroGLDisplay *self)
 
   for (filter = 0; filter < RETRO_VIDEO_FILTER_COUNT; filter++) {
     self->glsl_filter[filter] = retro_glsl_filter_new (filter_uris[filter], NULL);
-    retro_glsl_filter_prepare_program (self->glsl_filter[filter]);
+    retro_glsl_filter_prepare_program (self->glsl_filter[filter], &inner_error);
+    if (G_UNLIKELY (inner_error != NULL)) {
+      g_critical ("Shader program %s creation failed: %s",
+                  filter_uris[filter],
+                  inner_error->message);
+      g_clear_object (&self->glsl_filter[filter]);
+      g_clear_error (&inner_error);
+
+      continue;
+    }
 
     retro_glsl_filter_set_attribute_pointer (self->glsl_filter[filter],
                                              "position",
@@ -167,10 +177,6 @@ retro_gl_display_unrealize (RetroGLDisplay *self)
 static gboolean
 retro_gl_display_render (RetroGLDisplay *self)
 {
-  gdouble w = 0.0;
-  gdouble h = 0.0;
-  gdouble x = 0.0;
-  gdouble y = 0.0;
   GLfloat source_width, source_height;
   GLfloat target_width, target_height;
   GLfloat output_width, output_height;
@@ -178,19 +184,20 @@ retro_gl_display_render (RetroGLDisplay *self)
 
   g_return_val_if_fail (self != NULL, FALSE);
 
-  retro_gl_display_get_video_box (self, &w, &h, &x, &y);
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
   filter = self->filter >= RETRO_VIDEO_FILTER_COUNT ?
     RETRO_VIDEO_FILTER_SMOOTH :
     self->filter;
 
-  retro_glsl_filter_use_program (self->glsl_filter[filter]);
-
-  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  if (self->glsl_filter[filter] == NULL)
+    return FALSE;
 
   if (self->pixbuf == NULL)
     return FALSE;
 
+  retro_glsl_filter_use_program (self->glsl_filter[filter]);
+
   glTexImage2D (GL_TEXTURE_2D,
                 0,
                 GL_RGB,
diff --git a/retro-gtk/retro-glsl-filter.c b/retro-gtk/retro-glsl-filter.c
index b82c0a4..9e1790b 100644
--- a/retro-gtk/retro-glsl-filter.c
+++ b/retro-gtk/retro-glsl-filter.c
@@ -9,8 +9,6 @@ struct _RetroGLSLFilter
   GBytes *fragment;
   GLenum wrap;
   GLenum filter;
-  GLuint vertex_shader;
-  GLuint fragment_shader;
   GLuint program;
 };
 
@@ -18,6 +16,15 @@ G_DEFINE_TYPE (RetroGLSLFilter, retro_glsl_filter, G_TYPE_OBJECT)
 
 #define GLSL_FILTER_GROUP "GLSL Filter"
 
+#define RETRO_GLSL_FILTER_ERROR (retro_glsl_filter_error_quark ())
+
+typedef enum {
+  RETRO_GLSL_FILTER_ERROR_SHADER_COMPILATION,
+  RETRO_GLSL_FILTER_ERROR_SHADER_LINK
+} RetroGLSLFilterError;
+
+G_DEFINE_QUARK (retro-glsl-filter-error, retro_glsl_filter_error)
+
 static const gchar *
 g_key_file_try_get_string (GKeyFile    *key_file,
                            const gchar *group,
@@ -203,9 +210,8 @@ retro_glsl_filter_finalize (GObject *object)
     g_bytes_unref (self->vertex);
   if (self->fragment != NULL)
     g_bytes_unref (self->fragment);
-  glDeleteShader (self->vertex_shader);
-  glDeleteShader (self->fragment_shader);
   glDeleteProgram (self->program);
+  self->program = 0;
 
   G_OBJECT_CLASS (retro_glsl_filter_parent_class)->finalize (object);
 }
@@ -235,12 +241,16 @@ retro_glsl_filter_apply_texture_params (RetroGLSLFilter *self)
 }
 
 static GLuint
-create_shader (GBytes *source_bytes,
-               GLenum  shader_type)
+create_shader (GBytes  *source_bytes,
+               GLenum   shader_type,
+               GError **error)
 {
   const gchar *source;
   gint size;
   GLuint shader;
+  gint status;
+  gint log_length;
+  gchar *buffer;
 
   source = g_bytes_get_data (source_bytes, NULL);
   size = g_bytes_get_size (source_bytes);
@@ -248,27 +258,92 @@ create_shader (GBytes *source_bytes,
   glShaderSource (shader, 1, &source, &size);
   glCompileShader (shader);
 
+  status = 0;
+  glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
+  if (status == GL_FALSE) {
+    glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_length);
+    buffer = g_malloc (log_length + 1);
+    glGetShaderInfoLog (shader, log_length, NULL, buffer);
+
+    g_set_error (error, RETRO_GLSL_FILTER_ERROR, RETRO_GLSL_FILTER_ERROR_SHADER_COMPILATION,
+                 "Compilation failure in %s shader: %s",
+                 shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
+                 buffer);
+
+    g_free (buffer);
+    glDeleteShader (shader);
+
+    return 0;
+  }
+
   return shader;
 }
 
 void
-retro_glsl_filter_prepare_program (RetroGLSLFilter *self)
+retro_glsl_filter_prepare_program (RetroGLSLFilter  *self,
+                                   GError          **error)
 {
+  gint status;
+  gint log_length;
+  gchar *buffer;
+  GLuint vertex_shader;
+  GLuint fragment_shader;
+  GError *inner_error = NULL;
+
   g_return_if_fail (RETRO_IS_GLSL_FILTER (self));
+  g_return_if_fail (self->program == 0);
 
-  self->vertex_shader = create_shader (self->vertex, GL_VERTEX_SHADER);
-  self->fragment_shader = create_shader (self->fragment, GL_FRAGMENT_SHADER);
+  vertex_shader = create_shader (self->vertex, GL_VERTEX_SHADER, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_propagate_error (error, inner_error);
+    self->program = 0;
+
+    return;
+  }
+
+  fragment_shader = create_shader (self->fragment, GL_FRAGMENT_SHADER, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_propagate_error (error, inner_error);
+    glDeleteShader (vertex_shader);
+    self->program = 0;
+
+    return;
+  }
 
   self->program = glCreateProgram();
-  glAttachShader (self->program, self->vertex_shader);
-  glAttachShader (self->program, self->fragment_shader);
+  glAttachShader (self->program, vertex_shader);
+  glAttachShader (self->program, fragment_shader);
   glLinkProgram (self->program);
+
+  status = 0;
+  glGetProgramiv (self->program, GL_LINK_STATUS, &status);
+  if (status == GL_FALSE) {
+    log_length = 0;
+    glGetProgramiv (self->program, GL_INFO_LOG_LENGTH, &log_length);
+    buffer = g_malloc (log_length + 1);
+    glGetProgramInfoLog (self->program, log_length, NULL, buffer);
+
+    g_set_error (error, RETRO_GLSL_FILTER_ERROR, RETRO_GLSL_FILTER_ERROR_SHADER_LINK,
+                 "Linking failure in program: %s", buffer);
+    g_free (buffer);
+
+    glDeleteShader (vertex_shader);
+    glDeleteShader (fragment_shader);
+    glDeleteProgram (self->program);
+    self->program = 0;
+
+    return;
+  }
+
+  glDetachShader (self->program, vertex_shader);
+  glDetachShader (self->program, fragment_shader);
 }
 
 void
 retro_glsl_filter_use_program (RetroGLSLFilter *self)
 {
   g_return_if_fail (RETRO_IS_GLSL_FILTER (self));
+  g_return_if_fail (self->program != 0);
 
   glUseProgram (self->program);
 }
@@ -285,6 +360,7 @@ retro_glsl_filter_set_attribute_pointer (RetroGLSLFilter *self,
   GLint location;
 
   g_return_if_fail (RETRO_IS_GLSL_FILTER (self));
+  g_return_if_fail (self->program != 0);
 
   location = glGetAttribLocation (self->program, name);
   glVertexAttribPointer (location, size, type, normalized, stride, pointer);
@@ -300,6 +376,7 @@ retro_glsl_filter_set_uniform_1f (RetroGLSLFilter *self,
   GLint location;
 
   g_return_if_fail (RETRO_IS_GLSL_FILTER (self));
+  g_return_if_fail (self->program != 0);
 
   location = glGetUniformLocation (self->program, name);
   glUniform1f (location, v0);
@@ -316,6 +393,7 @@ retro_glsl_filter_set_uniform_4f (RetroGLSLFilter *self,
   GLint location;
 
   g_return_if_fail (RETRO_IS_GLSL_FILTER (self));
+  g_return_if_fail (self->program != 0);
 
   location = glGetUniformLocation (self->program, name);
   glUniform4f (location, v0, v1, v2, v3);
diff --git a/retro-gtk/retro-glsl-filter.h b/retro-gtk/retro-glsl-filter.h
index a9d0e11..d468626 100644
--- a/retro-gtk/retro-glsl-filter.h
+++ b/retro-gtk/retro-glsl-filter.h
@@ -14,7 +14,8 @@ G_DECLARE_FINAL_TYPE (RetroGLSLFilter, retro_glsl_filter, RETRO, GLSL_FILTER, GO
 RetroGLSLFilter *retro_glsl_filter_new (const char  *uri,
                                         GError     **error);
 void retro_glsl_filter_apply_texture_params (RetroGLSLFilter *self);
-void retro_glsl_filter_prepare_program (RetroGLSLFilter *self);
+void retro_glsl_filter_prepare_program (RetroGLSLFilter  *self,
+                                        GError          **error);
 void retro_glsl_filter_use_program (RetroGLSLFilter *self);
 void retro_glsl_filter_set_attribute_pointer (RetroGLSLFilter *self,
                                               const gchar     *name,


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