Blame ext/gl/gstglfiltershader.c

Packit Service 4387a0
/*
Packit Service 4387a0
 * glshader gstreamer plugin
Packit Service 4387a0
 * Copyrithg (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
Packit Service 4387a0
 * Copyright (C) 2009 Luc Deschenaux <luc.deschenaux@freesurf.ch>
Packit Service 4387a0
 *
Packit Service 4387a0
 * This library is free software; you can redistribute it and/or
Packit Service 4387a0
 * modify it under the terms of the GNU Library General Public
Packit Service 4387a0
 * License as published by the Free Software Foundation; either
Packit Service 4387a0
 * version 2 of the License, or (at your option) any later version.
Packit Service 4387a0
 *
Packit Service 4387a0
 * This library is distributed in the hope that it will be useful,
Packit Service 4387a0
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4387a0
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4387a0
 * Library General Public License for more details.
Packit Service 4387a0
 *
Packit Service 4387a0
 * You should have received a copy of the GNU Library General Public
Packit Service 4387a0
 * License along with this library; if not, write to the
Packit Service 4387a0
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit Service 4387a0
 * Boston, MA 02110-1301, USA.
Packit Service 4387a0
 */
Packit Service 4387a0
Packit Service 4387a0
/**
Packit Service 4387a0
 * SECTION:element-glshader
Packit Service 4387a0
 * @title: glshader
Packit Service 4387a0
 *
Packit Service 4387a0
 * OpenGL fragment shader filter
Packit Service 4387a0
 *
Packit Service 4387a0
 * ## Examples
Packit Service 4387a0
 * |[
Packit Service 4387a0
 * gst-launch-1.0 videotestsrc ! glupload ! glshader fragment="\"`cat myshader.frag`\"" ! glimagesink
Packit Service 4387a0
 * ]|
Packit Service 4387a0
 * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
Packit Service 4387a0
 * Depending on the exact OpenGL version chosen and the exact requirements of
Packit Service 4387a0
 * the OpenGL implementation, a #version header may be required.
Packit Service 4387a0
 *
Packit Service 4387a0
 * The following is a simple OpenGL ES (also usable with OpenGL 3 core contexts)
Packit Service 4387a0
 * passthrough shader with the required inputs.
Packit Service 4387a0
 * |[
Packit Service 4387a0
 * #version 100
Packit Service 4387a0
 * #ifdef GL_ES
Packit Service 4387a0
 * precision mediump float;
Packit Service 4387a0
 * #endif
Packit Service 4387a0
 * varying vec2 v_texcoord;
Packit Service 4387a0
 * uniform sampler2D tex;
Packit Service 4387a0
 * uniform float time;
Packit Service 4387a0
 * uniform float width;
Packit Service 4387a0
 * uniform float height;
Packit Service 4387a0
 *
Packit Service 4387a0
 * void main () {
Packit Service 4387a0
 *   gl_FragColor = texture2D( tex, v_texcoord );
Packit Service 4387a0
 * }
Packit Service 4387a0
 * ]|
Packit Service 4387a0
 *
Packit Service 4387a0
 */
Packit Service 4387a0
#ifdef HAVE_CONFIG_H
Packit Service 4387a0
#include "config.h"
Packit Service 4387a0
#endif
Packit Service 4387a0
Packit Service 4387a0
#include <gst/gl/gstglfuncs.h>
Packit Service 4387a0
Packit Service 4387a0
#include "gstglfiltershader.h"
Packit Service 4387a0
#ifdef HAVE_GRAPHENE
Packit Service 4387a0
#include <graphene-gobject.h>
Packit Service 4387a0
#endif
Packit Service 4387a0
Packit Service 4387a0
enum
Packit Service 4387a0
{
Packit Service 4387a0
  PROP_0,
Packit Service 4387a0
  PROP_SHADER,
Packit Service 4387a0
  PROP_VERTEX,
Packit Service 4387a0
  PROP_FRAGMENT,
Packit Service 4387a0
  PROP_UNIFORMS,
Packit Service 4387a0
  PROP_UPDATE_SHADER,
Packit Service 4387a0
  PROP_LAST,
Packit Service 4387a0
};
Packit Service 4387a0
Packit Service 4387a0
enum
Packit Service 4387a0
{
Packit Service 4387a0
  SIGNAL_0,
Packit Service 4387a0
  SIGNAL_CREATE_SHADER,
Packit Service 4387a0
  SIGNAL_LAST,
Packit Service 4387a0
};
Packit Service 4387a0
Packit Service 4387a0
static guint gst_gl_shader_signals[SIGNAL_LAST] = { 0 };
Packit Service 4387a0
Packit Service 4387a0
#define GST_CAT_DEFAULT gst_gl_filtershader_debug
Packit Service 4387a0
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
Packit Service 4387a0
Packit Service 4387a0
#define DEBUG_INIT \
Packit Service 4387a0
  GST_DEBUG_CATEGORY_INIT (gst_gl_filtershader_debug, "glshader", 0, "glshader element");
Packit Service 4387a0
#define gst_gl_filtershader_parent_class parent_class
Packit Service 4387a0
G_DEFINE_TYPE_WITH_CODE (GstGLFilterShader, gst_gl_filtershader,
Packit Service 4387a0
    GST_TYPE_GL_FILTER, DEBUG_INIT);
Packit Service 4387a0
Packit Service 4387a0
static void gst_gl_filtershader_finalize (GObject * object);
Packit Service 4387a0
static void gst_gl_filtershader_set_property (GObject * object, guint prop_id,
Packit Service 4387a0
    const GValue * value, GParamSpec * pspec);
Packit Service 4387a0
static void gst_gl_filtershader_get_property (GObject * object, guint prop_id,
Packit Service 4387a0
    GValue * value, GParamSpec * pspec);
Packit Service 4387a0
static gboolean gst_gl_filtershader_gl_start (GstGLBaseFilter * base);
Packit Service 4387a0
static void gst_gl_filtershader_gl_stop (GstGLBaseFilter * base);
Packit Service 4387a0
static gboolean gst_gl_filtershader_filter (GstGLFilter * filter,
Packit Service 4387a0
    GstBuffer * inbuf, GstBuffer * outbuf);
Packit Service 4387a0
static gboolean gst_gl_filtershader_filter_texture (GstGLFilter * filter,
Packit Service 4387a0
    GstGLMemory * in_tex, GstGLMemory * out_tex);
Packit Service 4387a0
static gboolean gst_gl_filtershader_hcallback (GstGLFilter * filter,
Packit Service 4387a0
    GstGLMemory * in_tex, gpointer stuff);
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
gst_gl_filtershader_class_init (GstGLFilterShaderClass * klass)
Packit Service 4387a0
{
Packit Service 4387a0
  GObjectClass *gobject_class;
Packit Service 4387a0
  GstElementClass *element_class;
Packit Service 4387a0
Packit Service 4387a0
  gobject_class = (GObjectClass *) klass;
Packit Service 4387a0
  element_class = GST_ELEMENT_CLASS (klass);
Packit Service 4387a0
Packit Service 4387a0
  gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
Packit Service 4387a0
Packit Service 4387a0
  gobject_class->finalize = gst_gl_filtershader_finalize;
Packit Service 4387a0
  gobject_class->set_property = gst_gl_filtershader_set_property;
Packit Service 4387a0
  gobject_class->get_property = gst_gl_filtershader_get_property;
Packit Service 4387a0
Packit Service 4387a0
  g_object_class_install_property (gobject_class, PROP_SHADER,
Packit Service 4387a0
      g_param_spec_object ("shader", "Shader object",
Packit Service 4387a0
          "GstGLShader to use", GST_TYPE_GL_SHADER,
Packit Service 4387a0
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit Service 4387a0
Packit Service 4387a0
  g_object_class_install_property (gobject_class, PROP_VERTEX,
Packit Service 4387a0
      g_param_spec_string ("vertex", "Vertex Source",
Packit Service 4387a0
          "GLSL vertex source", NULL,
Packit Service 4387a0
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit Service 4387a0
Packit Service 4387a0
  g_object_class_install_property (gobject_class, PROP_FRAGMENT,
Packit Service 4387a0
      g_param_spec_string ("fragment", "Fragment Source",
Packit Service 4387a0
          "GLSL fragment source", NULL,
Packit Service 4387a0
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit Service 4387a0
  /* FIXME: add other stages */
Packit Service 4387a0
Packit Service 4387a0
  g_object_class_install_property (gobject_class, PROP_UNIFORMS,
Packit Service 4387a0
      g_param_spec_boxed ("uniforms", "GLSL Uniforms",
Packit Service 4387a0
          "GLSL Uniforms", GST_TYPE_STRUCTURE,
Packit Service 4387a0
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit Service 4387a0
Packit Service 4387a0
  g_object_class_install_property (gobject_class, PROP_UPDATE_SHADER,
Packit Service 4387a0
      g_param_spec_boolean ("update-shader", "Update Shader",
Packit Service 4387a0
          "Emit the \'create-shader\' signal for the next frame",
Packit Service 4387a0
          FALSE, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
Packit Service 4387a0
Packit Service 4387a0
  /*
Packit Service 4387a0
   * GstGLFilterShader::create-shader:
Packit Service 4387a0
   * @object: the #GstGLFilterShader
Packit Service 4387a0
   *
Packit Service 4387a0
   * Ask's the application for a shader to render with as a result of
Packit Service 4387a0
   * inititialization or setting the 'update-shader' property.
Packit Service 4387a0
   *
Packit Service 4387a0
   * Returns: a new #GstGLShader for use in the rendering pipeline
Packit Service 4387a0
   */
Packit Service 4387a0
  gst_gl_shader_signals[SIGNAL_CREATE_SHADER] =
Packit Service 4387a0
      g_signal_new ("create-shader", G_TYPE_FROM_CLASS (klass),
Packit Service 4387a0
      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
Packit Service 4387a0
      GST_TYPE_GL_SHADER, 0);
Packit Service 4387a0
Packit Service 4387a0
  gst_element_class_set_metadata (element_class,
Packit Service 4387a0
      "OpenGL fragment shader filter", "Filter/Effect",
Packit Service 4387a0
      "Perform operations with a GLSL shader", "<matthew@centricular.com>");
Packit Service 4387a0
Packit Service 4387a0
  GST_GL_FILTER_CLASS (klass)->filter = gst_gl_filtershader_filter;
Packit Service 4387a0
  GST_GL_FILTER_CLASS (klass)->filter_texture =
Packit Service 4387a0
      gst_gl_filtershader_filter_texture;
Packit Service 4387a0
Packit Service 4387a0
  GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_filtershader_gl_start;
Packit Service 4387a0
  GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_filtershader_gl_stop;
Packit Service 4387a0
  GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
Packit Service 4387a0
      GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
gst_gl_filtershader_init (GstGLFilterShader * filtershader)
Packit Service 4387a0
{
Packit Service 4387a0
  filtershader->new_source = TRUE;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
gst_gl_filtershader_finalize (GObject * object)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
Packit Service 4387a0
Packit Service 4387a0
  g_free (filtershader->vertex);
Packit Service 4387a0
  filtershader->vertex = NULL;
Packit Service 4387a0
Packit Service 4387a0
  g_free (filtershader->fragment);
Packit Service 4387a0
  filtershader->fragment = NULL;
Packit Service 4387a0
Packit Service 4387a0
  if (filtershader->uniforms)
Packit Service 4387a0
    gst_structure_free (filtershader->uniforms);
Packit Service 4387a0
  filtershader->uniforms = NULL;
Packit Service 4387a0
Packit Service 4387a0
  G_OBJECT_CLASS (gst_gl_filtershader_parent_class)->finalize (object);
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
gst_gl_filtershader_set_property (GObject * object, guint prop_id,
Packit Service 4387a0
    const GValue * value, GParamSpec * pspec)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
Packit Service 4387a0
Packit Service 4387a0
  switch (prop_id) {
Packit Service 4387a0
    case PROP_SHADER:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      gst_object_replace ((GstObject **) & filtershader->shader,
Packit Service 4387a0
          g_value_dup_object (value));
Packit Service 4387a0
      filtershader->new_source = FALSE;
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_VERTEX:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      g_free (filtershader->vertex);
Packit Service 4387a0
      filtershader->vertex = g_value_dup_string (value);
Packit Service 4387a0
      filtershader->new_source = TRUE;
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_FRAGMENT:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      g_free (filtershader->fragment);
Packit Service 4387a0
      filtershader->fragment = g_value_dup_string (value);
Packit Service 4387a0
      filtershader->new_source = TRUE;
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_UNIFORMS:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      if (filtershader->uniforms)
Packit Service 4387a0
        gst_structure_free (filtershader->uniforms);
Packit Service 4387a0
      filtershader->uniforms = g_value_dup_boxed (value);
Packit Service 4387a0
      filtershader->new_uniforms = TRUE;
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_UPDATE_SHADER:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      filtershader->update_shader = g_value_get_boolean (value);
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    default:
Packit Service 4387a0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service 4387a0
      break;
Packit Service 4387a0
  }
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
gst_gl_filtershader_get_property (GObject * object, guint prop_id,
Packit Service 4387a0
    GValue * value, GParamSpec * pspec)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
Packit Service 4387a0
Packit Service 4387a0
  switch (prop_id) {
Packit Service 4387a0
    case PROP_SHADER:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      g_value_set_object (value, filtershader->shader);
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_VERTEX:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      g_value_set_string (value, filtershader->vertex);
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_FRAGMENT:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      g_value_set_string (value, filtershader->fragment);
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    case PROP_UNIFORMS:
Packit Service 4387a0
      GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
      g_value_set_boxed (value, filtershader->uniforms);
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      break;
Packit Service 4387a0
    default:
Packit Service 4387a0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service 4387a0
      break;
Packit Service 4387a0
  }
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
gst_gl_filtershader_gl_stop (GstGLBaseFilter * base)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (base);
Packit Service 4387a0
Packit Service 4387a0
  if (filtershader->shader)
Packit Service 4387a0
    gst_object_unref (filtershader->shader);
Packit Service 4387a0
  filtershader->shader = NULL;
Packit Service 4387a0
Packit Service 4387a0
  GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base);
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static gboolean
Packit Service 4387a0
gst_gl_filtershader_gl_start (GstGLBaseFilter * base)
Packit Service 4387a0
{
Packit Service 4387a0
  return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base);
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static inline gboolean
Packit Service 4387a0
_gst_clock_time_to_double (GstClockTime time, gdouble * result)
Packit Service 4387a0
{
Packit Service 4387a0
  if (!GST_CLOCK_TIME_IS_VALID (time))
Packit Service 4387a0
    return FALSE;
Packit Service 4387a0
Packit Service 4387a0
  *result = (gdouble) time / GST_SECOND;
Packit Service 4387a0
Packit Service 4387a0
  return TRUE;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static inline gboolean
Packit Service 4387a0
_gint64_time_val_to_double (gint64 time, gdouble * result)
Packit Service 4387a0
{
Packit Service 4387a0
  if (time == -1)
Packit Service 4387a0
    return FALSE;
Packit Service 4387a0
Packit Service 4387a0
  *result = (gdouble) time / GST_USECOND;
Packit Service 4387a0
Packit Service 4387a0
  return TRUE;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static gboolean
Packit Service 4387a0
gst_gl_filtershader_filter (GstGLFilter * filter, GstBuffer * inbuf,
Packit Service 4387a0
    GstBuffer * outbuf)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
Packit Service 4387a0
Packit Service 4387a0
  if (!_gst_clock_time_to_double (GST_BUFFER_PTS (inbuf), &filtershader->time)) {
Packit Service 4387a0
    if (!_gst_clock_time_to_double (GST_BUFFER_DTS (inbuf),
Packit Service 4387a0
            &filtershader->time))
Packit Service 4387a0
      _gint64_time_val_to_double (g_get_monotonic_time (), &filtershader->time);
Packit Service 4387a0
  }
Packit Service 4387a0
Packit Service 4387a0
  return gst_gl_filter_filter_texture (filter, inbuf, outbuf);
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static gboolean
Packit Service 4387a0
gst_gl_filtershader_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
Packit Service 4387a0
    GstGLMemory * out_tex)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
Packit Service 4387a0
Packit Service 4387a0
  gst_gl_filter_render_to_target (filter, in_tex, out_tex,
Packit Service 4387a0
      gst_gl_filtershader_hcallback, NULL);
Packit Service 4387a0
Packit Service 4387a0
  if (!filtershader->shader)
Packit Service 4387a0
    return FALSE;
Packit Service 4387a0
Packit Service 4387a0
  return TRUE;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static gboolean
Packit Service 4387a0
_set_uniform (GQuark field_id, const GValue * value, gpointer user_data)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLShader *shader = user_data;
Packit Service 4387a0
  const gchar *field_name = g_quark_to_string (field_id);
Packit Service 4387a0
Packit Service 4387a0
  if (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_INT)) {
Packit Service 4387a0
    gst_gl_shader_set_uniform_1i (shader, field_name, g_value_get_int (value));
Packit Service 4387a0
  } else if (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLOAT)) {
Packit Service 4387a0
    gst_gl_shader_set_uniform_1f (shader, field_name,
Packit Service 4387a0
        g_value_get_float (value));
Packit Service 4387a0
#ifdef HAVE_GRAPHENE
Packit Service 4387a0
  } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC2)) {
Packit Service 4387a0
    graphene_vec2_t *vec2 = g_value_get_boxed (value);
Packit Service 4387a0
    float x = graphene_vec2_get_x (vec2);
Packit Service 4387a0
    float y = graphene_vec2_get_y (vec2);
Packit Service 4387a0
    gst_gl_shader_set_uniform_2f (shader, field_name, x, y);
Packit Service 4387a0
  } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC3)) {
Packit Service 4387a0
    graphene_vec3_t *vec3 = g_value_get_boxed (value);
Packit Service 4387a0
    float x = graphene_vec3_get_x (vec3);
Packit Service 4387a0
    float y = graphene_vec3_get_y (vec3);
Packit Service 4387a0
    float z = graphene_vec3_get_z (vec3);
Packit Service 4387a0
    gst_gl_shader_set_uniform_3f (shader, field_name, x, y, z);
Packit Service 4387a0
  } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC4)) {
Packit Service 4387a0
    graphene_vec4_t *vec4 = g_value_get_boxed (value);
Packit Service 4387a0
    float x = graphene_vec4_get_x (vec4);
Packit Service 4387a0
    float y = graphene_vec4_get_y (vec4);
Packit Service 4387a0
    float z = graphene_vec4_get_z (vec4);
Packit Service 4387a0
    float w = graphene_vec4_get_w (vec4);
Packit Service 4387a0
    gst_gl_shader_set_uniform_4f (shader, field_name, x, y, z, w);
Packit Service 4387a0
  } else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_MATRIX)) {
Packit Service 4387a0
    graphene_matrix_t *matrix = g_value_get_boxed (value);
Packit Service 4387a0
    float matrix_f[16];
Packit Service 4387a0
    graphene_matrix_to_float (matrix, matrix_f);
Packit Service 4387a0
    gst_gl_shader_set_uniform_matrix_4fv (shader, field_name, 1, FALSE,
Packit Service 4387a0
        matrix_f);
Packit Service 4387a0
#endif
Packit Service 4387a0
  } else {
Packit Service 4387a0
    /* FIXME: Add support for unsigned ints, non 4x4 matrices, etc */
Packit Service 4387a0
    GST_FIXME ("Don't know how to set the \'%s\' paramater.  Unknown type",
Packit Service 4387a0
        field_name);
Packit Service 4387a0
    return TRUE;
Packit Service 4387a0
  }
Packit Service 4387a0
Packit Service 4387a0
  return TRUE;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static void
Packit Service 4387a0
_update_uniforms (GstGLFilterShader * filtershader)
Packit Service 4387a0
{
Packit Service 4387a0
  if (filtershader->new_uniforms && filtershader->uniforms) {
Packit Service 4387a0
    gst_gl_shader_use (filtershader->shader);
Packit Service 4387a0
Packit Service 4387a0
    gst_structure_foreach (filtershader->uniforms,
Packit Service 4387a0
        (GstStructureForeachFunc) _set_uniform, filtershader->shader);
Packit Service 4387a0
    filtershader->new_uniforms = FALSE;
Packit Service 4387a0
  }
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static GstGLShader *
Packit Service 4387a0
_maybe_recompile_shader (GstGLFilterShader * filtershader)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLContext *context = GST_GL_BASE_FILTER (filtershader)->context;
Packit Service 4387a0
  GstGLShader *shader;
Packit Service 4387a0
  GError *error = NULL;
Packit Service 4387a0
Packit Service 4387a0
  GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
Packit Service 4387a0
  if (!filtershader->shader || filtershader->update_shader) {
Packit Service 4387a0
    filtershader->update_shader = FALSE;
Packit Service 4387a0
    GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
    g_signal_emit (filtershader, gst_gl_shader_signals[SIGNAL_CREATE_SHADER], 0,
Packit Service 4387a0
        &shader);
Packit Service 4387a0
    GST_OBJECT_LOCK (filtershader);
Packit Service 4387a0
Packit Service 4387a0
    if (shader) {
Packit Service 4387a0
      if (filtershader->shader)
Packit Service 4387a0
        gst_object_unref (filtershader->shader);
Packit Service 4387a0
      filtershader->new_source = FALSE;
Packit Service 4387a0
      filtershader->shader = gst_object_ref (shader);
Packit Service 4387a0
      filtershader->new_uniforms = TRUE;
Packit Service 4387a0
      _update_uniforms (filtershader);
Packit Service 4387a0
      GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
      return shader;
Packit Service 4387a0
    }
Packit Service 4387a0
  }
Packit Service 4387a0
Packit Service 4387a0
  if (filtershader->shader) {
Packit Service 4387a0
    shader = gst_object_ref (filtershader->shader);
Packit Service 4387a0
    _update_uniforms (filtershader);
Packit Service 4387a0
    GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
    return shader;
Packit Service 4387a0
  }
Packit Service 4387a0
Packit Service 4387a0
  if (filtershader->new_source) {
Packit Service 4387a0
    GstGLSLStage *stage;
Packit Service 4387a0
Packit Service 4387a0
    shader = gst_gl_shader_new (context);
Packit Service 4387a0
Packit Service 4387a0
    if (filtershader->vertex) {
Packit Service 4387a0
      if (!(stage = gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
Packit Service 4387a0
                  GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_NONE,
Packit Service 4387a0
                  filtershader->vertex))) {
Packit Service 4387a0
        g_set_error (&error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
Packit Service 4387a0
            "Failed to create shader vertex stage");
Packit Service 4387a0
        goto print_error;
Packit Service 4387a0
      }
Packit Service 4387a0
    } else {
Packit Service 4387a0
      stage = gst_glsl_stage_new_default_vertex (context);
Packit Service 4387a0
    }
Packit Service 4387a0
Packit Service 4387a0
    if (!gst_gl_shader_compile_attach_stage (shader, stage, &error)) {
Packit Service 4387a0
      gst_object_unref (stage);
Packit Service 4387a0
      goto print_error;
Packit Service 4387a0
    }
Packit Service 4387a0
Packit Service 4387a0
    if (filtershader->fragment) {
Packit Service 4387a0
      if (!(stage = gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
Packit Service 4387a0
                  GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_NONE,
Packit Service 4387a0
                  filtershader->fragment))) {
Packit Service 4387a0
        g_set_error (&error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
Packit Service 4387a0
            "Failed to create shader fragment stage");
Packit Service 4387a0
        goto print_error;
Packit Service 4387a0
      }
Packit Service 4387a0
    } else {
Packit Service 4387a0
      stage = gst_glsl_stage_new_default_fragment (context);
Packit Service 4387a0
    }
Packit Service 4387a0
Packit Service 4387a0
    if (!gst_gl_shader_compile_attach_stage (shader, stage, &error)) {
Packit Service 4387a0
      gst_object_unref (stage);
Packit Service 4387a0
      goto print_error;
Packit Service 4387a0
    }
Packit Service 4387a0
Packit Service 4387a0
    if (!gst_gl_shader_link (shader, &error)) {
Packit Service 4387a0
      goto print_error;
Packit Service 4387a0
    }
Packit Service 4387a0
    if (filtershader->shader)
Packit Service 4387a0
      gst_object_unref (filtershader->shader);
Packit Service 4387a0
    filtershader->shader = gst_object_ref (shader);
Packit Service 4387a0
    filtershader->new_source = FALSE;
Packit Service 4387a0
    filtershader->new_uniforms = TRUE;
Packit Service 4387a0
    _update_uniforms (filtershader);
Packit Service 4387a0
Packit Service 4387a0
    GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
    return shader;
Packit Service 4387a0
  } else if (filtershader->shader) {
Packit Service 4387a0
    _update_uniforms (filtershader);
Packit Service 4387a0
    shader = gst_object_ref (filtershader->shader);
Packit Service 4387a0
    GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
    return shader;
Packit Service 4387a0
  }
Packit Service 4387a0
Packit Service 4387a0
  return NULL;
Packit Service 4387a0
Packit Service 4387a0
print_error:
Packit Service 4387a0
  if (shader) {
Packit Service 4387a0
    gst_object_unref (shader);
Packit Service 4387a0
    shader = NULL;
Packit Service 4387a0
  }
Packit Service 4387a0
Packit Service 4387a0
  GST_OBJECT_UNLOCK (filtershader);
Packit Service 4387a0
  GST_ELEMENT_ERROR (filtershader, RESOURCE, NOT_FOUND,
Packit Service 4387a0
      ("%s", error->message), (NULL));
Packit Service 4387a0
  return NULL;
Packit Service 4387a0
}
Packit Service 4387a0
Packit Service 4387a0
static gboolean
Packit Service 4387a0
gst_gl_filtershader_hcallback (GstGLFilter * filter, GstGLMemory * in_tex,
Packit Service 4387a0
    gpointer stuff)
Packit Service 4387a0
{
Packit Service 4387a0
  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
Packit Service 4387a0
  GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
Packit Service 4387a0
  GstGLShader *shader;
Packit Service 4387a0
Packit Service 4387a0
  if (!(shader = _maybe_recompile_shader (filtershader)))
Packit Service 4387a0
    return FALSE;
Packit Service 4387a0
Packit Service 4387a0
  gl->ClearColor (0.0, 0.0, 0.0, 1.0);
Packit Service 4387a0
  gl->Clear (GL_COLOR_BUFFER_BIT);
Packit Service 4387a0
Packit Service 4387a0
  gst_gl_shader_use (shader);
Packit Service 4387a0
Packit Service 4387a0
  /* FIXME: propertise these */
Packit Service 4387a0
  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
Packit Service 4387a0
  gst_gl_shader_set_uniform_1f (shader, "width",
Packit Service 4387a0
      GST_VIDEO_INFO_WIDTH (&filter->out_info));
Packit Service 4387a0
  gst_gl_shader_set_uniform_1f (shader, "height",
Packit Service 4387a0
      GST_VIDEO_INFO_HEIGHT (&filter->out_info));
Packit Service 4387a0
  gst_gl_shader_set_uniform_1f (shader, "time", filtershader->time);
Packit Service 4387a0
Packit Service 4387a0
  /* FIXME: propertise these */
Packit Service 4387a0
  filter->draw_attr_position_loc =
Packit Service 4387a0
      gst_gl_shader_get_attribute_location (shader, "a_position");
Packit Service 4387a0
  filter->draw_attr_texture_loc =
Packit Service 4387a0
      gst_gl_shader_get_attribute_location (shader, "a_texcoord");
Packit Service 4387a0
Packit Service 4387a0
  gl->ActiveTexture (GL_TEXTURE0);
Packit Service 4387a0
  gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
Packit Service 4387a0
Packit Service 4387a0
  gst_gl_filter_draw_fullscreen_quad (filter);
Packit Service 4387a0
Packit Service 4387a0
  gst_object_unref (shader);
Packit Service 4387a0
Packit Service 4387a0
  return TRUE;
Packit Service 4387a0
}