vlc | branch: master | Romain Vimont <[email protected]> | Tue Jul 7 12:34:02 2020 +0200| [d2a795eb1715be0f88c9bbd2afd9ff3eaa0d86e1] | committer: Alexandre Janniaux
opengl: enable multisampling Enable multisampling anti-aliasing: - render to an intermediate multisample renderbuffer; - resolve it to the output framebuffer. Co-authored-by: Alexandre Janniaux <[email protected]> Signed-off-by: Alexandre Janniaux <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d2a795eb1715be0f88c9bbd2afd9ff3eaa0d86e1 --- modules/video_output/opengl/filter.c | 10 ++- modules/video_output/opengl/filter.h | 12 ++++ modules/video_output/opengl/filter_priv.h | 4 ++ modules/video_output/opengl/filters.c | 100 +++++++++++++++++++++++++++++- modules/video_output/opengl/gl_api.c | 12 ++++ modules/video_output/opengl/gl_api.h | 3 + modules/video_output/opengl/gl_common.h | 8 +++ 7 files changed, 145 insertions(+), 4 deletions(-) diff --git a/modules/video_output/opengl/filter.c b/modules/video_output/opengl/filter.c index 208ccc12cb..819f5078aa 100644 --- a/modules/video_output/opengl/filter.c +++ b/modules/video_output/opengl/filter.c @@ -50,6 +50,7 @@ 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->config.msaa_level = 0; filter->ops = NULL; filter->sys = NULL; filter->module = NULL; @@ -109,12 +110,19 @@ vlc_gl_filter_Delete(struct vlc_gl_filter *filter) if (priv->sampler) vlc_gl_sampler_Delete(priv->sampler); + const opengl_vtable_t *vt = &filter->api->vt; + 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); } + if (filter->config.msaa_level) + { + vt->DeleteFramebuffers(1, &priv->framebuffer_msaa); + vt->DeleteRenderbuffers(1, &priv->renderbuffer_msaa); + } + vlc_object_delete(&filter->obj); } diff --git a/modules/video_output/opengl/filter.h b/modules/video_output/opengl/filter.h index 88b4f572b0..399087d68f 100644 --- a/modules/video_output/opengl/filter.h +++ b/modules/video_output/opengl/filter.h @@ -86,6 +86,18 @@ struct vlc_gl_filter { * This flag must be set by the filter module (default is false). */ bool blend; + + /** + * Request MSAA level. + * + * This value must be set by the filter module (default is 0, which + * means disabled). + * + * The actual MSAA level may be overwritten to 0 if multisampling is + * not supported, or to a higher value if another filter rendering on + * the same framebuffer requested a higher MSAA level. + */ + unsigned msaa_level; } config; const struct vlc_gl_filter_ops *ops; diff --git a/modules/video_output/opengl/filter_priv.h b/modules/video_output/opengl/filter_priv.h index de1c4cd319..f4c983ce85 100644 --- a/modules/video_output/opengl/filter_priv.h +++ b/modules/video_output/opengl/filter_priv.h @@ -41,6 +41,10 @@ struct vlc_gl_filter_priv { bool has_framebuffer_out; GLuint framebuffer_out; /* owned (this filter must delete it) */ GLuint texture_out; /* owned (attached to framebuffer_out) */ + + /* For multisampling, if msaa_level != 0 */ + GLuint framebuffer_msaa; /* owned */ + GLuint renderbuffer_msaa; /* owned (attached to framebuffer_msaa) */ /* } */ /* For lazy-loading sampler */ diff --git a/modules/video_output/opengl/filters.c b/modules/video_output/opengl/filters.c index 497ff2af68..66084b81cb 100644 --- a/modules/video_output/opengl/filters.c +++ b/modules/video_output/opengl/filters.c @@ -124,6 +124,34 @@ InitFramebufferOut(struct vlc_gl_filter_priv *priv) return VLC_SUCCESS; } +static int +InitFramebufferMSAA(struct vlc_gl_filter_priv *priv, unsigned msaa_level) +{ + assert(msaa_level); + assert(priv->size_out.width > 0 && priv->size_out.height > 0); + + const opengl_vtable_t *vt = &priv->filter.api->vt; + + vt->GenRenderbuffers(1, &priv->renderbuffer_msaa); + vt->BindRenderbuffer(GL_RENDERBUFFER, priv->renderbuffer_msaa); + vt->RenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, + GL_RGBA8, + priv->size_out.width, + priv->size_out.height); + + vt->GenFramebuffers(1, &priv->framebuffer_msaa); + vt->BindFramebuffer(GL_FRAMEBUFFER, priv->framebuffer_msaa); + vt->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, priv->renderbuffer_msaa); + + GLenum status = vt->CheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + return VLC_EGENERIC; + + vt->BindFramebuffer(GL_FRAMEBUFFER, 0); + return VLC_SUCCESS; +} + static struct vlc_gl_sampler * GetSampler(struct vlc_gl_filter *filter) { @@ -257,9 +285,53 @@ vlc_gl_filters_Append(struct vlc_gl_filters *filters, const char *name, int vlc_gl_filters_InitFramebuffers(struct vlc_gl_filters *filters) { - struct vlc_gl_filter_priv *priv; + struct vlc_gl_filter_priv *priv = NULL; + struct vlc_gl_filter_priv *subfilter_priv; + vlc_list_foreach(priv, &filters->list, node) { + /* Compute the highest msaa_level among the filter and its subfilters */ + unsigned msaa_level = 0; + if (filters->api->supports_multisample) + { + msaa_level = priv->filter.config.msaa_level; + vlc_list_foreach(subfilter_priv, &priv->blend_subfilters, node) + { + if (subfilter_priv->filter.config.msaa_level > msaa_level) + msaa_level = subfilter_priv->filter.config.msaa_level; + } + } + + /* Update the actual msaa_level used to create the MSAA framebuffer */ + priv->filter.config.msaa_level = msaa_level; + /* Also update the actual msaa_level for subfilters, just for info */ + vlc_list_foreach(subfilter_priv, &priv->blend_subfilters, node) + subfilter_priv->filter.config.msaa_level = msaa_level; + } + + /* "priv" is the last filter */ + assert(priv); /* There is at least one filter */ + + if (priv->filter.config.msaa_level) + { + /* Resolving multisampling to the default framebuffer might fail, + * because its format may be different. So insert a "draw" filter. */ + struct vlc_gl_filter *draw = + vlc_gl_filters_Append(filters, "draw", NULL); + if (!draw) + return VLC_EGENERIC; + } + + vlc_list_foreach(priv, &filters->list, node) + { + unsigned msaa_level = priv->filter.config.msaa_level; + if (msaa_level) + { + int ret = InitFramebufferMSAA(priv, msaa_level); + if (ret != VLC_SUCCESS) + return ret; + } + bool is_last = vlc_list_is_last(&priv->node, &filters->list); if (!is_last) { @@ -327,8 +399,13 @@ vlc_gl_filters_Draw(struct vlc_gl_filters *filters) } } - GLuint draw_fb = priv->has_framebuffer_out ? priv->framebuffer_out - : draw_framebuffer; + unsigned msaa_level = priv->filter.config.msaa_level; + GLuint draw_fb; + if (msaa_level) + draw_fb = priv->framebuffer_msaa; + else + draw_fb = priv->has_framebuffer_out ? priv->framebuffer_out + : draw_framebuffer; vt->BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_fb); @@ -359,6 +436,23 @@ vlc_gl_filters_Draw(struct vlc_gl_filters *filters) if (ret != VLC_SUCCESS) return ret; } + + if (filter->config.msaa_level) + { + /* Never resolve multisampling to the default framebuffer */ + assert(priv->has_framebuffer_out); + assert(priv->framebuffer_out != draw_framebuffer); + + /* Resolve the MSAA into the target framebuffer */ + vt->BindFramebuffer(GL_READ_FRAMEBUFFER, priv->framebuffer_msaa); + vt->BindFramebuffer(GL_DRAW_FRAMEBUFFER, priv->framebuffer_out); + + GLint width = priv->size_out.width; + GLint height = priv->size_out.height; + vt->BlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } } return VLC_SUCCESS; diff --git a/modules/video_output/opengl/gl_api.c b/modules/video_output/opengl/gl_api.c index 68c42cc6d4..1264dde2a1 100644 --- a/modules/video_output/opengl/gl_api.c +++ b/modules/video_output/opengl/gl_api.c @@ -151,6 +151,18 @@ vlc_gl_api_Init(struct vlc_gl_api *api, vlc_gl_t *gl) return VLC_EGENERIC; } + GL_ASSERT_NOERROR(&api->vt); + GLint version; + api->vt.GetIntegerv(GL_MAJOR_VERSION, &version); + GLenum error = api->vt.GetError(); + + /* OpenGL >= 3.0: + * https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glRenderbufferStorageMultisample.xhtml + * OpenGL ES >= 3.0: + * https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glRenderbufferStorageMultisample.xhtml + */ + api->supports_multisample = version >= 3 && error == GL_NO_ERROR; + #ifdef USE_OPENGL_ES2 api->is_gles = true; /* OpenGL ES 2 includes support for non-power of 2 textures by specification diff --git a/modules/video_output/opengl/gl_api.h b/modules/video_output/opengl/gl_api.h index 2ddae33178..49b46ae110 100644 --- a/modules/video_output/opengl/gl_api.h +++ b/modules/video_output/opengl/gl_api.h @@ -43,6 +43,9 @@ struct vlc_gl_api { /* Non-power-of-2 texture size support */ bool supports_npot; + + /* Multisampling for anti-aliasing */ + bool supports_multisample; }; int diff --git a/modules/video_output/opengl/gl_common.h b/modules/video_output/opengl/gl_common.h index 81ec807400..60f0873442 100644 --- a/modules/video_output/opengl/gl_common.h +++ b/modules/video_output/opengl/gl_common.h @@ -51,6 +51,14 @@ #define VLCGL_PICTURE_MAX 128 +#if !defined(GL_MAJOR_VERSION) +# define GL_MAJOR_VERSION 0x821B +#endif + +#if !defined(GL_MINOR_VERSION) +# define GL_MINOR_VERSION 0x821C +#endif + #ifndef GL_TEXTURE_RECTANGLE # define GL_TEXTURE_RECTANGLE 0x84F5 #endif _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
