[vlc-devel] [PATCH v4 06/20] opengl: add "direct" sampler

Romain Vimont rom1v at videolabs.io
Tue Jul 7 12:33:49 CEST 2020


A sampler exposes the VLC input picture via a GLSL function
vlc_texture().

Until now, the input picture always came from the interop (initialized
from a picture_t). With filters, the input picture may now be the output
picture of the previous filter, already stored in a OpenGL texture.

In that case, we need a sampler able to expose this input via
vlc_texture().

Co-authored-by: Alexandre Janniaux <ajanni at videolabs.io>
---
 modules/video_output/opengl/sampler.c      | 105 ++++++++++++++++++++-
 modules/video_output/opengl/sampler_priv.h |  42 ++++++++-
 modules/video_output/opengl/vout_helper.c  |   4 +-
 3 files changed, 141 insertions(+), 10 deletions(-)

diff --git a/modules/video_output/opengl/sampler.c b/modules/video_output/opengl/sampler.c
index 219cac3aec..8588cd883c 100644
--- a/modules/video_output/opengl/sampler.c
+++ b/modules/video_output/opengl/sampler.c
@@ -81,7 +81,16 @@ struct vlc_gl_sampler_priv {
         unsigned int i_visible_height;
     } last_source;
 
+    /* A sampler supports 2 kinds of input.
+     *  - created with _NewFromInterop(), it receives input pictures from VLC
+     *    (picture_t) via _UpdatePicture();
+     *  - created with _NewFromTexture2D() (interop is NULL), it receives
+     *    directly OpenGL textures via _UpdateTexture().
+     */
     struct vlc_gl_interop *interop;
+
+    /* Only used for "direct" sampler (when interop == NULL) */
+    video_format_t direct_fmt;
 };
 
 #define PRIV(sampler) container_of(sampler, struct vlc_gl_sampler_priv, sampler)
@@ -936,7 +945,7 @@ opengl_fragment_shader_init(struct vlc_gl_sampler *sampler, GLenum tex_target,
 }
 
 struct vlc_gl_sampler *
-vlc_gl_sampler_New(struct vlc_gl_interop *interop)
+vlc_gl_sampler_NewFromInterop(struct vlc_gl_interop *interop)
 {
     struct vlc_gl_sampler_priv *priv = calloc(1, sizeof(*priv));
     if (!priv)
@@ -1026,16 +1035,86 @@ vlc_gl_sampler_New(struct vlc_gl_interop *interop)
     return sampler;
 }
 
+
+static void
+sampler_direct_fetch_locations(struct vlc_gl_sampler *sampler, GLuint program)
+{
+    struct vlc_gl_sampler_priv *priv = PRIV(sampler);
+    const opengl_vtable_t *vt = priv->vt;
+
+    priv->uloc.Textures[0] =
+        vt->GetUniformLocation(program, "vlc_input_texture");
+    assert(priv->uloc.Textures[0] != -1);
+}
+
+static void
+sampler_direct_load(const struct vlc_gl_sampler *sampler)
+{
+    struct vlc_gl_sampler_priv *priv = PRIV(sampler);
+    const opengl_vtable_t *vt = priv->vt;
+
+    GLuint texture = priv->textures[0];
+
+    vt->ActiveTexture(GL_TEXTURE0);
+    vt->BindTexture(GL_TEXTURE_2D, texture);
+    vt->Uniform1i(priv->uloc.Textures[0], 0);
+}
+
+struct vlc_gl_sampler *
+vlc_gl_sampler_NewFromTexture2D(struct vlc_gl_t *gl,
+                                const struct vlc_gl_api *api,
+                                const video_format_t *fmt)
+{
+    struct vlc_gl_sampler_priv *priv = calloc(1, sizeof(*priv));
+    if (!priv)
+        return NULL;
+
+    struct vlc_gl_sampler *sampler = &priv->sampler;
+
+    priv->interop = NULL;
+    priv->gl = gl;
+    priv->vt = &api->vt;
+
+    sampler->fmt = *fmt;
+    /* this is the only allocated field, and we don't need it */
+    sampler->fmt.p_palette = NULL;
+
+    static const char *const SHADER_BODY =
+        "uniform sampler2D vlc_input_texture;\n"
+        "vec4 vlc_texture(vec2 pic_coords) {\n"
+        "  return texture2D(vlc_input_texture, pic_coords);\n"
+        "}\n";
+
+    sampler->shader.body = strdup(SHADER_BODY);
+    if (!sampler->shader.body)
+    {
+        free(priv);
+        return NULL;
+    }
+
+    /* No extension required */
+    sampler->shader.extensions = NULL;
+
+    static const struct vlc_gl_sampler_ops ops = {
+        .fetch_locations = sampler_direct_fetch_locations,
+        .load = sampler_direct_load,
+    };
+    sampler->ops = &ops;
+
+    return sampler;
+}
+
 void
 vlc_gl_sampler_Delete(struct vlc_gl_sampler *sampler)
 {
     struct vlc_gl_sampler_priv *priv = PRIV(sampler);
 
     struct vlc_gl_interop *interop = priv->interop;
-    const opengl_vtable_t *vt = interop->vt;
-
-    if (!interop->handle_texs_gen)
+    if (interop && !interop->handle_texs_gen)
+    {
+        const opengl_vtable_t *vt = interop->vt;
         vt->DeleteTextures(interop->tex_count, priv->textures);
+    }
 
 #ifdef HAVE_LIBPLACEBO
     FREENULL(priv->uloc.pl_vars);
@@ -1050,11 +1129,13 @@ vlc_gl_sampler_Delete(struct vlc_gl_sampler *sampler)
 }
 
 int
-vlc_gl_sampler_Update(struct vlc_gl_sampler *sampler, picture_t *picture)
+vlc_gl_sampler_UpdatePicture(struct vlc_gl_sampler *sampler, picture_t *picture)
 {
     struct vlc_gl_sampler_priv *priv = PRIV(sampler);
 
     const struct vlc_gl_interop *interop = priv->interop;
+    assert(interop);
+
     const video_format_t *source = &picture->format;
 
     if (source->i_x_offset != priv->last_source.i_x_offset
@@ -1142,3 +1223,17 @@ vlc_gl_sampler_Update(struct vlc_gl_sampler *sampler, picture_t *picture)
                                          priv->tex_widths, priv->tex_heights,
                                          picture, NULL);
 }
+
+int
+vlc_gl_sampler_UpdateTexture(struct vlc_gl_sampler *sampler, GLuint texture,
+                             GLsizei tex_width, GLsizei tex_height)
+{
+    struct vlc_gl_sampler_priv *priv = PRIV(sampler);
+    assert(!priv->interop);
+
+    priv->textures[0] = texture;
+    priv->tex_widths[0] = tex_width;
+    priv->tex_heights[0] = tex_height;
+
+    return VLC_SUCCESS;
+}
diff --git a/modules/video_output/opengl/sampler_priv.h b/modules/video_output/opengl/sampler_priv.h
index ccd96b60c4..e6c977d467 100644
--- a/modules/video_output/opengl/sampler_priv.h
+++ b/modules/video_output/opengl/sampler_priv.h
@@ -23,17 +23,36 @@
 
 #include <vlc_common.h>
 
+#include "gl_api.h"
 #include "sampler.h"
 
 struct vlc_gl_interop;
 
 /**
- * Create a new sampler
+ * Create a new sampler from an interop
+ *
+ * It receives input pictures from `picture_t`, and uses the interop to
+ * uploaded them to OpenGL textures.
  *
  * \param interop the interop
  */
 struct vlc_gl_sampler *
-vlc_gl_sampler_New(struct vlc_gl_interop *interop);
+vlc_gl_sampler_NewFromInterop(struct vlc_gl_interop *interop);
+
+/**
+ * Create a new direct sampler
+ *
+ * It receives input textures directly (typically the output of a previous
+ * filter), with target GL_TEXTURE_2D.
+ *
+ * \param gl the OpenGL context
+ * \param api the OpenGL API
+ * \param fmt the input format
+ */
+struct vlc_gl_sampler *
+vlc_gl_sampler_NewFromTexture2D(struct vlc_gl_t *gl,
+                                const struct vlc_gl_api *api,
+                                const video_format_t *fmt);
 
 /**
  * Delete a sampler
@@ -48,10 +67,27 @@ vlc_gl_sampler_Delete(struct vlc_gl_sampler *sampler);
  *
  * This changes the current input picture, available from the fragment shader.
  *
+ * Warning: only call on sampler created by vlc_gl_sampler_NewFromInterop().
+ *
  * \param sampler the sampler
  * \param picture the new picture
  */
 int
-vlc_gl_sampler_Update(struct vlc_gl_sampler *sampler, picture_t *picture);
+vlc_gl_sampler_UpdatePicture(struct vlc_gl_sampler *sampler,
+                             picture_t *picture);
+
+/**
+ * Update the input texture
+ *
+ * Warning: only call on sampler created by vlc_gl_sampler_NewFromTexture2D().
+ *
+ * \param sampler the sampler
+ * \param texture the new texture, with target GL_TEXTURE_2D
+ * \param tex_width the texture width
+ * \param tex_height the texture height
+ */
+int
+vlc_gl_sampler_UpdateTexture(struct vlc_gl_sampler *sampler, GLuint texture,
+                             GLsizei tex_width, GLsizei tex_height);
 
 #endif
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index 8eed276d54..726bff56bd 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -144,7 +144,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
         goto free_vgl;
     }
 
-    vgl->sampler = vlc_gl_sampler_New(vgl->interop);
+    vgl->sampler = vlc_gl_sampler_NewFromInterop(vgl->interop);
     if (!vgl->sampler)
     {
         msg_Err(gl, "Could not create sampler");
@@ -266,7 +266,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
 {
     GL_ASSERT_NOERROR(&vgl->api.vt);
 
-    int ret = vlc_gl_sampler_Update(vgl->sampler, picture);
+    int ret = vlc_gl_sampler_UpdatePicture(vgl->sampler, picture);
     if (ret != VLC_SUCCESS)
         return ret;
 
-- 
2.27.0



More information about the vlc-devel mailing list