[Cogl] [PATCH] gst: Cache the shader snippets

Neil Roberts neil at linux.intel.com
Tue Mar 5 07:15:32 PST 2013


Here's one thing that I forgot to mention that I think would be good
to squash in the CoglGst patch.

-- >8 --

Previously every time the renderer is initialised it will create a new
snippet. This will cause Cogl to compile a new GLSL program. Cogl
currently never destroys GLSL programs because they are always retained
in the pipeline cache so if the application ends up playing a lot of
videos it could end up with a lot of identical GLSL programs floating
around.

If we make it reuse the same snippets instead then it should be able to
take advantage of the pipeline cache and avoid creating a new program
object. The snippets are always created with a small set of static
strings and snippets can be constructed without a context so this patch
makes it just store the snippet in a static variable in renderer init
functions.
---
 cogl-gst/cogl-gst-video-sink.c | 78 +++++++++++++++++++++++++++++-------------
 1 file changed, 55 insertions(+), 23 deletions(-)

diff --git a/cogl-gst/cogl-gst-video-sink.c b/cogl-gst/cogl-gst-video-sink.c
index fae22c5..1e49b9a 100644
--- a/cogl-gst/cogl-gst-video-sink.c
+++ b/cogl-gst/cogl-gst-video-sink.c
@@ -198,9 +198,20 @@ 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)
 {
   CoglGstVideoSinkPrivate *priv = sink->priv;
@@ -212,34 +223,41 @@ create_template_pipeline (CoglGstVideoSink *sink,
 
   if (decl)
     {
-      CoglSnippet *snippet;
+      static CoglSnippet *default_sample_snippet = NULL;
 
       /* 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 */
-      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
-                                  decl,
-                                  NULL /* post */);
-      cogl_pipeline_add_snippet (priv->pipeline, snippet);
-      cogl_object_unref (snippet);
-
-      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
-                                  decl,
-                                  NULL /* post */);
-      cogl_pipeline_add_snippet (priv->pipeline, snippet);
-      cogl_object_unref (snippet);
+      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);
 
       /* Set the replace string for the last layer so that no
        * redundant code for the previous layers will be generated. The
        * application can also replace this default sampling by adding
        * another layer */
-      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
-                                  NULL,
-                                  NULL);
-      cogl_snippet_set_replace (snippet,
-                                _cogl_gst_shader_default_sample);
-      cogl_pipeline_add_layer_snippet (priv->pipeline, n_layers - 1, snippet);
-      cogl_object_unref (snippet);
+      if (default_sample_snippet == NULL)
+        {
+          default_sample_snippet =
+            cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT, NULL, NULL);
+          cogl_snippet_set_replace (default_sample_snippet,
+                                    _cogl_gst_shader_default_sample);
+        }
+      cogl_pipeline_add_layer_snippet (priv->pipeline,
+                                       n_layers - 1,
+                                       default_sample_snippet);
     }
 
   g_signal_emit (sink, video_sink_signals[PIPELINE_READY_SIGNAL], 0, NULL);
@@ -285,11 +303,16 @@ cogl_gst_rgb_init (CoglGstVideoSink *sink)
   CoglGstVideoSinkPrivate *priv = sink->priv;
 
   if (cogl_has_feature (priv->ctx, COGL_FEATURE_ID_GLSL))
-    create_template_pipeline (sink,
-                              _cogl_gst_shader_rgba_to_rgba_decl,
-                              1);
+    {
+      static SnippetCache snippet_cache;
+
+      create_template_pipeline (sink,
+                                _cogl_gst_shader_rgba_to_rgba_decl,
+                                &snippet_cache,
+                                1);
+    }
   else
-    create_template_pipeline (sink, NULL, 1);
+    create_template_pipeline (sink, NULL, NULL, 1);
 }
 
 static CoglBool
@@ -434,8 +457,11 @@ map_fail:
 static void
 cogl_gst_yv12_glsl_init (CoglGstVideoSink *sink)
 {
+  static SnippetCache snippet_cache;
+
   create_template_pipeline (sink,
                             _cogl_gst_shader_yv12_to_rgba_decl,
+                            &snippet_cache,
                             3);
 }
 
@@ -453,8 +479,11 @@ static CoglGstRenderer yv12_glsl_renderer =
 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);
 }
 
@@ -472,8 +501,11 @@ static CoglGstRenderer i420_glsl_renderer =
 static void
 cogl_gst_ayuv_glsl_init (CoglGstVideoSink *sink)
 {
+  static SnippetCache snippet_cache;
+
   create_template_pipeline (sink,
                             _cogl_gst_shader_ayuv_to_rgba_decl,
+                            &snippet_cache,
                             1);
 }
 
-- 
1.7.11.3.g3c3efa5



More information about the Cogl mailing list