[vlc-devel] [PATCH v3 20/22] opengl: enable multisampling
Romain Vimont
rom1v at videolabs.io
Mon Jul 6 12:47:13 CEST 2020
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 | 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
--
2.27.0
More information about the vlc-devel
mailing list