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

zhilizhao quinkblack at foxmail.com
Thu Dec 19 13:15:23 CET 2019


Hi Romain,

> On Dec 19, 2019, at 6:32 PM, Romain Vimont <rom1v at videolabs.io> wrote:
> 
> 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”

TransformMatrix requires the texture coordinate has the form of (s, t, 0, 1). Does the condition satisfied in this case?

>         "%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
> 
> _______________________________________________
> 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