[vlc-devel] [PATCH] opengl: use common fragment shader for Android

Romain Vimont rom1v at videolabs.io
Thu Dec 19 11:32:19 CET 2019


The OpenGL converter for Android used its own minimal fragment shader,
instead of the common one used by all the other converters.

This stemmed from the fact that on each texture update, Android provides
a transform matrix to apply in order to retrieve the correct texture
coordinates.

Adapt the common fragment shader to accept a transform matrix provided
by the converter, and make the Android converter use it.
---
 modules/video_output/opengl/converter.h       | 20 +++++++
 .../video_output/opengl/converter_android.c   | 54 +++----------------
 .../video_output/opengl/fragment_shaders.c    | 12 ++++-
 modules/video_output/opengl/gl_common.h       |  3 ++
 modules/video_output/opengl/vout_helper.c     | 22 +++++++-
 5 files changed, 63 insertions(+), 48 deletions(-)

diff --git a/modules/video_output/opengl/converter.h b/modules/video_output/opengl/converter.h
index a3aba06621..211d7e07c4 100644
--- a/modules/video_output/opengl/converter.h
+++ b/modules/video_output/opengl/converter.h
@@ -196,6 +196,26 @@ struct opengl_tex_converter_t
     void (*pf_prepare_shader)(const opengl_tex_converter_t *tc,
                               const GLsizei *tex_width, const GLsizei *tex_height,
                               float alpha);
+
+    /**
+     * Callback to retrieve the transform matrix to apply to texture coordinates
+     *
+     * This function pointer can be NULL. If it is set, it may return NULL.
+     *
+     * Otherwise, it must return a 4x4 matrix, as an array of 16 floats in
+     * column-major order.
+     *
+     * This transform matrix maps 2D homogeneous texture coordinates of the
+     * form (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the
+     * texture coordinate that should be used to sample that location from the
+     * texture.
+     *
+     * The returned pointer is owned by the converter module, and must not be
+     * freed before the module is closed.
+     *
+     * \param tc OpenGL tex converter
+     */
+    const float *(*pf_get_transform_matrix)(const opengl_tex_converter_t *tc);
 };
 
 /**
diff --git a/modules/video_output/opengl/converter_android.c b/modules/video_output/opengl/converter_android.c
index 6fb0a4e631..6468068640 100644
--- a/modules/video_output/opengl/converter_android.c
+++ b/modules/video_output/opengl/converter_android.c
@@ -35,10 +35,6 @@ struct priv
     AWindowHandler *awh;
     const float *transform_mtx;
     bool stex_attached;
-
-    struct {
-        GLint uSTMatrix;
-    } uloc;
 };
 
 static int
@@ -87,24 +83,11 @@ tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
     return VLC_SUCCESS;
 }
 
-static int
-tc_anop_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
+static const float *
+tc_get_transform_matrix(const opengl_tex_converter_t *tc)
 {
     struct priv *priv = tc->priv;
-    priv->uloc.uSTMatrix = tc->vt->GetUniformLocation(program, "uSTMatrix");
-    return priv->uloc.uSTMatrix != -1 ? VLC_SUCCESS : VLC_EGENERIC;
-}
-
-static void
-tc_anop_prepare_shader(const opengl_tex_converter_t *tc,
-                       const GLsizei *tex_width, const GLsizei *tex_height,
-                       float alpha)
-{
-    (void) tex_width; (void) tex_height; (void) alpha;
-    struct priv *priv = tc->priv;
-    if (priv->transform_mtx != NULL)
-        tc->vt->UniformMatrix4fv(priv->uloc.uSTMatrix, 1, GL_FALSE,
-                                  priv->transform_mtx);
+    return priv->transform_mtx;
 }
 
 static void
@@ -147,13 +130,7 @@ Open(vlc_object_t *obj)
 
     tc->pf_allocate_textures = tc_anop_allocate_textures;
     tc->pf_update         = tc_anop_update;
-    tc->pf_fetch_locations = tc_anop_fetch_locations;
-    tc->pf_prepare_shader = tc_anop_prepare_shader;
-
-    tc->tex_count = 1;
-    tc->texs[0] = (struct opengl_tex_cfg) { { 1, 1 }, { 1, 1 }, 0, 0, 0 };
-
-    tc->tex_target   = GL_TEXTURE_EXTERNAL_OES;
+    tc->pf_get_transform_matrix = tc_get_transform_matrix;
 
     /* The transform Matrix (uSTMatrix) given by the SurfaceTexture is not
      * using the same origin than us. Ask the caller to rotate textures
@@ -186,29 +163,14 @@ Open(vlc_object_t *obj)
             break;
     }
 
-    static const char *template =
-        "#version %u\n"
-        "#extension GL_OES_EGL_image_external : require\n"
-        "%s" /* precision */
-        "varying vec2 TexCoord0;"
-        "uniform samplerExternalOES sTexture;"
-        "uniform mat4 uSTMatrix;"
-        "void main()"
-        "{ "
-        "  gl_FragColor = texture2D(sTexture, (uSTMatrix * vec4(TexCoord0, 1, 1)).xy).rgba;"
-        "}";
-
-    char *code;
-    if (asprintf(&code, template, tc->glsl_version, tc->glsl_precision_header) < 0)
+    tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_EXTERNAL_OES,
+                                              VLC_CODEC_RGB32,
+                                              COLOR_SPACE_UNDEF);
+    if (!tc->fshader)
     {
         free(tc->priv);
         return VLC_EGENERIC;
     }
-    GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER);
-    tc->vt->ShaderSource(fragment_shader, 1, (const char **) &code, NULL);
-    tc->vt->CompileShader(fragment_shader);
-    tc->fshader = fragment_shader;
-    free(code);
 
     return VLC_SUCCESS;
 }
diff --git a/modules/video_output/opengl/fragment_shaders.c b/modules/video_output/opengl/fragment_shaders.c
index 9694b52d63..bd9978fda4 100644
--- a/modules/video_output/opengl/fragment_shaders.c
+++ b/modules/video_output/opengl/fragment_shaders.c
@@ -524,6 +524,11 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
     const char *sampler, *lookup, *coord_name;
     switch (tex_target)
     {
+        case GL_TEXTURE_EXTERNAL_OES:
+            sampler = "samplerExternalOES";
+            lookup = "texture2D";
+            coord_name = "TexCoord";
+            break;
         case GL_TEXTURE_2D:
             sampler = "sampler2D";
             lookup  = "texture2D";
@@ -545,7 +550,12 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
 #define ADD(x) vlc_memstream_puts(&ms, x)
 #define ADDF(x, ...) vlc_memstream_printf(&ms, x, ##__VA_ARGS__)
 
-    ADDF("#version %u\n%s", tc->glsl_version, tc->glsl_precision_header);
+    ADDF("#version %u\n", tc->glsl_version);
+
+    if (tex_target == GL_TEXTURE_EXTERNAL_OES)
+        ADDF("#extension GL_OES_EGL_image_external : require\n");
+
+    ADDF("%s", tc->glsl_precision_header);
 
     for (unsigned i = 0; i < tc->tex_count; ++i)
         ADDF("uniform %s Texture%u;\n"
diff --git a/modules/video_output/opengl/gl_common.h b/modules/video_output/opengl/gl_common.h
index 11c109a7a7..fb14ae3b66 100644
--- a/modules/video_output/opengl/gl_common.h
+++ b/modules/video_output/opengl/gl_common.h
@@ -52,6 +52,9 @@
 #ifndef GL_TEXTURE_RECTANGLE
 # define GL_TEXTURE_RECTANGLE 0x84F5
 #endif
+#ifndef GL_TEXTURE_EXTERNAL_OES
+# define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#endif
 
 #ifndef APIENTRY
 # define APIENTRY
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index 8e692eae5a..fae2ebd15e 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -49,6 +49,12 @@
 
 #define SPHERE_RADIUS 1.f
 
+static const GLfloat MATRIX_IDENTITY[16] =
+    { 1, 0, 0, 0,
+      0, 1, 0, 0,
+      0, 0, 1, 0,
+      0, 0, 0, 1 };
+
 /* FIXME: GL_ASSERT_NOERROR disabled for now because:
  * Proper GL error handling need to be implemented
  * glClear(GL_COLOR_BUFFER_BIT) throws a GL_INVALID_FRAMEBUFFER_OPERATION on macOS
@@ -105,6 +111,7 @@ struct prgm
     } var;
 
     struct { /* UniformLocation */
+        GLint TransformMatrix;
         GLint OrientationMatrix;
         GLint ProjectionMatrix;
         GLint ViewMatrix;
@@ -315,12 +322,13 @@ static GLuint BuildVertexShader(const opengl_tex_converter_t *tc,
         "attribute vec4 MultiTexCoord0;\n"
         "%s%s"
         "attribute vec3 VertexPosition;\n"
+        "uniform mat4 TransformMatrix;\n"
         "uniform mat4 OrientationMatrix;\n"
         "uniform mat4 ProjectionMatrix;\n"
         "uniform mat4 ZoomMatrix;\n"
         "uniform mat4 ViewMatrix;\n"
         "void main() {\n"
-        " TexCoord0 = vec4(OrientationMatrix * MultiTexCoord0).st;\n"
+        " TexCoord0 = vec4(TransformMatrix * OrientationMatrix * MultiTexCoord0).st;\n"
         "%s%s"
         " gl_Position = ProjectionMatrix * ZoomMatrix * ViewMatrix\n"
         "               * vec4(VertexPosition, 1.0);\n"
@@ -463,6 +471,7 @@ opengl_link_program(struct prgm *prgm)
 } while (0)
 #define GET_ULOC(x, str) GET_LOC(Uniform, prgm->uloc.x, str)
 #define GET_ALOC(x, str) GET_LOC(Attrib, prgm->aloc.x, str)
+    GET_ULOC(TransformMatrix, "TransformMatrix");
     GET_ULOC(OrientationMatrix, "OrientationMatrix");
     GET_ULOC(ProjectionMatrix, "ProjectionMatrix");
     GET_ULOC(ViewMatrix, "ViewMatrix");
@@ -533,6 +542,7 @@ opengl_init_program(vout_display_opengl_t *vgl, vlc_video_context *context,
     tc->vt = &vgl->vt;
     tc->b_dump_shaders = b_dump_shaders;
     tc->pf_fragment_shader_init = opengl_fragment_shader_init_impl;
+    tc->pf_get_transform_matrix = NULL;
     tc->glexts = glexts;
 #if defined(USE_OPENGL_ES2)
     tc->is_gles = true;
@@ -1498,6 +1508,13 @@ static void DrawWithShaders(vout_display_opengl_t *vgl, struct prgm *prgm)
     vgl->vt.EnableVertexAttribArray(prgm->aloc.VertexPosition);
     vgl->vt.VertexAttribPointer(prgm->aloc.VertexPosition, 3, GL_FLOAT, 0, 0, 0);
 
+    const GLfloat *tm = tc->pf_get_transform_matrix
+                      ? tc->pf_get_transform_matrix(tc) : NULL;
+    if (!tm)
+        tm = MATRIX_IDENTITY;
+
+    vgl->vt.UniformMatrix4fv(prgm->uloc.TransformMatrix, 1, GL_FALSE, tm);
+
     vgl->vt.UniformMatrix4fv(prgm->uloc.OrientationMatrix, 1, GL_FALSE,
                              prgm->var.OrientationMatrix);
     vgl->vt.UniformMatrix4fv(prgm->uloc.ProjectionMatrix, 1, GL_FALSE,
@@ -1677,6 +1694,9 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
         vgl->vt.VertexAttribPointer(prgm->aloc.VertexPosition, 2, GL_FLOAT,
                                     0, 0, 0);
 
+        vgl->vt.UniformMatrix4fv(prgm->uloc.TransformMatrix, 1, GL_FALSE,
+                                 MATRIX_IDENTITY);
+
         vgl->vt.UniformMatrix4fv(prgm->uloc.OrientationMatrix, 1, GL_FALSE,
                                  prgm->var.OrientationMatrix);
         vgl->vt.UniformMatrix4fv(prgm->uloc.ProjectionMatrix, 1, GL_FALSE,
-- 
2.24.1



More information about the vlc-devel mailing list