[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