[vlc-devel] [PATCH 20/27] opengl: enable multisampling
Romain Vimont
rom1v at videolabs.io
Mon Jun 29 17:24:25 CEST 2020
On Mon, Jun 29, 2020 at 04:57:18PM +0200, Alexandre Janniaux wrote:
> On Thu, Jun 25, 2020 at 02:23:07PM +0200, Romain Vimont wrote:
> > Enable multisampling anti-aliasing:
> > - render to an intermediate multisample renderbuffer;
> > - resolve it to the output framebuffer.
> >
> > Co-authored-by: Alexandre Janniaux <ajanni at videolabs.io>
> > ---
> > 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 | 16 ++++
> > modules/video_output/opengl/gl_api.h | 3 +
> > 6 files changed, 141 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 70710d69af..f22478893b 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)
> > {
> > @@ -256,9 +284,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)
> > {
> > @@ -326,8 +398,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);
> >
> > @@ -358,6 +435,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..46a27384fd 100644
> > --- a/modules/video_output/opengl/gl_api.c
> > +++ b/modules/video_output/opengl/gl_api.c
> > @@ -151,6 +151,22 @@ vlc_gl_api_Init(struct vlc_gl_api *api, vlc_gl_t *gl)
> > return VLC_EGENERIC;
> > }
> >
> > + const char *version = (const char *) api->vt.GetString(GL_VERSION);
> > +#ifdef USE_OPENGL_ES2
> > +# define PREFIX "OpenGL ES "
> > + /* starts with "OpenGL ES " */
> > + assert(!strncmp(version, PREFIX, sizeof(PREFIX) - 1));
> > + /* skip the prefix */
> > + version += sizeof(PREFIX) - 1;
> > +#endif
> > +
> > + /* 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 = strverscmp(version, "3.0") >= 0;
>
> Might be replaced and simplified into
>
> ```
> GL_ASSERT_NO_ERROR(vt);
> GLint version;
> vt->GetIntegerv(GL_MAJOR_VERSION, &version);
GL_MAJOR_VERSION is available only for OpenGL >= 3.
Note that it could be a hacky way to detect OpenGL >= 3 ;)
> GLenum error = vt->GetError();
> 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
> > --
> > 2.27.0
> >
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list