[retro-gtk/wip/aplazas/gl-display] filter meta info definition



commit 67abe4409838c59f5783041b9d15d782a68b7d19
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Wed Nov 15 11:27:13 2017 +0100

    filter meta info definition

 retro-gtk/glsl-filters/bicubic.filter |    1 +
 retro-gtk/glsl-filters/sharp.filter   |    7 +
 retro-gtk/meson.build                 |    1 +
 retro-gtk/retro-gl-display.c          |   64 ++------
 retro-gtk/retro-glsl-filter.c         |  272 +++++++++++++++++++++++++++++++++
 retro-gtk/retro-glsl-filter.h         |   22 +++
 6 files changed, 317 insertions(+), 50 deletions(-)
---
diff --git a/retro-gtk/glsl-filters/bicubic.filter b/retro-gtk/glsl-filters/bicubic.filter
index 5ace147..4d8ccd4 100644
--- a/retro-gtk/glsl-filters/bicubic.filter
+++ b/retro-gtk/glsl-filters/bicubic.filter
@@ -1,4 +1,5 @@
 [GLSL Filter]
+Vertex=sharp.vs
 Fragment=bicubic.fs
 Authors=hunterk;
 License=GPL-2.0+;
diff --git a/retro-gtk/glsl-filters/sharp.filter b/retro-gtk/glsl-filters/sharp.filter
new file mode 100644
index 0000000..cb22335
--- /dev/null
+++ b/retro-gtk/glsl-filters/sharp.filter
@@ -0,0 +1,7 @@
+[GLSL Filter]
+Filter=Nearest
+Wrap=Border
+Vertex=sharp.vs
+Fragment=sharp.fs
+Authors=Adrien Plazas;
+License=GPL-3.0+;
diff --git a/retro-gtk/meson.build b/retro-gtk/meson.build
index 9626675..00e9486 100644
--- a/retro-gtk/meson.build
+++ b/retro-gtk/meson.build
@@ -23,6 +23,7 @@ retro_gtk_sources = [
   'retro-environment.c',
   'retro-game-info.c',
   'retro-gl-display.c',
+  'retro-glsl-filter.c',
   'retro-input.c',
   'retro-input-descriptor.c',
   'retro-keyboard-key.c',
diff --git a/retro-gtk/retro-gl-display.c b/retro-gtk/retro-gl-display.c
index 6ad70f8..19ddcee 100644
--- a/retro-gtk/retro-gl-display.c
+++ b/retro-gtk/retro-gl-display.c
@@ -3,6 +3,7 @@
 #include "retro-gl-display.h"
 
 #include <epoxy/gl.h>
+#include "retro-glsl-filter.h"
 #include "retro-pixdata.h"
 
 struct _RetroGLDisplay
@@ -14,6 +15,7 @@ struct _RetroGLDisplay
   gfloat aspect_ratio;
   gulong on_video_output_id;
 
+  RetroGLSLFilter *glsl_filter;
   GLuint shader_program;
   GLuint texture;
 };
@@ -90,36 +92,13 @@ static GLuint elements[] = {
     2, 3, 0,
 };
 
-static GLuint
-create_shader_from_resource (GLenum                 shader_type,
-                             const char            *path,
-                             GResourceLookupFlags   lookup_flags,
-                             GError               **error)
-{
-  GBytes *source_bytes;
-  const gchar *source;
-  GLuint shader;
-
-  // TODO Handle the error properly.
-  source_bytes = g_resources_lookup_data (path, lookup_flags, error);
-  source = g_bytes_get_data (source_bytes, NULL);
-  shader = glCreateShader (shader_type);
-  glShaderSource (shader, 1, &source, NULL);
-  glCompileShader (shader);
-  g_bytes_unref (source_bytes);
-
-  return shader;
-}
-
 static void
 retro_gl_display_realize (RetroGLDisplay *self)
 {
   GLuint vertex_buffer_object;
   GLuint vertex_array_object;
   GLuint element_buffer_object;
-  GLuint vertex_shader;
-  GLuint fragment_shader;
-  GLuint shader_program;
+  GLuint program;
 
   gtk_gl_area_make_current (GTK_GL_AREA (self));
 
@@ -134,31 +113,16 @@ retro_gl_display_realize (RetroGLDisplay *self)
   glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, element_buffer_object);
   glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (elements), elements, GL_STATIC_DRAW);
 
-  vertex_shader =
-    create_shader_from_resource (GL_VERTEX_SHADER,
-                                 "/org/gnome/Retro/glsl-filters/crt-simple.vs",
-                                 0,
-                                 NULL);
-
-  fragment_shader =
-    create_shader_from_resource (GL_FRAGMENT_SHADER,
-                                 "/org/gnome/Retro/glsl-filters/crt-simple.fs",
-                                 0,
-                                 NULL);
-
-  // Prepare the shader program
-  shader_program = glCreateProgram();
-  glAttachShader (shader_program, vertex_shader);
-  glAttachShader (shader_program, fragment_shader);
-  glLinkProgram (shader_program);
-
-  glUseProgram (shader_program);
-  GLint position_attrib = glGetAttribLocation (shader_program, "position");
+  self->glsl_filter = retro_glsl_filter_new ("resource:///org/gnome/Retro/glsl-filters/crt-simple.filter", 
NULL);
+  program = retro_glsl_filter_create_program (self->glsl_filter);
+
+  glUseProgram (program);
+  GLint position_attrib = glGetAttribLocation (program, "position");
   glVertexAttribPointer (position_attrib, sizeof (((RetroVertex *) NULL)->position) / sizeof (float), 
GL_FLOAT, GL_FALSE,
                          sizeof (RetroVertex), offsetof (RetroVertex, position));
   glEnableVertexAttribArray (position_attrib);
 
-  GLint texture_coordinates_attrib = glGetAttribLocation (shader_program, "texCoord");
+  GLint texture_coordinates_attrib = glGetAttribLocation (program, "texCoord");
   glVertexAttribPointer (texture_coordinates_attrib, sizeof (((RetroVertex *) NULL)->texture_coordinates) / 
sizeof (float), GL_FLOAT, GL_FALSE,
                          sizeof (RetroVertex), offsetof (RetroVertex, texture_coordinates));
   glEnableVertexAttribArray (texture_coordinates_attrib);
@@ -166,7 +130,7 @@ retro_gl_display_realize (RetroGLDisplay *self)
   glGenTextures (1, &self->texture);
   glBindTexture (GL_TEXTURE_2D, self->texture);
 
-  self->shader_program = shader_program;
+  self->shader_program = program;
 }
 
 static void
@@ -238,10 +202,8 @@ retro_gl_display_render (RetroGLDisplay *self)
                 GL_RGBA, GL_UNSIGNED_BYTE,
                 gdk_pixbuf_get_pixels (self->pixbuf));
 
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+  if (self->glsl_filter != NULL)
+    retro_glsl_filter_apply_texture_params (self->glsl_filter);
 
   relative_aspect_ratio = glGetUniformLocation (self->shader_program, "relative_aspect_ratio");
   glUniform1f (relative_aspect_ratio,
@@ -286,6 +248,8 @@ retro_gl_display_finalize (GObject *object)
     g_object_unref (self->core);
   if (self->pixbuf != NULL)
     g_object_unref (self->pixbuf);
+  if (self->glsl_filter != NULL)
+    g_object_unref (self->glsl_filter);
 
   G_OBJECT_CLASS (retro_gl_display_parent_class)->finalize (object);
 }
diff --git a/retro-gtk/retro-glsl-filter.c b/retro-gtk/retro-glsl-filter.c
new file mode 100644
index 0000000..5a18735
--- /dev/null
+++ b/retro-gtk/retro-glsl-filter.c
@@ -0,0 +1,272 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#include "retro-glsl-filter.h"
+
+struct _RetroGLSLFilter
+{
+  GObject parent_instance;
+  GBytes *vertex;
+  GBytes *fragment;
+  GLenum wrap;
+  GLenum filter;
+};
+
+G_DEFINE_TYPE (RetroGLSLFilter, retro_glsl_filter, G_TYPE_OBJECT)
+
+#define GLSL_FILTER_GROUP "GLSL Filter"
+
+static const gchar *
+g_key_file_try_get_string (GKeyFile    *key_file,
+                           const gchar *group,
+                           const gchar *key)
+{
+  const gchar *value;
+  GError *inner_error = NULL;
+
+  value = g_key_file_get_string (key_file, group, key, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_debug ("%s", inner_error->message);
+    g_clear_error (&inner_error);
+
+    return NULL;
+  }
+
+  return value;
+}
+
+static GBytes *
+g_file_try_read_bytes (GFile *file)
+{
+  GFileInputStream *stream;
+  goffset size;
+  GBytes *bytes;
+  GError *inner_error = NULL;
+
+  stream = g_file_read (file, NULL, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_debug ("%s", inner_error->message);
+    g_clear_error (&inner_error);
+
+    return NULL;
+  }
+
+  g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_END, NULL, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_debug ("%s", inner_error->message);
+    g_clear_error (&inner_error);
+    g_object_unref (stream);
+
+    return NULL;
+  }
+
+  size = g_seekable_tell (G_SEEKABLE (stream));
+
+  g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_debug ("%s", inner_error->message);
+    g_clear_error (&inner_error);
+    g_object_unref (stream);
+
+    return NULL;
+  }
+
+  bytes = g_input_stream_read_bytes (G_INPUT_STREAM (stream), size, NULL, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_debug ("%s", inner_error->message);
+    g_clear_error (&inner_error);
+    g_object_unref (stream);
+
+    return NULL;
+  }
+
+  g_object_unref (stream);
+
+  return bytes;
+}
+
+static GBytes *
+g_key_file_try_read_child_bytes (GKeyFile    *key_file,
+                                 const gchar *group,
+                                 const gchar *key,
+                                 GFile       *parent)
+{
+  const gchar *value;
+  GFile *file;
+  GBytes *bytes;
+
+  value = g_key_file_try_get_string (key_file, group, key);
+  if (value == NULL)
+    return NULL;
+
+  file = g_file_get_child (parent, value);
+  bytes = g_file_try_read_bytes (file);
+  g_object_unref (file);
+
+  return bytes;
+}
+
+RetroGLSLFilter *
+retro_glsl_filter_new (const char  *uri,
+                       GError     **error)
+{
+  RetroGLSLFilter *self;
+  GKeyFile *key_file;
+  GFile *file;
+  GFile *parent;
+  GFileInputStream *stream;
+  GBytes *bytes;
+  const gchar *value;
+  GError *inner_error = NULL;
+
+  g_return_val_if_fail (uri != NULL, NULL);
+
+  file = g_file_new_for_uri (uri);
+  stream = g_file_read (file, NULL, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_propagate_error (error, inner_error);
+    g_object_unref (file);
+
+    return NULL;
+  }
+
+  bytes = g_input_stream_read_bytes (G_INPUT_STREAM (stream), 4096, NULL, error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_propagate_error (error, inner_error);
+    g_object_unref (file);
+    g_object_unref (stream);
+
+    return NULL;
+  }
+
+  g_object_unref (stream);
+
+  key_file = g_key_file_new ();
+  g_key_file_load_from_bytes (key_file, bytes, G_KEY_FILE_NONE, &inner_error);
+  if (G_UNLIKELY (inner_error != NULL)) {
+    g_propagate_error (error, inner_error);
+    g_object_unref (file);
+    g_bytes_unref (bytes);
+    g_key_file_unref (key_file);
+
+    return NULL;
+  }
+
+  g_bytes_unref (bytes);
+
+  self = g_object_new (RETRO_TYPE_GLSL_FILTER, NULL);
+
+  value = g_key_file_try_get_string (key_file, GLSL_FILTER_GROUP, "Filter");
+  if (g_strcmp0 (value, "Linear") == 0)
+    self->filter = GL_LINEAR;
+  else if (g_strcmp0 (value, "Nearest") == 0)
+    self->filter = GL_NEAREST;
+  else
+    self->filter = GL_LINEAR;
+
+  value = g_key_file_try_get_string (key_file, GLSL_FILTER_GROUP, "Wrap");
+  if (g_strcmp0 (value, "Border") == 0)
+    self->wrap = GL_CLAMP_TO_BORDER;
+  else if (g_strcmp0 (value, "Edge") == 0)
+    self->wrap = GL_CLAMP_TO_EDGE;
+  else
+    self->wrap = GL_CLAMP_TO_BORDER;
+
+  parent = g_file_get_parent (file);
+  g_object_unref (file);
+
+  self->vertex = g_key_file_try_read_child_bytes (key_file,
+                                                  GLSL_FILTER_GROUP,
+                                                  "Vertex",
+                                                  parent);
+
+  self->fragment = g_key_file_try_read_child_bytes (key_file,
+                                                    GLSL_FILTER_GROUP,
+                                                    "Fragment",
+                                                    parent);
+
+  g_object_unref (parent);
+  g_key_file_unref (key_file);
+
+  return self;
+}
+
+static void
+retro_glsl_filter_finalize (GObject *object)
+{
+  RetroGLSLFilter *self = (RetroGLSLFilter *) object;
+
+  if (self->vertex != NULL)
+    g_bytes_unref (self->vertex);
+  if (self->fragment != NULL)
+    g_bytes_unref (self->fragment);
+
+  G_OBJECT_CLASS (retro_glsl_filter_parent_class)->finalize (object);
+}
+
+static void
+retro_glsl_filter_class_init (RetroGLSLFilterClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = retro_glsl_filter_finalize;
+}
+
+static void
+retro_glsl_filter_init (RetroGLSLFilter *self)
+{
+}
+
+void
+retro_glsl_filter_apply_texture_params (RetroGLSLFilter *self)
+{
+  g_return_if_fail (RETRO_IS_GLSL_FILTER (self));
+
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, self->wrap);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, self->wrap);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, self->filter);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, self->filter);
+}
+
+static GLuint
+create_shader (GBytes *source_bytes,
+               GLenum  shader_type)
+{
+  const gchar *source;
+  GLuint shader;
+
+  source = g_bytes_get_data (source_bytes, NULL);
+  shader = glCreateShader (shader_type);
+  glShaderSource (shader, 1, &source, NULL);
+  glCompileShader (shader);
+
+  return shader;
+}
+
+static void
+try_create_and_attach_shader (GLuint  program,
+                              GBytes *source_bytes,
+                              GLenum  shader_type)
+{
+  GLuint shader;
+
+  if (source_bytes == NULL)
+    return;
+
+  shader = create_shader (source_bytes, shader_type);
+  glAttachShader (program, shader);
+}
+
+GLuint
+retro_glsl_filter_create_program (RetroGLSLFilter *self)
+{
+  GLuint program;
+
+  g_return_val_if_fail (RETRO_IS_GLSL_FILTER (self), 0);
+
+  program = glCreateProgram();
+  try_create_and_attach_shader (program, self->vertex, GL_VERTEX_SHADER);
+  try_create_and_attach_shader (program, self->fragment, GL_FRAGMENT_SHADER);
+  glLinkProgram (program);
+
+  return program;
+}
diff --git a/retro-gtk/retro-glsl-filter.h b/retro-gtk/retro-glsl-filter.h
new file mode 100644
index 0000000..7e5d94e
--- /dev/null
+++ b/retro-gtk/retro-glsl-filter.h
@@ -0,0 +1,22 @@
+#ifndef RETRO_GLSL_FILTER_H
+#define RETRO_GLSL_FILTER_H
+
+#include <epoxy/gl.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define RETRO_TYPE_GLSL_FILTER (retro_glsl_filter_get_type())
+
+G_DECLARE_FINAL_TYPE (RetroGLSLFilter, retro_glsl_filter, RETRO, GLSL_FILTER, GObject)
+
+RetroGLSLFilter *retro_glsl_filter_new (const char  *uri,
+                                        GError     **error);
+void retro_glsl_filter_apply_texture_params (RetroGLSLFilter *self);
+GLuint retro_glsl_filter_create_program (RetroGLSLFilter *self);
+
+G_END_DECLS
+
+#endif /* RETRO_GLSL_FILTER_H */
+


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