[vlc-devel] [PATCH 1/4] vgl: provide a module to allow rendering in a user defined opengl context

Pierre Lamot pierre at videolabs.io
Tue Jul 3 14:38:34 CEST 2018


  This module aims to provide the same kind of functionnality as vmem but for
  opengl rendering.

  Users will have to provide different callbacks:

  * vgl-create-cb to create texture and other opengl resources
  * vgl-destroy-cb to release resources created by vgl-create-cb
  * vgl-render-cb that will be called before and after rending the current frame
  * vgl-make-current-cb to enter/leave the opengl context
  * vgl-get-proc-address-cb to provide opengl functions

  Note that users will have to ensure synchronisation on their side since
  VLC will run and render OpenGL in its own thread.
---
 include/vlc_opengl.h                      |   9 ++
 modules/video_output/Makefile.am          |   2 +
 modules/video_output/opengl/vout_helper.c |  59 +++++++--
 modules/video_output/vgl.c                | 145 ++++++++++++++++++++++
 4 files changed, 203 insertions(+), 12 deletions(-)
 create mode 100644 modules/video_output/vgl.c

diff --git a/include/vlc_opengl.h b/include/vlc_opengl.h
index 57a1e71c3b..f9329c7675 100644
--- a/include/vlc_opengl.h
+++ b/include/vlc_opengl.h
@@ -55,6 +55,7 @@ struct vlc_gl_t
         VLC_GL_EXT_DEFAULT,
         VLC_GL_EXT_EGL,
         VLC_GL_EXT_WGL,
+        VLC_GL_EXT_VGL,
     } ext;
 
     union {
@@ -74,6 +75,14 @@ struct vlc_gl_t
         {
             const char *(*getExtensionsString)(vlc_gl_t *);
         } wgl;
+        /* if ext == VLC_GL_EXT_VGL */
+        struct
+        {
+            void (*createCb)(void *p_opaque, size_t width, size_t height);
+            void (*destroyCb)(void *p_opaque);
+            void (*renderCb)(void *p_opaque, bool enter);
+            void *p_opaque;
+        } vgl;
     };
 };
 
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 3013e3fd1d..9df738fff3 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -454,10 +454,12 @@ libvdummy_plugin_la_SOURCES = video_output/vdummy.c
 libvmem_plugin_la_SOURCES = video_output/vmem.c
 libwdummy_plugin_la_SOURCES = video_output/wdummy.c
 libyuv_plugin_la_SOURCES = video_output/yuv.c
+libvgl_plugin_la_SOURCES = video_output/vgl.c
 
 vout_LTLIBRARIES += \
 	libflaschen_plugin.la \
 	libvdummy_plugin.la \
 	libvmem_plugin.la \
 	libwdummy_plugin.la \
+	libvgl_plugin.la \
 	libyuv_plugin.la
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index 33f738f579..3b8d599777 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -979,6 +979,11 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     }
 
     GL_ASSERT_NOERROR();
+
+    if (vgl->gl->ext == VLC_GL_EXT_VGL &&  vgl->gl->vgl.createCb) {
+        vgl->gl->vgl.createCb(vgl->gl->vgl.p_opaque, vgl->fmt.i_visible_width, vgl->fmt.i_visible_height);
+    }
+
     return vgl;
 }
 
@@ -998,6 +1003,10 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
     opengl_deinit_program(vgl, vgl->prgm);
     opengl_deinit_program(vgl, vgl->sub_prgm);
 
+    if (vgl->gl->ext == VLC_GL_EXT_VGL && vgl->gl->vgl.destroyCb) {
+        vgl->gl->vgl.destroyCb(vgl->gl->vgl.p_opaque);
+    }
+
     vgl->vt.DeleteBuffers(1, &vgl->vertex_buffer_object);
     vgl->vt.DeleteBuffers(1, &vgl->index_buffer_object);
     vgl->vt.DeleteBuffers(main_tex_count, vgl->texture_buffer_object);
@@ -1656,16 +1665,8 @@ static void TextureCropForStereo(vout_display_opengl_t *vgl,
     }
 }
 
-int vout_display_opengl_Display(vout_display_opengl_t *vgl,
-                                const video_format_t *source)
+static int drawScene(vout_display_opengl_t *vgl,  const video_format_t *source)
 {
-    GL_ASSERT_NOERROR();
-
-    /* Why drawing here and not in Render()? Because this way, the
-       OpenGL providers can call vout_display_opengl_Display to force redraw.
-       Currently, the OS X provider uses it to get a smooth window resizing */
-    vgl->vt.Clear(GL_COLOR_BUFFER_BIT);
-
     vgl->vt.UseProgram(vgl->prgm->id);
 
     if (source->i_x_offset != vgl->last_source.i_x_offset
@@ -1791,11 +1792,45 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
     }
     vgl->vt.Disable(GL_BLEND);
 
-    /* Display */
-    vlc_gl_Swap(vgl->gl);
-
     GL_ASSERT_NOERROR();
 
     return VLC_SUCCESS;
 }
 
+
+int vout_display_opengl_Display(vout_display_opengl_t *vgl,
+                                const video_format_t *source)
+{
+    GL_ASSERT_NOERROR();
+
+    /* Why drawing here and not in Render()? Because this way, the
+       OpenGL providers can call vout_display_opengl_Display to force redraw.
+       Currently, the OS X provider uses it to get a smooth window resizing */
+    vgl->vt.ClearColor(0.0, 1.0, 0.0, 1.0);
+    if (vgl->gl->ext == VLC_GL_EXT_VGL && vgl->gl->vgl.renderCb != 0) {
+        // Draw scene into framebuffers.
+        vgl->vt.UseProgram(vgl->prgm->id);
+
+        vgl->vt.Viewport(0, 0, vgl->fmt.i_visible_width, vgl->fmt.i_visible_height);
+
+        // Framebuffer
+        vgl->gl->vgl.renderCb(vgl->gl->vgl.p_opaque, true);
+
+        vgl->vt.Clear(GL_COLOR_BUFFER_BIT);
+        drawScene(vgl, source);
+
+        vgl->gl->vgl.renderCb(vgl->gl->vgl.p_opaque, false);
+        // Exit framebuffer.
+    }
+    else
+    {
+        vgl->vt.Clear(GL_COLOR_BUFFER_BIT);
+        drawScene(vgl, source);
+        /* Display */
+        vlc_gl_Swap(vgl->gl);
+    }
+
+    GL_ASSERT_NOERROR();
+
+    return VLC_SUCCESS;
+}
diff --git a/modules/video_output/vgl.c b/modules/video_output/vgl.c
new file mode 100644
index 0000000000..7296ec50cb
--- /dev/null
+++ b/modules/video_output/vgl.c
@@ -0,0 +1,145 @@
+/*****************************************************************************
+ * vgl.c: virtual LibVLC OpenGL extension
+ *****************************************************************************
+ * Copyright (c) 2018 VLC authors and VideoLAN
+ *
+ * Authors: Pierre Lamot <pierre at videolabs.io>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout_display.h>
+#include <vlc_opengl.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open(vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+    set_shortname(N_("GL texture"))
+    set_description(N_("GL texture output"))
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VOUT)
+
+    set_capability("opengl", 0)
+    set_callbacks(Open, Close)
+    add_shortcut("vglmem")
+
+    add_submodule ()
+    set_capability ("opengl es2", 0)
+    set_callbacks (Open, Close)
+    add_shortcut ("vglmem")
+vlc_module_end()
+
+/*****************************************************************************
+ * Local prototypes.
+ *****************************************************************************/
+
+typedef bool (*makeCurrent_t)(void* opaque, bool);
+typedef void* (*getProcAddress_t)(void* opaque, const char *name);
+
+struct vout_display_sys_t
+{
+    vlc_gl_t              *gl;
+    makeCurrent_t p_makeCurrent_cb;
+    getProcAddress_t p_getProcAddress_cb;
+};
+
+static int           MakeCurrent(vlc_gl_t *gl);
+static void          ReleaseCurrent(vlc_gl_t *gl);
+static void         *OurGetProcAddress(vlc_gl_t *gl, const char *name);
+static void          SwapBuffers(vlc_gl_t *gl);
+
+
+#define SET_CALLBACK_ADDR(var, varname) \
+    do {                                                           \
+        var = var_InheritAddress(gl, varname);                     \
+        if (! var) {                                               \
+            msg_Err( gl, varname " address is missing" );          \
+            goto error;                                            \
+        }                                                          \
+    } while(0)
+
+
+static int Open(vlc_object_t *object)
+{
+    vlc_gl_t *gl = (vlc_gl_t *)object;
+    vout_display_sys_t *sys;
+
+    /* Allocate structure */
+    gl->sys = sys = calloc(1, sizeof(*sys));
+    if (!sys)
+        return VLC_ENOMEM;
+
+    SET_CALLBACK_ADDR(gl->vgl.createCb, "vgl-create-cb");
+    SET_CALLBACK_ADDR(gl->vgl.destroyCb, "vgl-destroy-cb");
+    SET_CALLBACK_ADDR(gl->vgl.renderCb, "vgl-render-cb");
+    SET_CALLBACK_ADDR(gl->vgl.p_opaque, "vgl-opaque");
+    SET_CALLBACK_ADDR(sys->p_makeCurrent_cb, "vgl-make-current-cb");
+    SET_CALLBACK_ADDR(sys->p_getProcAddress_cb, "vgl-get-proc-address-cb");
+
+    gl->ext = VLC_GL_EXT_VGL;
+    gl->makeCurrent = MakeCurrent;
+    gl->releaseCurrent = ReleaseCurrent;
+    gl->resize = NULL;
+    gl->swap = SwapBuffers;
+    gl->getProcAddress = OurGetProcAddress;
+    return VLC_SUCCESS;
+
+error:
+    Close(object);
+    return VLC_EGENERIC;
+}
+
+#undef SET_CALLBACK_ADDR
+
+static void Close(vlc_object_t *object)
+{
+    vlc_gl_t *gl = (vlc_gl_t *)object;
+    vout_display_sys_t *sys = gl->sys;
+    free(sys);
+}
+
+static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
+{
+    vout_display_sys_t *sys = gl->sys;
+    return sys->p_getProcAddress_cb(gl->vgl.p_opaque, name);
+}
+
+static int MakeCurrent(vlc_gl_t *gl)
+{
+    vout_display_sys_t *sys = gl->sys;
+    bool success = sys->p_makeCurrent_cb(gl->vgl.p_opaque, true);
+    return success ? VLC_SUCCESS : VLC_EGENERIC;
+}
+
+static void ReleaseCurrent(vlc_gl_t *gl)
+{
+    vout_display_sys_t *sys = gl->sys;
+    sys->p_makeCurrent_cb(gl->vgl.p_opaque, false);
+}
+
+static void SwapBuffers(vlc_gl_t * gl)
+{
+    VLC_UNUSED(gl);
+    /* swap won't be called */
+}
-- 
2.17.1



More information about the vlc-devel mailing list