[vlc-devel] [PATCH v3 14/22] opengl: support "blend" filters

Romain Vimont rom1v at videolabs.io
Mon Jul 6 12:47:07 CEST 2020


A blend filter draws over the result of any previous filter.

Expose a flag to be set by filter modules implementation, and draw them
using the same draw framebuffer as the last (non-blend) filter.

If the first filter is a blend filter, then a "draw" filter (a non-blend
filter which just draws the input picture) is automatically inserted.

Co-authored-by: Alexandre Janniaux <ajanni at videolabs.io>
Co-authored-by: Maxime Meissonnier <mmeisson at outlook.fr>
---
 modules/video_output/opengl/filter.c      | 10 +++++
 modules/video_output/opengl/filter.h      |  9 ++++
 modules/video_output/opengl/filter_priv.h | 10 +++++
 modules/video_output/opengl/filters.c     | 51 +++++++++++++++++++++--
 4 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/modules/video_output/opengl/filter.c b/modules/video_output/opengl/filter.c
index 11007edfcd..91b2627d6f 100644
--- a/modules/video_output/opengl/filter.c
+++ b/modules/video_output/opengl/filter.c
@@ -49,10 +49,13 @@ vlc_gl_filter_New(vlc_object_t *parent, const struct vlc_gl_api *api)
 
     struct vlc_gl_filter *filter = &priv->filter;
     filter->api = api;
+    filter->config.blend = false;
     filter->ops = NULL;
     filter->sys = NULL;
     filter->module = NULL;
 
+    vlc_list_init(&priv->blend_subfilters);
+
     return filter;
 }
 
@@ -98,6 +101,13 @@ vlc_gl_filter_Delete(struct vlc_gl_filter *filter)
 
     struct vlc_gl_filter_priv *priv = vlc_gl_filter_PRIV(filter);
 
+    struct vlc_gl_filter_priv *subfilter_priv;
+    vlc_list_foreach(subfilter_priv, &priv->blend_subfilters, node)
+    {
+        struct vlc_gl_filter *subfilter = &subfilter_priv->filter;
+        vlc_gl_filter_Delete(subfilter);
+    }
+
     if (priv->sampler)
         vlc_gl_sampler_Delete(priv->sampler);
 
diff --git a/modules/video_output/opengl/filter.h b/modules/video_output/opengl/filter.h
index f6dbd3db23..41bf5b133f 100644
--- a/modules/video_output/opengl/filter.h
+++ b/modules/video_output/opengl/filter.h
@@ -58,6 +58,15 @@ struct vlc_gl_filter {
 
     const struct vlc_gl_api *api;
 
+    struct {
+        /**
+         * A blend filter draws over the input picture (without reading it).
+         *
+         * This flag must be set by the filter module (default is false).
+         */
+        bool blend;
+    } config;
+
     const struct vlc_gl_filter_ops *ops;
     void *sys;
 };
diff --git a/modules/video_output/opengl/filter_priv.h b/modules/video_output/opengl/filter_priv.h
index 8e177908f3..509a74ec64 100644
--- a/modules/video_output/opengl/filter_priv.h
+++ b/modules/video_output/opengl/filter_priv.h
@@ -30,14 +30,24 @@
 
 struct vlc_gl_filter_priv {
     struct vlc_gl_filter filter;
+
+    /* For a blend filter, must be the same as the size_out of the previous
+     * filter */
     struct vlc_gl_tex_size size_out;
+
+    /* Only meaningful for non-blend filters { */
     struct vlc_gl_sampler *sampler; /* owned */
 
     bool has_framebuffer_out;
     GLuint framebuffer_out; /* owned (this filter must delete it) */
     GLuint texture_out; /* owned (attached to framebuffer_out) */
+    /* } */
 
     struct vlc_list node; /**< node of vlc_gl_filters.list */
+
+    /* Blend filters are attached to their non-blend "parent" instead of the
+     * filter chain to simplify the rendering code */
+    struct vlc_list blend_subfilters; /**< list of vlc_gl_filter_priv.node */
 };
 
 #define vlc_gl_filter_PRIV(filter) \
diff --git a/modules/video_output/opengl/filters.c b/modules/video_output/opengl/filters.c
index 2f4f7af64a..6a8ba0ec4c 100644
--- a/modules/video_output/opengl/filters.c
+++ b/modules/video_output/opengl/filters.c
@@ -162,12 +162,30 @@ vlc_gl_filters_Append(struct vlc_gl_filters *filters, const char *name,
         return NULL;
     }
 
-    if (prev_filter)
+    /* A blend filter may not change its output size. */
+    assert(!filter->config.blend
+           || (priv->size_out.width == size_in.width
+            && priv->size_out.height == size_in.height));
+
+    if (filter->config.blend && !prev_filter)
     {
-        /* It was the last filter before we append this one */
+        /* We cannot blend with nothing, so insert a "draw" filter to draw the
+         * input picture to blend with. */
+        struct vlc_gl_filter *draw =
+            vlc_gl_filters_Append(filters, "draw", NULL);
+        if (!draw)
+        {
+            vlc_gl_filter_Delete(filter);
+            return NULL;
+        }
+    }
+    else if (!filter->config.blend && prev_filter)
+    {
+        /* It was the last non-blend filter before we append this one */
         assert(!prev_filter->has_framebuffer_out);
 
-        /* Every non-last filter needs its own framebuffer */
+        /* Every non-blend filter needs its own framebuffer, except the last
+         * one */
         ret = InitFramebufferOut(prev_filter);
         if (ret != VLC_SUCCESS)
         {
@@ -176,7 +194,18 @@ vlc_gl_filters_Append(struct vlc_gl_filters *filters, const char *name,
         }
     }
 
-    vlc_list_append(&priv->node, &filters->list);
+    if (filter->config.blend)
+    {
+        /* Append as a subfilter of a non-blend filter */
+        struct vlc_gl_filter_priv *last_filter =
+            vlc_list_last_entry_or_null(&filters->list,
+                                        struct vlc_gl_filter_priv, node);
+        assert(last_filter);
+        vlc_list_append(&priv->node, &last_filter->blend_subfilters);
+    }
+    else
+        /* Append to the main filter list */
+        vlc_list_append(&priv->node, &filters->list);
 
     return filter;
 }
@@ -234,6 +263,20 @@ vlc_gl_filters_Draw(struct vlc_gl_filters *filters)
         int ret = filter->ops->draw(filter);
         if (ret != VLC_SUCCESS)
             return ret;
+
+        /* Draw blend subfilters */
+        struct vlc_gl_filter_priv *subfilter_priv;
+        vlc_list_foreach(subfilter_priv, &priv->blend_subfilters, node)
+        {
+            /* Reset the draw buffer, in case it has been changed from a filter
+             * draw() callback */
+            vt->BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fb);
+
+            struct vlc_gl_filter *subfilter = &subfilter_priv->filter;
+            ret = subfilter->ops->draw(subfilter);
+            if (ret != VLC_SUCCESS)
+                return ret;
+        }
     }
 
     return VLC_SUCCESS;
-- 
2.27.0



More information about the vlc-devel mailing list