From c766ca0381277f3797b9702d24879269972d9336 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 21 Oct 2015 03:23:30 +1100 Subject: [PATCH] glshaderelement: implement setting arbitrary uniforms Currently float and int are supported by default. vec2, vec3, vec4 and mat4 are supported if graphene is used. Of course if one wants to set custom uniforms they can also be set using the create-shader signal. --- ext/gl/gstglfiltershader.c | 93 ++++++++++++++++++++++++++++++++++++++ ext/gl/gstglfiltershader.h | 1 + 2 files changed, 94 insertions(+) diff --git a/ext/gl/gstglfiltershader.c b/ext/gl/gstglfiltershader.c index bde6630832..f8643e73d5 100644 --- a/ext/gl/gstglfiltershader.c +++ b/ext/gl/gstglfiltershader.c @@ -40,6 +40,9 @@ #include #include "gstglfiltershader.h" +#if HAVE_GRAPHENE +#include +#endif enum { @@ -47,6 +50,7 @@ enum PROP_SHADER, PROP_VERTEX, PROP_FRAGMENT, + PROP_UNIFORMS, PROP_UPDATE_SHADER, PROP_LAST, }; @@ -112,6 +116,11 @@ gst_gl_filtershader_class_init (GstGLFilterShaderClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /* FIXME: add other stages */ + g_object_class_install_property (gobject_class, PROP_UNIFORMS, + g_param_spec_boxed ("uniforms", "GLSL Uniforms", + "GLSL Uniforms", GST_TYPE_STRUCTURE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_UPDATE_SHADER, g_param_spec_boolean ("update-shader", "Update Shader", "Emit the \'create-shader\' signal for the next frame", @@ -154,6 +163,12 @@ gst_gl_filtershader_init (GstGLFilterShader * filtershader) static void gst_gl_filtershader_finalize (GObject * object) { + GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object); + + if (filtershader->uniforms) + gst_structure_free (filtershader->uniforms); + filtershader->uniforms = NULL; + G_OBJECT_CLASS (gst_gl_filtershader_parent_class)->finalize (object); } @@ -187,6 +202,14 @@ gst_gl_filtershader_set_property (GObject * object, guint prop_id, filtershader->new_source = TRUE; GST_OBJECT_UNLOCK (filtershader); break; + case PROP_UNIFORMS: + GST_OBJECT_LOCK (filtershader); + if (filtershader->uniforms) + gst_structure_free (filtershader->uniforms); + filtershader->uniforms = g_value_dup_boxed (value); + filtershader->new_uniforms = TRUE; + GST_OBJECT_UNLOCK (filtershader); + break; case PROP_UPDATE_SHADER: GST_OBJECT_LOCK (filtershader); filtershader->update_shader = g_value_get_boolean (value); @@ -220,6 +243,11 @@ gst_gl_filtershader_get_property (GObject * object, guint prop_id, g_value_set_string (value, filtershader->fragment); GST_OBJECT_UNLOCK (filtershader); break; + case PROP_UNIFORMS: + GST_OBJECT_LOCK (filtershader); + g_value_set_boxed (value, filtershader->uniforms); + GST_OBJECT_UNLOCK (filtershader); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -296,6 +324,65 @@ gst_gl_filtershader_filter_texture (GstGLFilter * filter, guint in_tex, return TRUE; } +static gboolean +_set_uniform (GQuark field_id, const GValue * value, gpointer user_data) +{ + GstGLShader *shader = user_data; + const gchar *field_name = g_quark_to_string (field_id); + + if (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_INT)) { + gst_gl_shader_set_uniform_1i (shader, field_name, g_value_get_int (value)); + } else if (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLOAT)) { + gst_gl_shader_set_uniform_1f (shader, field_name, + g_value_get_float (value)); +#if HAVE_GRAPHENE + } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC2)) { + graphene_vec2_t *vec2 = g_value_get_boxed (value); + float x = graphene_vec2_get_x (vec2); + float y = graphene_vec2_get_y (vec2); + gst_gl_shader_set_uniform_2f (shader, field_name, x, y); + } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC3)) { + graphene_vec3_t *vec3 = g_value_get_boxed (value); + float x = graphene_vec3_get_x (vec3); + float y = graphene_vec3_get_y (vec3); + float z = graphene_vec3_get_z (vec3); + gst_gl_shader_set_uniform_3f (shader, field_name, x, y, z); + } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC4)) { + graphene_vec4_t *vec4 = g_value_get_boxed (value); + float x = graphene_vec4_get_x (vec4); + float y = graphene_vec4_get_y (vec4); + float z = graphene_vec4_get_z (vec4); + float w = graphene_vec4_get_w (vec4); + gst_gl_shader_set_uniform_4f (shader, field_name, x, y, z, w); + } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_MATRIX)) { + graphene_matrix_t *matrix = g_value_get_boxed (value); + float matrix_f[16]; + graphene_matrix_to_float (matrix, matrix_f); + gst_gl_shader_set_uniform_matrix_4fv (shader, field_name, 1, FALSE, + matrix_f); +#endif + } else { + /* FIXME: Add support for unsigned ints, non 4x4 matrices, etc */ + GST_FIXME ("Don't know how to set the \'%s\' paramater. Unknown type", + field_name); + return TRUE; + } + + return TRUE; +} + +static void +_update_uniforms (GstGLFilterShader * filtershader) +{ + if (filtershader->new_uniforms && filtershader->uniforms) { + gst_gl_shader_use (filtershader->shader); + + gst_structure_foreach (filtershader->uniforms, + (GstStructureForeachFunc) _set_uniform, filtershader->shader); + filtershader->new_uniforms = FALSE; + } +} + static GstGLShader * _maybe_recompile_shader (GstGLFilterShader * filtershader) { @@ -317,6 +404,8 @@ _maybe_recompile_shader (GstGLFilterShader * filtershader) gst_object_unref (filtershader->shader); filtershader->new_source = FALSE; filtershader->shader = gst_object_ref (shader); + filtershader->new_uniforms = TRUE; + _update_uniforms (filtershader); GST_OBJECT_UNLOCK (filtershader); return shader; } @@ -324,6 +413,7 @@ _maybe_recompile_shader (GstGLFilterShader * filtershader) if (filtershader->shader) { shader = gst_object_ref (filtershader->shader); + _update_uniforms (filtershader); GST_OBJECT_UNLOCK (filtershader); return shader; } @@ -374,10 +464,13 @@ _maybe_recompile_shader (GstGLFilterShader * filtershader) gst_object_unref (filtershader->shader); filtershader->shader = gst_object_ref (shader); filtershader->new_source = FALSE; + filtershader->new_uniforms = TRUE; + _update_uniforms (filtershader); GST_OBJECT_UNLOCK (filtershader); return shader; } else if (filtershader->shader) { + _update_uniforms (filtershader); shader = gst_object_ref (filtershader->shader); GST_OBJECT_UNLOCK (filtershader); return shader; diff --git a/ext/gl/gstglfiltershader.h b/ext/gl/gstglfiltershader.h index ccddf34c58..adf14109cf 100644 --- a/ext/gl/gstglfiltershader.h +++ b/ext/gl/gstglfiltershader.h @@ -46,6 +46,7 @@ struct _GstGLFilterShader GstStructure *uniforms; gboolean new_source; + gboolean new_uniforms; gdouble time; gint attr_position_loc;