From c47fa4dc62ec1f79e45dcb7b0073f838139fd477 Mon Sep 17 00:00:00 2001 From: Filippo Argiolas Date: Fri, 18 Jul 2008 10:49:34 +0200 Subject: [PATCH] [127/906] Imported GstGLShader from cvs branch. Added a demo laplacian convolution filter to demonstrate how this can be integrated with minimum effort. --- gst-libs/gst/gl/Makefile.am | 6 +- gst-libs/gst/gl/gstglshader.c | 497 ++++++++++++++++++++++++++++++++++ gst-libs/gst/gl/gstglshader.h | 94 +++++++ 3 files changed, 595 insertions(+), 2 deletions(-) create mode 100644 gst-libs/gst/gl/gstglshader.c create mode 100644 gst-libs/gst/gl/gstglshader.h diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index e896912770..aee4816f94 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -4,13 +4,15 @@ lib_LTLIBRARIES = libgstgl-@GST_MAJORMINOR@.la libgstgl_@GST_MAJORMINOR@_la_SOURCES = \ gstgldisplay.c \ gstglbuffer.c \ - gstglfilter.c + gstglfilter.c \ + gstglshader.c libgstgl_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/gl libgstgl_@GST_MAJORMINOR@include_HEADERS = \ gstgldisplay.h \ gstglbuffer.h \ - gstglfilter.h + gstglfilter.h \ + gstglshader.h libgstgl_@GST_MAJORMINOR@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ diff --git a/gst-libs/gst/gl/gstglshader.c b/gst-libs/gst/gl/gstglshader.c new file mode 100644 index 0000000000..e3917587f6 --- /dev/null +++ b/gst-libs/gst/gl/gstglshader.c @@ -0,0 +1,497 @@ +/* + * GStreamer + * Copyright (C) 2008 Filippo Argiolas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstglshader.h" + +#define GST_GL_SHADER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_SHADER, GstGLShaderPrivate)) + +enum +{ + PROP_0, + PROP_VERTEX_SRC, + PROP_FRAGMENT_SRC, + PROP_COMPILED, + PROP_ACTIVE //unused +}; + +struct _GstGLShaderPrivate +{ + gchar *vertex_src; + gchar *fragment_src; + + GLhandleARB vertex_handle; + GLhandleARB fragment_handle; + GLhandleARB program_handle; + + gboolean compiled; + gboolean active; +}; + +G_DEFINE_TYPE (GstGLShader, gst_gl_shader, G_TYPE_OBJECT); + +static void +gst_gl_shader_finalize (GObject * object) +{ + GstGLShader *shader; + GstGLShaderPrivate *priv; +/* GLint status = GL_FALSE; */ + + shader = GST_GL_SHADER (object); + priv = shader->priv; + + g_free (priv->vertex_src); + g_free (priv->fragment_src); + + /* release shader objects */ + gst_gl_shader_release (shader); + + /* delete program */ + if (priv->program_handle) { + glDeleteObjectARB (priv->program_handle); + glGetError (); + /* g_debug ("error: 0x%x", err); */ + /* glGetObjectParameterivARB(priv->program_handle, GL_OBJECT_DELETE_STATUS_ARB, &status); */ + /* g_debug ("program deletion status:%s", status == GL_TRUE ? "true" : "false" ); */ + } + + priv->fragment_handle = 0; + priv->vertex_handle = 0; + priv->program_handle = 0; + + G_OBJECT_CLASS (gst_gl_shader_parent_class)->finalize (object); +} + +static void +gst_gl_shader_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstGLShader *shader = GST_GL_SHADER (object); + + switch (prop_id) { + case PROP_VERTEX_SRC: + gst_gl_shader_set_vertex_source (shader, g_value_get_string (value)); + break; + case PROP_FRAGMENT_SRC: + gst_gl_shader_set_fragment_source (shader, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gl_shader_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstGLShader *shader = GST_GL_SHADER (object); + GstGLShaderPrivate *priv = shader->priv; + + switch (prop_id) { + case PROP_VERTEX_SRC: + g_value_set_string (value, priv->vertex_src); + break; + case PROP_FRAGMENT_SRC: + g_value_set_string (value, priv->fragment_src); + break; + case PROP_COMPILED: + g_value_set_boolean (value, priv->compiled); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +gst_gl_shader_class_init (GstGLShaderClass * klass) +{ + /* bind class methods .. */ + GObjectClass *obj_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GstGLShaderPrivate)); + + obj_class->finalize = gst_gl_shader_finalize; + obj_class->set_property = gst_gl_shader_set_property; + obj_class->get_property = gst_gl_shader_get_property; + + /* .. and install properties */ + + g_object_class_install_property (obj_class, + PROP_VERTEX_SRC, + g_param_spec_string ("vertex-src", + "Vertex Source", + "GLSL Vertex Shader source code", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (obj_class, + PROP_FRAGMENT_SRC, + g_param_spec_string ("fragment-src", + "Fragment Source", + "GLSL Fragment Shader source code", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (obj_class, + PROP_ACTIVE, + g_param_spec_string ("active", + "Active", "Enable/Disable the shader", NULL, G_PARAM_READWRITE)); + g_object_class_install_property (obj_class, + PROP_COMPILED, + g_param_spec_boolean ("compiled", + "Compiled", + "Shader compile and link status", FALSE, G_PARAM_READABLE)); +} + +void +gst_gl_shader_set_vertex_source (GstGLShader * shader, const gchar * src) +{ + GstGLShaderPrivate *priv; + + g_return_if_fail (GST_GL_IS_SHADER (shader)); + g_return_if_fail (src != NULL); + + priv = shader->priv; + + if (gst_gl_shader_is_compiled (shader)) + gst_gl_shader_release (shader); + + g_free (priv->vertex_src); + + priv->vertex_src = g_strdup (src); +} + +void +gst_gl_shader_set_fragment_source (GstGLShader * shader, const gchar * src) +{ + GstGLShaderPrivate *priv; + + g_return_if_fail (GST_GL_IS_SHADER (shader)); + g_return_if_fail (src != NULL); + + priv = shader->priv; + + if (gst_gl_shader_is_compiled (shader)) + gst_gl_shader_release (shader); + + g_free (priv->fragment_src); + + priv->fragment_src = g_strdup (src); +} + +G_CONST_RETURN gchar * +gst_gl_shader_get_vertex_source (GstGLShader * shader) +{ + g_return_val_if_fail (GST_GL_IS_SHADER (shader), NULL); + return shader->priv->vertex_src; +} + +G_CONST_RETURN gchar * +gst_gl_shader_get_fragment_source (GstGLShader * shader) +{ + g_return_val_if_fail (GST_GL_IS_SHADER (shader), NULL); + return shader->priv->fragment_src; +} + +static void +gst_gl_shader_init (GstGLShader * self) +{ + /* initialize sources and create program object */ + GstGLShaderPrivate *priv; + + priv = self->priv = GST_GL_SHADER_GET_PRIVATE (self); + + priv->vertex_src = NULL; + priv->fragment_src = NULL; + + priv->fragment_handle = 0; + priv->vertex_handle = 0; + priv->program_handle = glCreateProgramObjectARB (); + + g_assert (priv->program_handle); + + priv->compiled = FALSE; + priv->active = FALSE; // unused at the moment +} + +GstGLShader * +gst_gl_shader_new (void) +{ + return g_object_new (GST_GL_TYPE_SHADER, NULL); +} + +gboolean +gst_gl_shader_is_compiled (GstGLShader * shader) +{ + g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE); + + return shader->priv->compiled; +} + +gboolean +gst_gl_shader_compile (GstGLShader * shader, GError ** error) +{ + GstGLShaderPrivate *priv; + + gchar info_buffer[2048]; + GLsizei len = 0; + GLint status = GL_FALSE; + + g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE); + + priv = shader->priv; + + if (priv->compiled) + return priv->compiled; + + g_assert (priv->program_handle); + + if (priv->vertex_src) { + /* create vertex object */ + const gchar *vertex_source = priv->vertex_src; + priv->vertex_handle = glCreateShaderObjectARB (GL_VERTEX_SHADER); + glShaderSourceARB (priv->vertex_handle, 1, &vertex_source, NULL); + /* compile */ + glCompileShaderARB (priv->vertex_handle); + /* check everything is ok */ + glGetObjectParameterivARB (priv->vertex_handle, + GL_OBJECT_COMPILE_STATUS_ARB, &status); + + glGetInfoLogARB (priv->vertex_handle, + sizeof (info_buffer) - 1, &len, info_buffer); + info_buffer[len] = '\0'; + + if (status != GL_TRUE) { + g_set_error (error, GST_GL_SHADER_ERROR, + GST_GL_SHADER_ERROR_COMPILE, + "Vertex Shader compilation failed:\n%s", info_buffer); + + glDeleteObjectARB (priv->vertex_handle); + priv->compiled = FALSE; + return priv->compiled; + } else if (len > 1) { + g_debug ("\n%s\n", info_buffer); + } + glAttachObjectARB (priv->program_handle, priv->vertex_handle); + } + + if (priv->fragment_src) { + /* create fragment object */ + const gchar *fragment_source = priv->fragment_src; + priv->fragment_handle = glCreateShaderObjectARB (GL_FRAGMENT_SHADER_ARB); + glShaderSourceARB (priv->fragment_handle, 1, &fragment_source, NULL); + /* compile */ + glCompileShaderARB (priv->fragment_handle); + /* check everything is ok */ + glGetObjectParameterivARB (priv->fragment_handle, + GL_OBJECT_COMPILE_STATUS_ARB, &status); + + glGetInfoLogARB (priv->fragment_handle, + sizeof (info_buffer) - 1, &len, info_buffer); + info_buffer[len] = '\0'; + if (status != GL_TRUE) { + g_set_error (error, GST_GL_SHADER_ERROR, + GST_GL_SHADER_ERROR_COMPILE, + "Fragment Shader compilation failed:\n%s", info_buffer); + + glDeleteObjectARB (priv->fragment_handle); + priv->compiled = FALSE; + return priv->compiled; + } else if (len > 1) { + g_debug ("\n%s\n", info_buffer); + } + glAttachObjectARB (priv->program_handle, priv->fragment_handle); + } + + /* if nothing failed link shaders */ + glLinkProgramARB (priv->program_handle); + + glGetObjectParameterivARB (priv->program_handle, GL_LINK_STATUS, &status); + + glGetInfoLogARB (priv->program_handle, + sizeof (info_buffer) - 1, &len, info_buffer); + info_buffer[len] = '\0'; + + if (status != GL_TRUE) { + g_set_error (error, GST_GL_SHADER_ERROR, + GST_GL_SHADER_ERROR_LINK, "Shader Linking failed:\n%s", info_buffer); + priv->compiled = FALSE; + return priv->compiled; + } else if (len > 1) { + g_debug ("\n%s\n", info_buffer); + } + /* success! */ + priv->compiled = TRUE; + g_object_notify (G_OBJECT (shader), "compiled"); + + return priv->compiled; +} + +void +gst_gl_shader_release (GstGLShader * shader) +{ + GstGLShaderPrivate *priv; + /* GLint status; */ + /* GLenum err = 0; */ + + g_return_if_fail (GST_GL_IS_SHADER (shader)); + + priv = shader->priv; + + g_assert (priv->program_handle); + + if (!priv->compiled) + return; + + if (priv->vertex_handle) { // not needed but nvidia doesn't care to respect the spec + glDeleteObjectARB (priv->vertex_handle); + + /* err = glGetError (); */ + /* g_debug ("error: 0x%x", err); */ + /* glGetObjectParameterivARB(priv->vertex_handle, GL_OBJECT_DELETE_STATUS_ARB, &status); */ + /* g_debug ("vertex deletion status:%s", status == GL_TRUE ? "true" : "false" ); */ + } + + if (priv->fragment_handle) { + glDeleteObjectARB (priv->fragment_handle); + + /* err = glGetError (); */ + /* g_debug ("error: 0x%x", err); */ + /* glGetObjectParameterivARB(priv->fragment_handle, GL_OBJECT_DELETE_STATUS_ARB, &status); */ + /* g_debug ("fragment deletion status:%s", status == GL_TRUE ? "true" : "false" ); */ + } + + if (priv->vertex_handle) + glDetachObjectARB (priv->program_handle, priv->vertex_handle); + if (priv->fragment_handle) + glDetachObjectARB (priv->program_handle, priv->fragment_handle); + + priv->compiled = FALSE; + g_object_notify (G_OBJECT (shader), "compiled"); +} + +void +gst_gl_shader_use (GstGLShader * shader) +{ + GstGLShaderPrivate *priv; + + if (!shader) { + glUseProgramObjectARB (0); + return; + } + + priv = shader->priv; + + g_assert (priv->program_handle); + + glUseProgramObjectARB (priv->program_handle); + + return; +} + +gboolean +gst_gl_shader_compile_and_check (GstGLShader * shader, + const gchar * source, GstGLShaderSourceType type) +{ + gboolean is_compiled = FALSE; + + g_object_get (G_OBJECT (shader), "compiled", &is_compiled, NULL); + + if (!is_compiled) { + GError *error = NULL; + + switch (type) { + case GST_GL_SHADER_FRAGMENT_SOURCE: + gst_gl_shader_set_fragment_source (shader, source); + break; + case GST_GL_SHADER_VERTEX_SOURCE: + gst_gl_shader_set_vertex_source (shader, source); + break; + default: + g_assert_not_reached (); + break; + } + + gst_gl_shader_compile (shader, &error); + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + return FALSE; + } + } + return TRUE; +} + +void +gst_gl_shader_set_uniform_1f (GstGLShader * shader, const gchar * name, + gfloat value) +{ + GstGLShaderPrivate *priv; + GLint location = -1; + + priv = shader->priv; + + g_return_if_fail (priv->program_handle != 0); + + location = glGetUniformLocationARB (priv->program_handle, name); + + glUniform1fARB (location, value); +} + +void +gst_gl_shader_set_uniform_1fv (GstGLShader * shader, const gchar * name, + guint count, gfloat * value) +{ + GstGLShaderPrivate *priv; + GLint location = -1; + + priv = shader->priv; + + g_return_if_fail (priv->program_handle != 0); + + location = glGetUniformLocationARB (priv->program_handle, name); + + glUniform1fvARB (location, count, value); +} + +void +gst_gl_shader_set_uniform_1i (GstGLShader * shader, const gchar * name, + gint value) +{ + GstGLShaderPrivate *priv; + GLint location = -1; + + priv = shader->priv; + + g_return_if_fail (priv->program_handle != 0); + + location = glGetUniformLocationARB (priv->program_handle, name); + + glUniform1iARB (location, value); +} + +GQuark +gst_gl_shader_error_quark (void) +{ + return g_quark_from_static_string ("gst-gl-shader-error"); +} diff --git a/gst-libs/gst/gl/gstglshader.h b/gst-libs/gst/gl/gstglshader.h new file mode 100644 index 0000000000..53a71ddcf8 --- /dev/null +++ b/gst-libs/gst/gl/gstglshader.h @@ -0,0 +1,94 @@ +/* + * GStreamer + * Copyright (C) 2008 Filippo Argiolas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_GL_SHADER_H__ +#define __GST_GL_SHADER_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_GL_TYPE_SHADER (gst_gl_shader_get_type()) +#define GST_GL_SHADER(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_SHADER, GstGLShader)) +#define GST_GL_SHADER_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_SHADER, GstGLShaderClass)) +#define GST_GL_IS_SHADER(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_SHADER)) +#define GST_GL_IS_SHADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_SHADER)) +#define GST_GL_SHADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_SHADER, GstGLShaderClass)) + +#define GST_GL_SHADER_ERROR (gst_gl_shader_error_quark ()) + +typedef enum { + GST_GL_SHADER_ERROR_COMPILE, + GST_GL_SHADER_ERROR_LINK, + GST_GL_SHADER_ERROR_PROGRAM +} GstGLShaderError; + +typedef enum { + GST_GL_SHADER_FRAGMENT_SOURCE, + GST_GL_SHADER_VERTEX_SOURCE +} GstGLShaderSourceType; + +typedef struct _GstGLShader GstGLShader; +typedef struct _GstGLShaderPrivate GstGLShaderPrivate; +typedef struct _GstGLShaderClass GstGLShaderClass; + +struct _GstGLShader { + /*< private >*/ + GObject parent; + GstGLShaderPrivate *priv; +}; + +struct _GstGLShaderClass { + /*< private >*/ + GObjectClass parent_class; +}; + +/* methods */ + +GQuark gst_gl_shader_error_quark (void); +GType gst_gl_shader_get_type (void); + +GstGLShader * gst_gl_shader_new (void); + +void gst_gl_shader_set_vertex_source (GstGLShader *shader, + const gchar *src); +void gst_gl_shader_set_fragment_source (GstGLShader *shader, + const gchar *src); +G_CONST_RETURN gchar * gst_gl_shader_get_vertex_source (GstGLShader *shader); +G_CONST_RETURN gchar * gst_gl_shader_get_fragment_source (GstGLShader *shader); + +void gst_gl_shader_set_active (GstGLShader *shader, + gboolean active); + +gboolean gst_gl_shader_is_compiled (GstGLShader *shader); + +gboolean gst_gl_shader_compile (GstGLShader *shader, GError **error); +gboolean gst_gl_shader_compile_and_check (GstGLShader *shader, const gchar *source, GstGLShaderSourceType type); +void gst_gl_shader_release (GstGLShader *shader); +void gst_gl_shader_use (GstGLShader *shader); + +void gst_gl_shader_set_uniform_1i (GstGLShader *shader, const gchar *name, gint value); +void gst_gl_shader_set_uniform_1f (GstGLShader *shader, const gchar *name, gfloat value); +void gst_gl_shader_set_uniform_1fv (GstGLShader *shader, const gchar *name, guint count, gfloat * value); + +G_END_DECLS + +#endif /* __GST_GL_SHADER_H__ */