From b9e1cd3732b783b0e6ad40ed6723fb864ca50d65 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sat, 17 Oct 2015 15:26:46 +1100 Subject: [PATCH] glshaderelement: implement on-demand create-shader signalling One may not have an GstGLContext available or current in the thread where one would need to update the shader. Support this by signalling create-shader whenever the one-shot 'update-shader' is set to TRUE. --- ext/gl/gstglfiltershader.c | 56 +++++++++++++++++++++---------- ext/gl/gstglfiltershader.h | 4 +-- tests/examples/gtk/glliveshader.c | 51 ++++++++++++---------------- 3 files changed, 62 insertions(+), 49 deletions(-) diff --git a/ext/gl/gstglfiltershader.c b/ext/gl/gstglfiltershader.c index e0c418b5bf..bde6630832 100644 --- a/ext/gl/gstglfiltershader.c +++ b/ext/gl/gstglfiltershader.c @@ -47,6 +47,7 @@ enum PROP_SHADER, PROP_VERTEX, PROP_FRAGMENT, + PROP_UPDATE_SHADER, PROP_LAST, }; @@ -111,6 +112,20 @@ 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_UPDATE_SHADER, + g_param_spec_boolean ("update-shader", "Update Shader", + "Emit the \'create-shader\' signal for the next frame", + FALSE, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + + /* + * GstGLFilterShader::create-shader: + * @object: the #GstGLFilterShader + * + * Ask's the application for a shader to render with as a result of + * inititialization or setting the 'update-shader' property. + * + * Returns: a new #GstGLShader for use in the rendering pipeline + */ gst_gl_shader_signals[SIGNAL_CREATE_SHADER] = g_signal_new ("create-shader", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, @@ -139,13 +154,6 @@ gst_gl_filtershader_init (GstGLFilterShader * filtershader) static void gst_gl_filtershader_finalize (GObject * object) { - GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object); - - if (filtershader->shader_prop) { - gst_object_unref (filtershader->shader_prop); - filtershader->shader_prop = NULL; - } - G_OBJECT_CLASS (gst_gl_filtershader_parent_class)->finalize (object); } @@ -158,9 +166,9 @@ gst_gl_filtershader_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_SHADER: GST_OBJECT_LOCK (filtershader); - gst_object_replace ((GstObject **) & filtershader->shader_prop, + gst_object_replace ((GstObject **) & filtershader->shader, g_value_dup_object (value)); - filtershader->new_source = TRUE; + filtershader->new_source = FALSE; GST_OBJECT_UNLOCK (filtershader); break; case PROP_VERTEX: @@ -179,6 +187,11 @@ gst_gl_filtershader_set_property (GObject * object, guint prop_id, filtershader->new_source = TRUE; GST_OBJECT_UNLOCK (filtershader); break; + case PROP_UPDATE_SHADER: + GST_OBJECT_LOCK (filtershader); + filtershader->update_shader = g_value_get_boolean (value); + GST_OBJECT_UNLOCK (filtershader); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -194,7 +207,7 @@ gst_gl_filtershader_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_SHADER: GST_OBJECT_LOCK (filtershader); - g_value_set_object (value, filtershader->shader_prop); + g_value_set_object (value, filtershader->shader); GST_OBJECT_UNLOCK (filtershader); break; case PROP_VERTEX: @@ -292,22 +305,29 @@ _maybe_recompile_shader (GstGLFilterShader * filtershader) GST_OBJECT_LOCK (filtershader); - if (filtershader->shader_prop) { - shader = gst_object_ref (filtershader->shader_prop); + if (!filtershader->shader || filtershader->update_shader) { + filtershader->update_shader = FALSE; GST_OBJECT_UNLOCK (filtershader); - return shader; - } - if (!filtershader->shader) { g_signal_emit (filtershader, gst_gl_shader_signals[SIGNAL_CREATE_SHADER], 0, - &filtershader->shader); - if (filtershader->shader) { + &shader); + GST_OBJECT_LOCK (filtershader); + + if (shader) { + if (filtershader->shader) + gst_object_unref (filtershader->shader); filtershader->new_source = FALSE; - shader = gst_object_ref (filtershader->shader); + filtershader->shader = gst_object_ref (shader); GST_OBJECT_UNLOCK (filtershader); return shader; } } + if (filtershader->shader) { + shader = gst_object_ref (filtershader->shader); + GST_OBJECT_UNLOCK (filtershader); + return shader; + } + if (filtershader->new_source) { GstGLSLStage *stage; diff --git a/ext/gl/gstglfiltershader.h b/ext/gl/gstglfiltershader.h index 31cbc2e3b1..ccddf34c58 100644 --- a/ext/gl/gstglfiltershader.h +++ b/ext/gl/gstglfiltershader.h @@ -39,12 +39,12 @@ struct _GstGLFilterShader GstGLFilter filter; /* properties */ - GstGLShader *shader_prop; + GstGLShader *shader; gchar *vertex; gchar *fragment; + gboolean update_shader; /* update the shader on the next draw */ GstStructure *uniforms; - GstGLShader *shader; gboolean new_source; gdouble time; diff --git a/tests/examples/gtk/glliveshader.c b/tests/examples/gtk/glliveshader.c index a8d128a4fe..6f820a63a9 100644 --- a/tests/examples/gtk/glliveshader.c +++ b/tests/examples/gtk/glliveshader.c @@ -195,36 +195,36 @@ _new_shader (GstGLContext * context, struct shader_state *state) return shader; } +static gboolean +_set_compilation_state (struct shader_state *state) +{ + gtk_label_set_text (GTK_LABEL (state->label), + state->shader_linked ? "Success" : "Failure"); + + return G_SOURCE_REMOVE; +} + static GstGLShader * _create_shader (GstElement * element, struct shader_state *state) { GstGLContext *context; - GstGLShader *shader; + GstGLShader *shader, *new_shader; - g_object_get (G_OBJECT (element), "context", &context, NULL); + g_object_get (G_OBJECT (element), "context", &context, "shader", &shader, + NULL); - shader = _new_shader (context, state); - state->shader_linked = TRUE; + new_shader = _new_shader (context, state); + if (!shader && !new_shader) + g_warning ("Failed to create a shader!"); + state->shader_linked = new_shader != NULL; - if (state->context) - gst_object_unref (state->context); - state->context = context; + if (shader) + gst_object_unref (shader); + gst_object_unref (context); - return shader; -} + g_main_context_invoke (NULL, (GSourceFunc) _set_compilation_state, state); -static void -_modify_shader (GstGLContext * context, struct shader_state *state) -{ - GstGLShader *shader; - - if (!(shader = _new_shader (context, state))) { - state->shader_linked = FALSE; - return; - } - state->shader_linked = TRUE; - - g_object_set (state->shader, "shader", shader, NULL); + return new_shader; } static void @@ -232,18 +232,11 @@ _on_text_changed (GtkTextBuffer * text, struct text_view_state *state) { GtkTextIter start, end; - if (!state->state->context) - return; - gtk_text_buffer_get_bounds (text, &start, &end); if (state->str) g_free (state->str); state->str = gtk_text_buffer_get_text (text, &start, &end, FALSE); - gst_gl_context_thread_add (state->state->context, - (GstGLContextThreadFunc) _modify_shader, state->state); - - gtk_label_set_text (GTK_LABEL (state->state->label), - state->state->shader_linked ? "Success" : "Failure"); + g_object_set (state->state->shader, "update-shader", TRUE, NULL); } static GtkWidget *