vlc | branch: master | Romain Vimont <[email protected]> | Tue Jul 7 12:33:53 2020 +0200| [9d0b1e1eb11e9e4468c840e9bfa10bfb933b65bc] | committer: Alexandre Janniaux
opengl: create and bind filters framebuffers Create one framebuffer and its associate texture for each filter, and bind them as necessary before drawing so that the output of a filter is the input of the next one. Co-authored-by: Alexandre Janniaux <[email protected]> Co-authored-by: Maxime Meissonnier <[email protected]> Signed-off-by: Alexandre Janniaux <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=9d0b1e1eb11e9e4468c840e9bfa10bfb933b65bc --- modules/video_output/opengl/filter.c | 11 +++++ modules/video_output/opengl/filter_priv.h | 4 ++ modules/video_output/opengl/filters.c | 72 +++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/modules/video_output/opengl/filter.c b/modules/video_output/opengl/filter.c index 80a0459be9..11007edfcd 100644 --- a/modules/video_output/opengl/filter.c +++ b/modules/video_output/opengl/filter.c @@ -30,6 +30,7 @@ #include <vlc_common.h> #include <vlc_modules.h> +#include "gl_api.h" #include "sampler_priv.h" #undef vlc_gl_filter_New @@ -44,6 +45,8 @@ vlc_gl_filter_New(vlc_object_t *parent, const struct vlc_gl_api *api) priv->size_out.width = 0; priv->size_out.height = 0; + priv->has_framebuffer_out = false; + struct vlc_gl_filter *filter = &priv->filter; filter->api = api; filter->ops = NULL; @@ -94,8 +97,16 @@ vlc_gl_filter_Delete(struct vlc_gl_filter *filter) module_unneed(filter, filter->module); struct vlc_gl_filter_priv *priv = vlc_gl_filter_PRIV(filter); + if (priv->sampler) vlc_gl_sampler_Delete(priv->sampler); + if (priv->has_framebuffer_out) + { + const opengl_vtable_t *vt = &filter->api->vt; + vt->DeleteFramebuffers(1, &priv->framebuffer_out); + vt->DeleteTextures(1, &priv->texture_out); + } + vlc_object_delete(&filter->obj); } diff --git a/modules/video_output/opengl/filter_priv.h b/modules/video_output/opengl/filter_priv.h index 50134faf50..8e177908f3 100644 --- a/modules/video_output/opengl/filter_priv.h +++ b/modules/video_output/opengl/filter_priv.h @@ -33,6 +33,10 @@ struct vlc_gl_filter_priv { struct vlc_gl_tex_size size_out; 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 */ }; diff --git a/modules/video_output/opengl/filters.c b/modules/video_output/opengl/filters.c index 47c222f533..d6762b0b56 100644 --- a/modules/video_output/opengl/filters.c +++ b/modules/video_output/opengl/filters.c @@ -73,6 +73,41 @@ vlc_gl_filters_Delete(struct vlc_gl_filters *filters) free(filters); } +static int +InitFramebufferOut(struct vlc_gl_filter_priv *priv) +{ + assert(priv->size_out.width > 0 && priv->size_out.height > 0); + + const opengl_vtable_t *vt = &priv->filter.api->vt; + + /* Create a texture having the expected size */ + vt->GenTextures(1, &priv->texture_out); + vt->BindTexture(GL_TEXTURE_2D, priv->texture_out); + vt->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, priv->size_out.width, + priv->size_out.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + vt->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + vt->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + /* iOS needs GL_CLAMP_TO_EDGE or power-of-two textures */ + vt->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + vt->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + /* Create a framebuffer and attach the texture */ + vt->GenFramebuffers(1, &priv->framebuffer_out); + vt->BindFramebuffer(GL_FRAMEBUFFER, priv->framebuffer_out); + vt->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, priv->texture_out, 0); + + priv->has_framebuffer_out = true; + + GLenum status = vt->CheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + return VLC_EGENERIC; + + vt->BindFramebuffer(GL_FRAMEBUFFER, 0); + return VLC_SUCCESS; +} + struct vlc_gl_filter * vlc_gl_filters_Append(struct vlc_gl_filters *filters, const char *name, const config_chain_t *config) @@ -127,6 +162,20 @@ vlc_gl_filters_Append(struct vlc_gl_filters *filters, const char *name, return NULL; } + if (prev_filter) + { + /* It was the last filter before we append this one */ + assert(!prev_filter->has_framebuffer_out); + + /* Every non-last filter needs its own framebuffer */ + ret = InitFramebufferOut(prev_filter); + if (ret != VLC_SUCCESS) + { + vlc_gl_filter_Delete(filter); + return NULL; + } + } + vlc_list_append(&priv->node, &filters->list); return filter; @@ -150,9 +199,32 @@ vlc_gl_filters_UpdatePicture(struct vlc_gl_filters *filters, int vlc_gl_filters_Draw(struct vlc_gl_filters *filters) { + const opengl_vtable_t *vt = &filters->api->vt; + struct vlc_gl_filter_priv *priv; vlc_list_foreach(priv, &filters->list, node) { + struct vlc_gl_filter_priv *previous = + vlc_list_prev_entry_or_null(&filters->list, priv, + struct vlc_gl_filter_priv, node); + if (previous) + { + /* Read from the output of the previous filter */ + int ret = vlc_gl_sampler_UpdateTexture(priv->sampler, + previous->texture_out, + previous->size_out.width, + previous->size_out.height); + if (ret != VLC_SUCCESS) + { + msg_Err(filters->gl, "Could not update sampler texture"); + return ret; + } + } + + GLuint draw_fb = priv->has_framebuffer_out ? priv->framebuffer_out : 0; + + vt->BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fb); + struct vlc_gl_filter *filter = &priv->filter; int ret = filter->ops->draw(filter); if (ret != VLC_SUCCESS) _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
