mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-31 03:29:50 +00:00
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.
This commit is contained in:
parent
61b51b82ed
commit
b9e1cd3732
3 changed files with 62 additions and 49 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Reference in a new issue