[retro-gtk/wip/aplazas/gl-display] filter meta info definition
- From: Adrien Plazas <aplazas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [retro-gtk/wip/aplazas/gl-display] filter meta info definition
- Date: Wed, 15 Nov 2017 14:15:25 +0000 (UTC)
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]