[Cogl] [PATCH] cogl-gst: Add a functions to facilitate layering

Robert Bragg robert at sixbynine.org
Thu Apr 25 09:50:27 PDT 2013


This patch looks good to land to me:

Reviewed-by: Robert Bragg <robert at linux.intel.com>

thanks,
- Robert


On Wed, Apr 17, 2013 at 5:25 PM, Neil Roberts <neil at linux.intel.com> wrote:
> Thanks for the updated patch. I have some comments which I've
> addressed in another version of the patch below.
>
> I think it would be better if it only generated the default pipeline
> lazily when it is first requested because there is no point in having
> it if the application is only going to use the setup_pipeline
> function. For this to work, instead of emitting the pipeline_ready
> signal when we've actually created the pipeline, we can just emit it
> immediately after the caps are decided. As far as I can tell, your
> patch will end up emitting the ‘pipeline-ready’ signal as soon as
> set_first_layer() is called, even if no renderer is decided yet. I
> think it would be better to be able to call this as soon as the sink
> is created.
>
> I think it would be better to try to get the render to avoid
> generating the shader snippet code if there is already a cached
> snippet available. I think your version of the patch will generate the
> source for the snippet and then free it if it detects it already has a
> snippet.
>
> If we go back to making the cache a static variable in the
> setup_pipeline function then we don't need to store the render in the
> snippet cache.
>
> The global video sampling functions now all include the custom_start
> value as part of the function name. What is the idea behind this? Is
> it so that you could combine multiple video sinks into a single
> pipeline or something? I've left this in for now.
>
> The i420 renderer is using exactly the same source code as the yv12
> snippet. We might as well just make them share the same setup_pipeline
> function.
>
> I've removed the deinit virtual.
>
> Here is a proposed second version of the patch which implements these
> changes and rebases the patch on top of my patch to avoid setting a
> replace snippet.
>
> -->8--
> From: Plamena Manolova <plamena.n.manolova at intel.com>
>
> These functions are used when attaching frames at a start point other
> than layer 0 is required. This could potentially be used to "layer"
> videos and textures on top of each other in the CoglPipeline. This
> layering could come handy if videos are used as alpha masks or normal
> maps, or when arranging layers in a perticular order, so Cogl could
> blend them nicely without extra hassle.
> ---
>  cogl-gst/Makefile.am               |   7 +-
>  cogl-gst/cogl-gst-shader-private.h |  48 -----
>  cogl-gst/cogl-gst-shader.c         |  81 ---------
>  cogl-gst/cogl-gst-video-sink.c     | 359 ++++++++++++++++++++++++++-----------
>  cogl-gst/cogl-gst-video-sink.h     |  11 ++
>  5 files changed, 264 insertions(+), 242 deletions(-)
>  delete mode 100644 cogl-gst/cogl-gst-shader-private.h
>  delete mode 100644 cogl-gst/cogl-gst-shader.c
>
> diff --git a/cogl-gst/Makefile.am b/cogl-gst/Makefile.am
> index 57a64d8..d5e49ae 100644
> --- a/cogl-gst/Makefile.am
> +++ b/cogl-gst/Makefile.am
> @@ -8,7 +8,6 @@ DISTCLEANFILES =
>  EXTRA_DIST =
>
>  source_c = \
> -       cogl-gst-shader.c \
>         cogl-gst-video-sink.c \
>         $(NULL)
>
> @@ -17,13 +16,9 @@ source_h = \
>         cogl-gst-video-sink.h \
>         $(NULL)
>
> -source_h_priv = \
> -       cogl-gst-shader-private.h \
> -       $(NULL)
> -
>  lib_LTLIBRARIES = libcogl-gst.la
>
> -libcogl_gst_la_SOURCES = $(source_c) $(source_h) $(source_h_priv)
> +libcogl_gst_la_SOURCES = $(source_c) $(source_h)
>  libcogl_gst_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_GST_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
>  libcogl_gst_la_LIBADD = $(top_builddir)/cogl/libcogl2.la
>  libcogl_gst_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_GST_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
> diff --git a/cogl-gst/cogl-gst-shader-private.h b/cogl-gst/cogl-gst-shader-private.h
> deleted file mode 100644
> index bdf7164..0000000
> --- a/cogl-gst/cogl-gst-shader-private.h
> +++ /dev/null
> @@ -1,48 +0,0 @@
> -/*
> - * Cogl-GStreamer.
> - *
> - * GStreamer integration library for Cogl.
> - *
> - * cogl-gst-video-sink-private.h - Miscellaneous video sink functions
> - *
> - * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
> - *             Chris Lord        <chris at openedhand.com>
> - *             Damien Lespiau    <damien.lespiau at intel.com>
> - *             Matthew Allum     <mallum at openedhand.com>
> - *             Plamena Manolova  <plamena.n.manolova at intel.com>
> - *
> - * Copyright (C) 2007, 2008 OpenedHand
> - * Copyright (C) 2009, 2010, 2013 Intel Corporation
> - *
> - * This library is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU Lesser 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
> - * Lesser General Public License for more details.
> - *
> - * You should have received a copy of the GNU Lesser 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 __COGL_GST_SHADER_PRIVATE_H__
> -#define __COGL_GST_SHADER_PRIVATE_H__
> -
> -extern const char
> -_cogl_gst_shader_rgba_to_rgba_decl[];
> -
> -extern const char
> -_cogl_gst_shader_yv12_to_rgba_decl[];
> -
> -extern const char
> -_cogl_gst_shader_ayuv_to_rgba_decl[];
> -
> -extern const char
> -_cogl_gst_shader_default_sample[];
> -
> -#endif /* __COGL_GST_SHADER_PRIVATE_H__ */
> diff --git a/cogl-gst/cogl-gst-shader.c b/cogl-gst/cogl-gst-shader.c
> deleted file mode 100644
> index 7c34376..0000000
> --- a/cogl-gst/cogl-gst-shader.c
> +++ /dev/null
> @@ -1,81 +0,0 @@
> -/*
> - * Cogl-GStreamer.
> - *
> - * GStreamer integration library for Cogl.
> - *
> - * cogl-gst-video-sink-private.h - Miscellaneous video sink functions
> - *
> - * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
> - *             Chris Lord        <chris at openedhand.com>
> - *             Damien Lespiau    <damien.lespiau at intel.com>
> - *             Matthew Allum     <mallum at openedhand.com>
> - *             Plamena Manolova  <plamena.n.manolova at intel.com>
> - *
> - * Copyright (C) 2007, 2008 OpenedHand
> - * Copyright (C) 2009, 2010, 2013 Intel Corporation
> - *
> - * This library is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU Lesser 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
> - * Lesser General Public License for more details.
> - *
> - * You should have received a copy of the GNU Lesser 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 "cogl-gst-shader-private.h"
> -
> -const char
> -_cogl_gst_shader_rgba_to_rgba_decl[] =
> -  "vec4\n"
> -  "cogl_gst_sample_video (vec2 UV)\n"
> -  "{\n"
> -  "  return texture2D (cogl_sampler0, UV);\n"
> -  "}\n";
> -
> -const char
> -_cogl_gst_shader_yv12_to_rgba_decl[] =
> -  "vec4\n"
> -  "cogl_gst_sample_video (vec2 UV)\n"
> -  "{\n"
> -  "  float y = 1.1640625 * (texture2D (cogl_sampler0, UV).a - 0.0625);\n"
> -  "  float u = texture2D (cogl_sampler1, UV).a - 0.5;\n"
> -  "  float v = texture2D (cogl_sampler2, UV).a - 0.5;\n"
> -  "  vec4 color;\n"
> -  "  color.r = y + 1.59765625 * v;\n"
> -  "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
> -  "  color.b = y + 2.015625 * u;\n"
> -  "  color.a = 1.0;\n"
> -  "  return color;\n"
> -  "}\n";
> -
> -const char
> -_cogl_gst_shader_ayuv_to_rgba_decl[] =
> -  "vec4\n"
> -  "cogl_gst_sample_video (vec2 UV)\n"
> -  "{\n"
> -  "  vec4 color = texture2D (cogl_sampler0, UV);\n"
> -  "  float y = 1.1640625 * (color.g - 0.0625);\n"
> -  "  float u = color.b - 0.5;\n"
> -  "  float v = color.a - 0.5;\n"
> -  "  color.a = color.r;\n"
> -  "  color.r = y + 1.59765625 * v;\n"
> -  "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
> -  "  color.b = y + 2.015625 * u;\n"
> -  "  return color;\n"
> -  "}\n";
> -
> -const char
> -_cogl_gst_shader_default_sample[] =
> -  "  cogl_layer *= cogl_gst_sample_video (cogl_tex_coord0_in.st);\n";
> diff --git a/cogl-gst/cogl-gst-video-sink.c b/cogl-gst/cogl-gst-video-sink.c
> index c36111c..321ded8 100644
> --- a/cogl-gst/cogl-gst-video-sink.c
> +++ b/cogl-gst/cogl-gst-video-sink.c
> @@ -43,7 +43,6 @@
>  #include <string.h>
>
>  #include "cogl-gst-video-sink.h"
> -#include "cogl-gst-shader-private.h"
>
>  #define COGL_GST_TEXTURE_FLAGS \
>         (COGL_TEXTURE_NO_SLICING | COGL_TEXTURE_NO_ATLAS)
> @@ -99,6 +98,23 @@ typedef enum
>    COGL_GST_RENDERER_NEEDS_GLSL = (1 << 0)
>  } CoglGstRendererFlag;
>
> +/* We want to cache the snippets instead of recreating a new one every
> + * time we initialise a pipeline so that if we end up recreating the
> + * same pipeline again then Cogl will be able to use the pipeline
> + * cache to avoid linking a redundant identical shader program */
> +typedef struct
> +{
> +  CoglSnippet *vertex_snippet;
> +  CoglSnippet *fragment_snippet;
> +  CoglSnippet *default_sample_snippet;
> +  int start_position;
> +} SnippetCacheEntry;
> +
> +typedef struct
> +{
> +  GQueue entries;
> +} SnippetCache;
> +
>  typedef struct _CoglGstSource
>  {
>    GSource source;
> @@ -117,8 +133,9 @@ typedef struct _CoglGstRenderer
>    CoglGstVideoFormat format;
>    int flags;
>    GstStaticCaps caps;
> -  void (*init) (CoglGstVideoSink *sink);
> -  void (*deinit) (CoglGstVideoSink *sink);
> +  int n_layers;
> +  void (*setup_pipeline) (CoglGstVideoSink *sink,
> +                          CoglPipeline *pipeline);
>    CoglBool (*upload) (CoglGstVideoSink *sink,
>                        GstBuffer *buffer);
>  } CoglGstRenderer;
> @@ -136,7 +153,9 @@ struct _CoglGstVideoSinkPrivate
>    GstCaps *caps;
>    CoglGstRenderer *renderer;
>    GstFlowReturn flow_return;
> +  int custom_start;
>    int free_layer;
> +  CoglBool default_sample;
>    GstVideoInfo info;
>  };
>
> @@ -168,7 +187,8 @@ cogl_gst_video_sink_attach_frame (CoglGstVideoSink *sink,
>
>    for (i = 0; i < G_N_ELEMENTS (priv->frame); i++)
>      if (priv->frame[i] != NULL)
> -      cogl_pipeline_set_layer_texture (pln, i, priv->frame[i]);
> +      cogl_pipeline_set_layer_texture (pln, i + priv->custom_start,
> +                                       priv->frame[i]);
>
>    return priv->free_layer;
>  }
> @@ -200,77 +220,139 @@ cogl_gst_video_sink_set_priority (CoglGstVideoSink *sink,
>      g_source_set_priority ((GSource *) sink->priv->source, priority);
>  }
>
> -/* We want to cache the snippets instead of recreating a new one every
> - * time we initialise a pipeline so that if we end up recreating the
> - * same pipeline again then Cogl will be able to use the pipeline
> - * cache to avoid linking a redundant identical shader program */
> -typedef struct
> -{
> -  CoglSnippet *vertex_snippet;
> -  CoglSnippet *fragment_snippet;
> -} SnippetCache;
> -
>  static void
> -create_template_pipeline (CoglGstVideoSink *sink,
> -                          const char *decl,
> -                          SnippetCache *snippet_cache,
> -                          int n_layers)
> +dirty_default_pipeline (CoglGstVideoSink *sink)
>  {
>    CoglGstVideoSinkPrivate *priv = sink->priv;
> -  priv->free_layer = n_layers;
>
>    if (priv->pipeline)
> -    cogl_object_unref (priv->pipeline);
> -  priv->pipeline = cogl_pipeline_new (priv->ctx);
> +    {
> +      cogl_object_unref (priv->pipeline);
> +      priv->pipeline = NULL;
> +    }
> +}
> +
> +void
> +cogl_gst_video_sink_set_first_layer (CoglGstVideoSink *sink,
> +                                     int first_layer)
> +{
> +  if (first_layer != sink->priv->custom_start)
> +    {
> +      sink->priv->custom_start = first_layer;
> +      dirty_default_pipeline (sink);
> +
> +      if (sink->priv->renderer)
> +        sink->priv->free_layer = (sink->priv->custom_start +
> +                                  sink->priv->renderer->n_layers);
> +    }
> +}
> +
> +void
> +cogl_gst_video_sink_set_default_sample (CoglGstVideoSink *sink,
> +                                        CoglBool default_sample)
> +{
> +  if (default_sample != sink->priv->default_sample)
> +    {
> +      sink->priv->default_sample = default_sample;
> +      dirty_default_pipeline (sink);
> +    }
> +}
> +
> +void
> +cogl_gst_video_sink_setup_pipeline (CoglGstVideoSink *sink,
> +                                    CoglPipeline *pipeline)
> +{
> +  sink->priv->renderer->setup_pipeline (sink, pipeline);
> +}
> +
> +static SnippetCacheEntry *
> +get_cache_entry (CoglGstVideoSink *sink,
> +                 SnippetCache *cache)
> +{
> +  CoglGstVideoSinkPrivate *priv = sink->priv;
> +  GList *l;
> +
> +  for (l = cache->entries.head; l; l = l->next)
> +    {
> +      SnippetCacheEntry *entry = l->data;
> +
> +      if (entry->start_position == priv->custom_start)
> +        return entry;
> +    }
> +
> +  return NULL;
> +}
> +
> +static SnippetCacheEntry *
> +add_cache_entry (CoglGstVideoSink *sink,
> +                 SnippetCache *cache,
> +                 const char *decl)
> +{
> +  CoglGstVideoSinkPrivate *priv = sink->priv;
> +  SnippetCacheEntry *entry = g_slice_new (SnippetCacheEntry);
> +  char *default_source;
> +
> +  entry->start_position = priv->custom_start;
> +
> +  entry->vertex_snippet =
> +    cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
> +                      decl,
> +                      NULL /* post */);
> +  entry->fragment_snippet =
> +    cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
> +                      decl,
> +                      NULL /* post */);
> +
> +  default_source =
> +    g_strdup_printf ("  cogl_layer *= cogl_gst_sample_video%i "
> +                     "(cogl_tex_coord%i_in.st);\n",
> +                     priv->custom_start,
> +                     priv->custom_start);
> +  entry->default_sample_snippet =
> +    cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
> +                      NULL, /* declarations */
> +                      default_source);
> +  g_free (default_source);
> +
> +  g_queue_push_head (&cache->entries, entry);
> +
> +  return entry;
> +}
> +
> +static void
> +setup_pipeline_from_cache_entry (CoglGstVideoSink *sink,
> +                                 CoglPipeline *pipeline,
> +                                 SnippetCacheEntry *cache_entry,
> +                                 int n_layers)
> +{
> +  CoglGstVideoSinkPrivate *priv = sink->priv;
>
> -  if (decl)
> +  if (cache_entry)
>      {
> -      static CoglSnippet *default_sample_snippet = NULL;
>        int i;
>
>        /* The global sampling function gets added to both the fragment
>         * and vertex stages. The hope is that the GLSL compiler will
>         * easily remove the dead code if it's not actually used */
> -      if (snippet_cache->vertex_snippet == NULL)
> -        snippet_cache->vertex_snippet =
> -          cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
> -                            decl,
> -                            NULL /* post */);
> -      cogl_pipeline_add_snippet (priv->pipeline,
> -                                 snippet_cache->vertex_snippet);
> -
> -      if (snippet_cache->fragment_snippet == NULL)
> -        snippet_cache->fragment_snippet =
> -          cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
> -                            decl,
> -                            NULL /* post */);
> -      cogl_pipeline_add_snippet (priv->pipeline,
> -                                 snippet_cache->fragment_snippet);
> +      cogl_pipeline_add_snippet (pipeline, cache_entry->vertex_snippet);
> +      cogl_pipeline_add_snippet (pipeline, cache_entry->fragment_snippet);
>
>        /* Set all of the layers to just directly copy from the previous
>         * layer so that it won't redundantly generate code to sample
>         * the intermediate textures */
>        for (i = 0; i < n_layers; i++)
> -        cogl_pipeline_set_layer_combine (priv->pipeline,
> -                                         i,
> +        cogl_pipeline_set_layer_combine (pipeline,
> +                                         priv->custom_start + i,
>                                           "RGBA=REPLACE(PREVIOUS)",
>                                           NULL);
>
> -      if (default_sample_snippet == NULL)
> -        {
> -          default_sample_snippet =
> -            cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
> -                              NULL, /* declarations */
> -                              _cogl_gst_shader_default_sample);
> -        }
> -      cogl_pipeline_add_layer_snippet (priv->pipeline,
> -                                       n_layers - 1,
> -                                       default_sample_snippet);
> +      if (priv->default_sample)
> +        cogl_pipeline_add_layer_snippet (pipeline,
> +                                         priv->custom_start + n_layers - 1,
> +                                         cache_entry->default_sample_snippet);
>      }
>
>    priv->frame_dirty = TRUE;
> -
> -  g_signal_emit (sink, video_sink_signals[PIPELINE_READY_SIGNAL], 0, NULL);
>  }
>
>  CoglPipeline *
> @@ -278,23 +360,24 @@ cogl_gst_video_sink_get_pipeline (CoglGstVideoSink *vt)
>  {
>    CoglGstVideoSinkPrivate *priv = vt->priv;
>
> -  if (priv->frame_dirty)
> +  if (priv->pipeline == NULL)
> +    {
> +      priv->pipeline = cogl_pipeline_new (priv->ctx);
> +      cogl_gst_video_sink_setup_pipeline (vt, priv->pipeline);
> +      cogl_gst_video_sink_attach_frame (vt, priv->pipeline);
> +      priv->frame_dirty = FALSE;
> +    }
> +  else if (priv->frame_dirty)
>      {
>        CoglPipeline *pipeline = cogl_pipeline_copy (priv->pipeline);
>        cogl_object_unref (priv->pipeline);
>        priv->pipeline = pipeline;
>
>        cogl_gst_video_sink_attach_frame (vt, pipeline);
> -
>        priv->frame_dirty = FALSE;
>      }
>
> -  return vt->priv->pipeline;
> -}
> -
> -static void
> -cogl_gst_dummy_deinit (CoglGstVideoSink *sink)
> -{
> +  return priv->pipeline;
>  }
>
>  static void
> @@ -317,21 +400,35 @@ clear_frame_textures (CoglGstVideoSink *sink)
>  }
>
>  static void
> -cogl_gst_rgb_init (CoglGstVideoSink *sink)
> +cogl_gst_rgb_setup_pipeline (CoglGstVideoSink *sink,
> +                             CoglPipeline *pipeline)
>  {
>    CoglGstVideoSinkPrivate *priv = sink->priv;
>
>    if (cogl_has_feature (priv->ctx, COGL_FEATURE_ID_GLSL))
>      {
>        static SnippetCache snippet_cache;
> +      SnippetCacheEntry *entry = get_cache_entry (sink, &snippet_cache);
>
> -      create_template_pipeline (sink,
> -                                _cogl_gst_shader_rgba_to_rgba_decl,
> -                                &snippet_cache,
> -                                1);
> +      if (entry == NULL)
> +        {
> +          char *source;
> +
> +          source =
> +            g_strdup_printf ("vec4\n"
> +                             "cogl_gst_sample_video%i (vec2 UV)\n"
> +                             "{\n"
> +                             "  return texture2D (cogl_sampler%i, UV);\n"
> +                             "}\n",
> +                             priv->custom_start,
> +                             priv->custom_start);
> +
> +          setup_pipeline_from_cache_entry (sink, pipeline, entry, 1);
> +          g_free (source);
> +        }
>      }
>    else
> -    create_template_pipeline (sink, NULL, NULL, 1);
> +    setup_pipeline_from_cache_entry (sink, pipeline, NULL, 1);
>  }
>
>  static CoglBool
> @@ -376,8 +473,8 @@ static CoglGstRenderer rgb24_renderer =
>    COGL_GST_RGB24,
>    0,
>    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGB, BGR }")),
> -  cogl_gst_rgb_init,
> -  cogl_gst_dummy_deinit,
> +  1, /* n_layers */
> +  cogl_gst_rgb_setup_pipeline,
>    cogl_gst_rgb24_upload,
>  };
>
> @@ -423,8 +520,8 @@ static CoglGstRenderer rgb32_renderer =
>    COGL_GST_RGB32,
>    0,
>    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, BGRA }")),
> -  cogl_gst_rgb_init,
> -  cogl_gst_dummy_deinit,
> +  1, /* n_layers */
> +  cogl_gst_rgb_setup_pipeline,
>    cogl_gst_rgb32_upload,
>  };
>
> @@ -474,14 +571,44 @@ map_fail:
>  }
>
>  static void
> -cogl_gst_yv12_glsl_init (CoglGstVideoSink *sink)
> +cogl_gst_yv12_glsl_setup_pipeline (CoglGstVideoSink *sink,
> +                                   CoglPipeline *pipeline)
>  {
> +  CoglGstVideoSinkPrivate *priv = sink->priv;
>    static SnippetCache snippet_cache;
> +  SnippetCacheEntry *entry;
> +
> +  entry = get_cache_entry (sink, &snippet_cache);
> +
> +  if (entry == NULL)
> +    {
> +      char *source;
> +
> +      source =
> +        g_strdup_printf ("vec4\n"
> +                         "cogl_gst_sample_video%i (vec2 UV)\n"
> +                         "{\n"
> +                         "  float y = 1.1640625 * "
> +                         "(texture2D (cogl_sampler%i, UV).a - 0.0625);\n"
> +                         "  float u = texture2D (cogl_sampler%i, UV).a - 0.5;\n"
> +                         "  float v = texture2D (cogl_sampler%i, UV).a - 0.5;\n"
> +                         "  vec4 color;\n"
> +                         "  color.r = y + 1.59765625 * v;\n"
> +                         "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
> +                         "  color.b = y + 2.015625 * u;\n"
> +                         "  color.a = 1.0;\n"
> +                         "  return color;\n"
> +                         "}\n",
> +                         priv->custom_start,
> +                         priv->custom_start,
> +                         priv->custom_start + 1,
> +                         priv->custom_start + 2);
> +
> +      entry = add_cache_entry (sink, &snippet_cache, source);
> +      g_free (source);
> +    }
>
> -  create_template_pipeline (sink,
> -                            _cogl_gst_shader_yv12_to_rgba_decl,
> -                            &snippet_cache,
> -                            3);
> +  setup_pipeline_from_cache_entry (sink, pipeline, entry, 3);
>  }
>
>  static CoglGstRenderer yv12_glsl_renderer =
> @@ -490,42 +617,57 @@ static CoglGstRenderer yv12_glsl_renderer =
>    COGL_GST_YV12,
>    COGL_GST_RENDERER_NEEDS_GLSL,
>    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("YV12")),
> -  cogl_gst_yv12_glsl_init,
> -  cogl_gst_dummy_deinit,
> +  3, /* n_layers */
> +  cogl_gst_yv12_glsl_setup_pipeline,
>    cogl_gst_yv12_upload,
>  };
>
> -static void
> -cogl_gst_i420_glsl_init (CoglGstVideoSink *sink)
> -{
> -  static SnippetCache snippet_cache;
> -
> -  create_template_pipeline (sink,
> -                            _cogl_gst_shader_yv12_to_rgba_decl,
> -                            &snippet_cache,
> -                            3);
> -}
> -
>  static CoglGstRenderer i420_glsl_renderer =
>  {
>    "I420 glsl",
>    COGL_GST_I420,
>    COGL_GST_RENDERER_NEEDS_GLSL,
>    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")),
> -  cogl_gst_i420_glsl_init,
> -  cogl_gst_dummy_deinit,
> +  3, /* n_layers */
> +  cogl_gst_yv12_glsl_setup_pipeline,
>    cogl_gst_yv12_upload,
>  };
>
>  static void
> -cogl_gst_ayuv_glsl_init (CoglGstVideoSink *sink)
> +cogl_gst_ayuv_glsl_setup_pipeline (CoglGstVideoSink *sink,
> +                                   CoglPipeline *pipeline)
>  {
> +  CoglGstVideoSinkPrivate *priv = sink->priv;
>    static SnippetCache snippet_cache;
> +  SnippetCacheEntry *entry;
> +
> +  entry = get_cache_entry (sink, &snippet_cache);
> +
> +  if (entry == NULL)
> +    {
> +      char *source;
> +
> +      source
> +        = g_strdup_printf ("vec4\n"
> +                           "cogl_gst_sample_video%i (vec2 UV)\n"
> +                           "{\n"
> +                           "  vec4 color = texture2D (cogl_sampler%i, UV);\n"
> +                           "  float y = 1.1640625 * (color.g - 0.0625);\n"
> +                           "  float u = color.b - 0.5;\n"
> +                           "  float v = color.a - 0.5;\n"
> +                           "  color.a = color.r;\n"
> +                           "  color.r = y + 1.59765625 * v;\n"
> +                           "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
> +                           "  color.b = y + 2.015625 * u;\n"
> +                           "  return color;\n"
> +                           "}\n", priv->custom_start,
> +                           priv->custom_start);
> +
> +      entry = add_cache_entry (sink, &snippet_cache, source);
> +      g_free (source);
> +    }
>
> -  create_template_pipeline (sink,
> -                            _cogl_gst_shader_ayuv_to_rgba_decl,
> -                            &snippet_cache,
> -                            1);
> +  setup_pipeline_from_cache_entry (sink, pipeline, entry, 3);
>  }
>
>  static CoglBool
> @@ -565,8 +707,8 @@ static CoglGstRenderer ayuv_glsl_renderer =
>    COGL_GST_AYUV,
>    COGL_GST_RENDERER_NEEDS_GLSL,
>    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("AYUV")),
> -  cogl_gst_ayuv_glsl_init,
> -  cogl_gst_dummy_deinit,
> +  3, /* n_layers */
> +  cogl_gst_ayuv_glsl_setup_pipeline,
>    cogl_gst_ayuv_upload,
>  };
>
> @@ -814,14 +956,21 @@ cogl_gst_source_dispatch (GSource *source,
>          gst_pad_get_current_caps (GST_BASE_SINK_PAD ((GST_BASE_SINK
>                  (gst_source->sink))));
>
> -      if (priv->renderer)
> -        priv->renderer->deinit (gst_source->sink);
> -
>        if (!cogl_gst_video_sink_parse_caps (caps, gst_source->sink, TRUE))
>          goto negotiation_fail;
>
> -      priv->renderer->init (gst_source->sink);
>        gst_source->has_new_caps = FALSE;
> +      priv->free_layer = priv->custom_start + priv->renderer->n_layers;
> +
> +      dirty_default_pipeline (gst_source->sink);
> +
> +      /* We are now in a state where we could generate the pipeline if
> +       * the application requests it so we can emit the signal.
> +       * However we'll actually generate the pipeline lazily only if
> +       * the application actually asks for it. */
> +      g_signal_emit (gst_source->sink,
> +                     video_sink_signals[PIPELINE_READY_SIGNAL],
> +                     0 /* detail */);
>      }
>
>    buffer = gst_source->buffer;
> @@ -942,12 +1091,6 @@ cogl_gst_video_sink_dispose (GObject *object)
>
>    clear_frame_textures (self);
>
> -  if (priv->renderer)
> -    {
> -      priv->renderer->deinit (self);
> -      priv->renderer = NULL;
> -    }
> -
>    if (priv->pipeline)
>      {
>        cogl_object_unref (priv->pipeline);
> @@ -1113,6 +1256,8 @@ cogl_gst_video_sink_new (CoglContext *ctx)
>  {
>    CoglGstVideoSink *sink = g_object_new (COGL_GST_TYPE_VIDEO_SINK, NULL);
>    cogl_gst_video_sink_set_context (sink, ctx);
> +  sink->priv->custom_start = 0;
> +  sink->priv->default_sample = TRUE;
>
>    return sink;
>  }
> diff --git a/cogl-gst/cogl-gst-video-sink.h b/cogl-gst/cogl-gst-video-sink.h
> index 7ca054b..0bdf679 100644
> --- a/cogl-gst/cogl-gst-video-sink.h
> +++ b/cogl-gst/cogl-gst-video-sink.h
> @@ -117,6 +117,17 @@ int
>  cogl_gst_video_sink_attach_frame (CoglGstVideoSink *sink,
>                                    CoglPipeline *pln);
>
> +void
> +cogl_gst_video_sink_set_first_layer (CoglGstVideoSink *sink,
> +                                     int first_layer);
> +
> +void
> +cogl_gst_video_sink_set_default_sample (CoglGstVideoSink *sink,
> +                                        CoglBool default_sample);
> +
> +void
> +cogl_gst_video_sink_setup_pipeline (CoglGstVideoSink *sink,
> +                                    CoglPipeline *pipeline);
>  G_END_DECLS
>
>  #endif
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl


More information about the Cogl mailing list