[vlc-devel] [PATCH 02/18] opengl: extract importer from converter

Thomas Guillem thomas at gllm.fr
Mon Dec 23 11:40:34 CET 2019



On Fri, Dec 20, 2019, at 15:48, Romain Vimont wrote:
> Extract fields specific to texture importer into a separate structure.
> For now, it is still embedded in opengl_tex_converter_t.
> ---
>  modules/video_output/opengl/converter.h       | 105 +----------
>  .../video_output/opengl/converter_android.c   |  62 ++++---
>  modules/video_output/opengl/converter_sw.c    | 136 ++++++++-------
>  modules/video_output/opengl/converter_vaapi.c |  92 +++++-----
>  modules/video_output/opengl/converter_vdpau.c |  41 +++--
>  .../video_output/opengl/fragment_shaders.c    |  71 ++++----
>  modules/video_output/opengl/importer.h        | 150 ++++++++++++++++
>  modules/video_output/opengl/vout_helper.c     | 165 ++++++++++--------
>  8 files changed, 467 insertions(+), 355 deletions(-)
>  create mode 100644 modules/video_output/opengl/importer.h
> 
> diff --git a/modules/video_output/opengl/converter.h 
> b/modules/video_output/opengl/converter.h
> index 211d7e07c4..aa6649c816 100644
> --- a/modules/video_output/opengl/converter.h
> +++ b/modules/video_output/opengl/converter.h
> @@ -27,6 +27,7 @@
>  #include <vlc_picture_pool.h>
>  #include <vlc_plugin.h>
>  #include "gl_common.h"
> +#include "importer.h"

I would prefer a name like "interop".
>  
>  struct pl_context;
>  struct pl_shader;
> @@ -47,9 +48,6 @@ struct opengl_tex_converter_t
>      /* Pointer to object gl, set by the caller */
>      vlc_gl_t *gl;
>  
> -    /* Pointer to decoder video context, set by the caller (can be NULL) */
> -    vlc_video_context *vctx;
> -
>      /* libplacebo context, created by the caller (optional) */
>      struct pl_context *pl_ctx;
>  
> @@ -64,45 +62,16 @@ struct opengl_tex_converter_t
>      GLuint (*pf_fragment_shader_init)(opengl_tex_converter_t *, GLenum,
>                                        vlc_fourcc_t, video_color_space_t);
>  
> -    /* Available gl extensions (from GL_EXTENSIONS) */
> -    const char *glexts;
> -
> -    /* True if the current API is OpenGL ES, set by the caller */
> -    bool is_gles;
>      /* GLSL version, set by the caller. 100 for GLSL ES, 120 for 
> desktop GLSL */
>      unsigned glsl_version;
>      /* Precision header, set by the caller. In OpenGLES, the fragment 
> language
>       * has no default precision qualifier for floating point types. */
>      const char *glsl_precision_header;
>  
> -    /* Can only be changed from the module open function */
> -    video_format_t fmt;
> -
>      /* Fragment shader, must be set from the module open function. It will be
>       * deleted by the caller. */
>      GLuint fshader;
>  
> -    /* Number of textures, cannot be 0 */
> -    unsigned tex_count;
> -
> -    /* Texture mapping (usually: GL_TEXTURE_2D), cannot be 0 */
> -    GLenum tex_target;
> -
> -    /* Set to true if textures are generated from pf_update() */
> -    bool handle_texs_gen;
> -
> -    struct opengl_tex_cfg {
> -        /* Texture scale factor, cannot be 0 */
> -        vlc_rational_t w;
> -        vlc_rational_t h;
> -
> -        /* The following is used and filled by the opengl_fragment_shader_init
> -         * function. */
> -        GLint  internal;
> -        GLenum format;
> -        GLenum type;
> -    } texs[PICTURE_PLANE_MAX];
> -
>      /* The following is used and filled by the opengl_fragment_shader_init
>       * function. */
>      struct {
> @@ -118,57 +87,7 @@ struct opengl_tex_converter_t
>      struct pl_shader *pl_sh;
>      const struct pl_shader_res *pl_sh_res;
>  
> -    /* Private context */
> -    void *priv;
> -
> -    /**
> -     * Callback to allocate data for bound textures
> -     *
> -     * This function pointer can be NULL. Software converters should 
> call
> -     * glTexImage2D() to allocate textures data (it will be 
> deallocated by the
> -     * caller when calling glDeleteTextures()). Won't be called if
> -     * handle_texs_gen is true.
> -     *
> -     * \param tc OpenGL tex converter
> -     * \param textures array of textures to bind (one per plane)
> -     * \param tex_width array of tex width (one per plane)
> -     * \param tex_height array of tex height (one per plane)
> -     * \return VLC_SUCCESS or a VLC error
> -     */
> -    int (*pf_allocate_textures)(const opengl_tex_converter_t *tc, 
> GLuint *textures,
> -                                const GLsizei *tex_width, const 
> GLsizei *tex_height);
> -
> -    /**
> -     * Callback to allocate a picture pool
> -     *
> -     * This function pointer *can* be NULL. If NULL, A generic pool 
> with
> -     * pictures allocated from the video_format_t will be used.
> -     *
> -     * \param tc OpenGL tex converter
> -     * \param requested_count number of pictures to allocate
> -     * \return the picture pool or NULL in case of error
> -     */
> -    picture_pool_t *(*pf_get_pool)(const opengl_tex_converter_t *tc,
> -                                   unsigned requested_count);

For Info, this call won't be needed soon. See with upcoming patches from Steve.

> -
> -    /**
> -     * Callback to update a picture
> -     *
> -     * This function pointer cannot be NULL. The implementation should 
> upload
> -     * every planes of the picture.
> -     *
> -     * \param tc OpenGL tex converter
> -     * \param textures array of textures to bind (one per plane)
> -     * \param tex_width array of tex width (one per plane)
> -     * \param tex_height array of tex height (one per plane)
> -     * \param pic picture to update
> -     * \param plane_offset offsets of each picture planes to read data 
> from
> -     * (one per plane, can be NULL)
> -     * \return VLC_SUCCESS or a VLC error
> -     */
> -    int (*pf_update)(const opengl_tex_converter_t *tc, GLuint 
> *textures,
> -                     const GLsizei *tex_width, const GLsizei 
> *tex_height,
> -                     picture_t *pic, const size_t *plane_offset);
> +    struct vlc_gl_importer importer;
>  
>      /**
>       * Callback to fetch locations of uniform or attributes variables
> @@ -196,26 +115,6 @@ 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 6468068640..1d3e2348f2 100644
> --- a/modules/video_output/opengl/converter_android.c
> +++ b/modules/video_output/opengl/converter_android.c
> @@ -38,15 +38,15 @@ struct priv
>  };
>  
>  static int
> -tc_anop_allocate_textures(const opengl_tex_converter_t *tc, GLuint 
> *textures,
> +tc_anop_allocate_textures(const struct vlc_gl_importer *imp, GLuint 
> *textures,
>                            const GLsizei *tex_width, const GLsizei 
> *tex_height)
>  {
>      (void) tex_width; (void) tex_height;
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = imp->priv;
>      assert(textures[0] != 0);
>      if (SurfaceTexture_attachToGLContext(priv->awh, textures[0]) != 0)
>      {
> -        msg_Err(tc->gl, "SurfaceTexture_attachToGLContext failed");
> +        msg_Err(imp->gl, "SurfaceTexture_attachToGLContext failed");
>          return VLC_EGENERIC;
>      }
>      priv->stex_attached = true;
> @@ -54,7 +54,7 @@ tc_anop_allocate_textures(const 
> opengl_tex_converter_t *tc, GLuint *textures,
>  }
>  
>  static int
> -tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
> +tc_anop_update(const struct vlc_gl_importer *imp, GLuint *textures,
>                 const GLsizei *tex_width, const GLsizei *tex_height,
>                 picture_t *pic, const size_t *plane_offset)
>  {
> @@ -65,7 +65,7 @@ tc_anop_update(const opengl_tex_converter_t *tc, 
> GLuint *textures,
>      if (plane_offset != NULL)
>          return VLC_EGENERIC;
>  
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = imp->priv;
>  
>      if (!priv->avctx->render(pic->context))
>          return VLC_SUCCESS; /* already rendered */
> @@ -77,16 +77,16 @@ tc_anop_update(const opengl_tex_converter_t *tc, 
> GLuint *textures,
>          return VLC_EGENERIC;
>      }
>  
> -    tc->vt->ActiveTexture(GL_TEXTURE0);
> -    tc->vt->BindTexture(tc->tex_target, textures[0]);
> +    imp->vt->ActiveTexture(GL_TEXTURE0);
> +    imp->vt->BindTexture(imp->tex_target, textures[0]);
>  
>      return VLC_SUCCESS;
>  }
>  
>  static const float *
> -tc_get_transform_matrix(const opengl_tex_converter_t *tc)
> +tc_get_transform_matrix(const struct vlc_gl_importer *imp)
>  {
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = imp->priv;
>      return priv->transform_mtx;
>  }
>  
> @@ -106,60 +106,64 @@ static int
>  Open(vlc_object_t *obj)
>  {
>      opengl_tex_converter_t *tc = (void *) obj;
> +    struct vlc_gl_importer *imp = &tc->importer;
>  
> -    if (tc->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE
> -     || !tc->gl->surface->handle.anativewindow
> -     || !tc->vctx)
> +    if (imp->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE
> +     || !imp->gl->surface->handle.anativewindow
> +     || !imp->vctx)
>          return VLC_EGENERIC;
>  
>      android_video_context_t *avctx =
> -        vlc_video_context_GetPrivate(tc->vctx, VLC_VIDEO_CONTEXT_AWINDOW);
> +        vlc_video_context_GetPrivate(imp->vctx, VLC_VIDEO_CONTEXT_AWINDOW);
>  
>      if (avctx->id != AWindow_SurfaceTexture)
>          return VLC_EGENERIC;
>  
> -    tc->priv = malloc(sizeof(struct priv));
> -    if (unlikely(tc->priv == NULL))
> +    imp->priv = malloc(sizeof(struct priv));
> +    if (unlikely(imp->priv == NULL))
>          return VLC_ENOMEM;
>  
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = imp->priv;
>      priv->avctx = avctx;
> -    priv->awh = tc->gl->surface->handle.anativewindow;
> +    priv->awh = imp->gl->surface->handle.anativewindow;
>      priv->transform_mtx = NULL;
>      priv->stex_attached = false;
>  
> -    tc->pf_allocate_textures = tc_anop_allocate_textures;
> -    tc->pf_update         = tc_anop_update;
> -    tc->pf_get_transform_matrix = tc_get_transform_matrix;
> +    static const struct vlc_gl_importer_ops ops = {
> +        .allocate_textures = tc_anop_allocate_textures,
> +        .update_textures = tc_anop_update,
> +        .get_transform_matrix = tc_get_transform_matrix,
> +    };
> +    imp->ops = &ops;
>  
>      /* The transform Matrix (uSTMatrix) given by the SurfaceTexture is not
>       * using the same origin than us. Ask the caller to rotate textures
>       * coordinates, via the vertex shader, by forcing an orientation. */
> -    switch (tc->fmt.orientation)
> +    switch (imp->fmt.orientation)
>      {
>          case ORIENT_TOP_LEFT:
> -            tc->fmt.orientation = ORIENT_BOTTOM_LEFT;
> +            imp->fmt.orientation = ORIENT_BOTTOM_LEFT;
>              break;
>          case ORIENT_TOP_RIGHT:
> -            tc->fmt.orientation = ORIENT_BOTTOM_RIGHT;
> +            imp->fmt.orientation = ORIENT_BOTTOM_RIGHT;
>              break;
>          case ORIENT_BOTTOM_LEFT:
> -            tc->fmt.orientation = ORIENT_TOP_LEFT;
> +            imp->fmt.orientation = ORIENT_TOP_LEFT;
>              break;
>          case ORIENT_BOTTOM_RIGHT:
> -            tc->fmt.orientation = ORIENT_TOP_RIGHT;
> +            imp->fmt.orientation = ORIENT_TOP_RIGHT;
>              break;
>          case ORIENT_LEFT_TOP:
> -            tc->fmt.orientation = ORIENT_RIGHT_TOP;
> +            imp->fmt.orientation = ORIENT_RIGHT_TOP;
>              break;
>          case ORIENT_LEFT_BOTTOM:
> -            tc->fmt.orientation = ORIENT_RIGHT_BOTTOM;
> +            imp->fmt.orientation = ORIENT_RIGHT_BOTTOM;
>              break;
>          case ORIENT_RIGHT_TOP:
> -            tc->fmt.orientation = ORIENT_LEFT_TOP;
> +            imp->fmt.orientation = ORIENT_LEFT_TOP;
>              break;
>          case ORIENT_RIGHT_BOTTOM:
> -            tc->fmt.orientation = ORIENT_LEFT_BOTTOM;
> +            imp->fmt.orientation = ORIENT_LEFT_BOTTOM;
>              break;
>      }
>  
> diff --git a/modules/video_output/opengl/converter_sw.c 
> b/modules/video_output/opengl/converter_sw.c
> index 3eb3eeb3ae..9cea29b9bf 100644
> --- a/modules/video_output/opengl/converter_sw.c
> +++ b/modules/video_output/opengl/converter_sw.c
> @@ -72,6 +72,8 @@ pbo_picture_destroy(picture_t *pic)
>  static picture_t *
>  pbo_picture_create(const opengl_tex_converter_t *tc)
>  {
> +    const struct vlc_gl_importer *imp = &tc->importer;
> +
>      picture_sys_t *picsys = calloc(1, sizeof(*picsys));
>      if (unlikely(picsys == NULL))
>          return NULL;
> @@ -80,7 +82,7 @@ pbo_picture_create(const opengl_tex_converter_t *tc)
>          .p_sys = picsys,
>          .pf_destroy = pbo_picture_destroy,
>      };
> -    picture_t *pic = picture_NewFromResource(&tc->fmt, &rsc);
> +    picture_t *pic = picture_NewFromResource(&imp->fmt, &rsc);
>      if (pic == NULL)
>      {
>          free(picsys);
> @@ -91,14 +93,14 @@ pbo_picture_create(const opengl_tex_converter_t *tc)
>      picsys->DeleteBuffers = tc->vt->DeleteBuffers;
>  
>      /* XXX: needed since picture_NewFromResource override pic planes */
> -    if (picture_Setup(pic, &tc->fmt))
> +    if (picture_Setup(pic, &imp->fmt))
>      {
>          picture_Release(pic);
>          return NULL;
>      }
>  
>      assert(pic->i_planes > 0
> -        && (unsigned) pic->i_planes == tc->tex_count);
> +        && (unsigned) pic->i_planes == imp->tex_count);
>  
>      for (int i = 0; i < pic->i_planes; ++i)
>      {
> @@ -141,7 +143,7 @@ pbo_data_alloc(const opengl_tex_converter_t *tc, 
> picture_t *pic)
>  static int
>  pbo_pics_alloc(const opengl_tex_converter_t *tc)
>  {
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = tc->importer.priv;
>      for (size_t i = 0; i < PBO_DISPLAY_COUNT; ++i)
>      {
>          picture_t *pic = priv->pbo.display_pics[i] = 
> pbo_picture_create(tc);
> @@ -163,12 +165,12 @@ error:
>  }
>  
>  static int
> -tc_pbo_update(const opengl_tex_converter_t *tc, GLuint *textures,
> +tc_pbo_update(const struct vlc_gl_importer *imp, GLuint *textures,
>                const GLsizei *tex_width, const GLsizei *tex_height,
>                picture_t *pic, const size_t *plane_offset)
>  {
>      (void) plane_offset; assert(plane_offset == NULL);
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = imp->priv;
>  
>      picture_t *display_pic = 
> priv->pbo.display_pics[priv->pbo.display_idx];
>      picture_sys_t *p_sys = display_pic->p_sys;
> @@ -178,53 +180,52 @@ tc_pbo_update(const opengl_tex_converter_t *tc, 
> GLuint *textures,
>      {
>          GLsizeiptr size = pic->p[i].i_lines * pic->p[i].i_pitch;
>          const GLvoid *data = pic->p[i].p_pixels;
> -        tc->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
> +        imp->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
>                             p_sys->buffers[i]);
> -        tc->vt->BufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, data);
> +        imp->vt->BufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, data);
>  
> -        tc->vt->ActiveTexture(GL_TEXTURE0 + i);
> -        tc->vt->BindTexture(tc->tex_target, textures[i]);
> +        imp->vt->ActiveTexture(GL_TEXTURE0 + i);
> +        imp->vt->BindTexture(imp->tex_target, textures[i]);
>  
> -        tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[i].i_pitch
> +        imp->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[i].i_pitch
>              * tex_width[i] / (pic->p[i].i_visible_pitch ? 
> pic->p[i].i_visible_pitch : 1));
>  
> -        tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, tex_width[i], 
> tex_height[i],
> -                              tc->texs[i].format, tc->texs[i].type, 
> NULL);
> -
> -        tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
> +        imp->vt->TexSubImage2D(imp->tex_target, 0, 0, 0, tex_width[i], 
> tex_height[i],
> +                               imp->texs[i].format, imp->texs[i].type, 
> NULL);
> +        imp->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
>      }
>  
>      /* turn off pbo */
> -    tc->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
> +    imp->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
>  
>      return VLC_SUCCESS;
>  }
>  
>  static int
> -tc_common_allocate_textures(const opengl_tex_converter_t *tc, GLuint 
> *textures,
> +tc_common_allocate_textures(const struct vlc_gl_importer *imp, GLuint 
> *textures,
>                              const GLsizei *tex_width, const GLsizei 
> *tex_height)
>  {
> -    for (unsigned i = 0; i < tc->tex_count; i++)
> +    for (unsigned i = 0; i < imp->tex_count; i++)
>      {
> -        tc->vt->BindTexture(tc->tex_target, textures[i]);
> -        tc->vt->TexImage2D(tc->tex_target, 0, tc->texs[i].internal,
> -                           tex_width[i], tex_height[i], 0, 
> tc->texs[i].format,
> -                           tc->texs[i].type, NULL);
> +        imp->vt->BindTexture(imp->tex_target, textures[i]);
> +        imp->vt->TexImage2D(imp->tex_target, 0, imp->texs[i].internal,
> +                           tex_width[i], tex_height[i], 0, 
> imp->texs[i].format,
> +                           imp->texs[i].type, NULL);
>      }
>      return VLC_SUCCESS;
>  }
>  
>  static int
> -upload_plane(const opengl_tex_converter_t *tc, unsigned tex_idx,
> +upload_plane(const struct vlc_gl_importer *imp, unsigned tex_idx,
>               GLsizei width, GLsizei height,
>               unsigned pitch, unsigned visible_pitch, const void *pixels)
>  {
> -    struct priv *priv = tc->priv;
> -    GLenum tex_format = tc->texs[tex_idx].format;
> -    GLenum tex_type = tc->texs[tex_idx].type;
> +    struct priv *priv = imp->priv;
> +    GLenum tex_format = imp->texs[tex_idx].format;
> +    GLenum tex_type = imp->texs[tex_idx].type;
>  
>      /* This unpack alignment is the default, but setting it just in case. */
> -    tc->vt->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
> +    imp->vt->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
>  
>      if (!priv->has_unpack_subimage)
>      {
> @@ -255,41 +256,41 @@ upload_plane(const opengl_tex_converter_t *tc, 
> unsigned tex_idx,
>                  source += pitch;
>                  destination += visible_pitch;
>              }
> -            tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, width, 
> height,
> -                                  tex_format, tex_type, 
> priv->texture_temp_buf);
> +            imp->vt->TexSubImage2D(imp->tex_target, 0, 0, 0, width, 
> height,
> +                                   tex_format, tex_type, 
> priv->texture_temp_buf);
>          }
>          else
>          {
> -            tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, width, 
> height,
> -                                  tex_format, tex_type, pixels);
> +            imp->vt->TexSubImage2D(imp->tex_target, 0, 0, 0, width, 
> height,
> +                                   tex_format, tex_type, pixels);
>          }
>      }
>      else
>      {
> -        tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pitch * width / 
> (visible_pitch ? visible_pitch : 1));
> -        tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, width, height,
> +        imp->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pitch * width / 
> (visible_pitch ? visible_pitch : 1));
> +        imp->vt->TexSubImage2D(imp->tex_target, 0, 0, 0, width, height,
>                                tex_format, tex_type, pixels);
> -        tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
> +        imp->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
>      }
>      return VLC_SUCCESS;
>  }
>  
>  static int
> -tc_common_update(const opengl_tex_converter_t *tc, GLuint *textures,
> +tc_common_update(const struct vlc_gl_importer *imp, GLuint *textures,
>                   const GLsizei *tex_width, const GLsizei *tex_height,
>                   picture_t *pic, const size_t *plane_offset)
>  {
>      int ret = VLC_SUCCESS;
> -    for (unsigned i = 0; i < tc->tex_count && ret == VLC_SUCCESS; i++)
> +    for (unsigned i = 0; i < imp->tex_count && ret == VLC_SUCCESS; i++)
>      {
>          assert(textures[i] != 0);
> -        tc->vt->ActiveTexture(GL_TEXTURE0 + i);
> -        tc->vt->BindTexture(tc->tex_target, textures[i]);
> +        imp->vt->ActiveTexture(GL_TEXTURE0 + i);
> +        imp->vt->BindTexture(imp->tex_target, textures[i]);
>          const void *pixels = plane_offset != NULL ?
>                               &pic->p[i].p_pixels[plane_offset[i]] :
>                               pic->p[i].p_pixels;
>  
> -        ret = upload_plane(tc, i, tex_width[i], tex_height[i],
> +        ret = upload_plane(imp, i, tex_width[i], tex_height[i],
>                             pic->p[i].i_pitch, 
> pic->p[i].i_visible_pitch, pixels);
>      }
>      return ret;
> @@ -298,21 +299,23 @@ tc_common_update(const opengl_tex_converter_t 
> *tc, GLuint *textures,
>  int
>  opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool 
> allow_dr)
>  {
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
>      GLuint fragment_shader = 0;
>      video_color_space_t space;
>      const vlc_fourcc_t *list;
>  
> -    if (vlc_fourcc_IsYUV(tc->fmt.i_chroma))
> +    if (vlc_fourcc_IsYUV(imp->fmt.i_chroma))
>      {
>          GLint max_texture_units = 0;
>          tc->vt->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
>          if (max_texture_units < 3)
>              return VLC_EGENERIC;
>  
> -        list = vlc_fourcc_GetYUVFallback(tc->fmt.i_chroma);
> -        space = tc->fmt.space;
> +        list = vlc_fourcc_GetYUVFallback(imp->fmt.i_chroma);
> +        space = imp->fmt.space;
>      }
> -    else if (tc->fmt.i_chroma == VLC_CODEC_XYZ12)
> +    else if (imp->fmt.i_chroma == VLC_CODEC_XYZ12)
>      {
>          static const vlc_fourcc_t xyz12_list[] = { VLC_CODEC_XYZ12, 0 
> };
>          list = xyz12_list;
> @@ -320,7 +323,7 @@ 
> opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool 
> allow_dr)
>      }
>      else
>      {
> -        list = vlc_fourcc_GetRGBFallback(tc->fmt.i_chroma);
> +        list = vlc_fourcc_GetRGBFallback(imp->fmt.i_chroma);
>          space = COLOR_SPACE_UNDEF;
>      }
>  
> @@ -330,20 +333,20 @@ 
> opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool 
> allow_dr)
>              opengl_fragment_shader_init(tc, GL_TEXTURE_2D, *list, 
> space);
>          if (fragment_shader != 0)
>          {
> -            tc->fmt.i_chroma = *list;
> +            imp->fmt.i_chroma = *list;
>  
> -            if (tc->fmt.i_chroma == VLC_CODEC_RGB32)
> +            if (imp->fmt.i_chroma == VLC_CODEC_RGB32)
>              {
>  #if defined(WORDS_BIGENDIAN)
> -                tc->fmt.i_rmask  = 0xff000000;
> -                tc->fmt.i_gmask  = 0x00ff0000;
> -                tc->fmt.i_bmask  = 0x0000ff00;
> +                imp->fmt.i_rmask  = 0xff000000;
> +                imp->fmt.i_gmask  = 0x00ff0000;
> +                imp->fmt.i_bmask  = 0x0000ff00;
>  #else
> -                tc->fmt.i_rmask  = 0x000000ff;
> -                tc->fmt.i_gmask  = 0x0000ff00;
> -                tc->fmt.i_bmask  = 0x00ff0000;
> +                imp->fmt.i_rmask  = 0x000000ff;
> +                imp->fmt.i_gmask  = 0x0000ff00;
> +                imp->fmt.i_bmask  = 0x00ff0000;
>  #endif
> -                video_format_FixRgb(&tc->fmt);
> +                video_format_FixRgb(&imp->fmt);
>              }
>              break;
>          }
> @@ -352,19 +355,22 @@ 
> opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool 
> allow_dr)
>      if (fragment_shader == 0)
>          return VLC_EGENERIC;
>  
> -    struct priv *priv = tc->priv = calloc(1, sizeof(struct priv));
> +    struct priv *priv = imp->priv = calloc(1, sizeof(struct priv));
>      if (unlikely(priv == NULL))
>      {
>          tc->vt->DeleteShader(fragment_shader);
>          return VLC_ENOMEM;
>      }
>  
> -    tc->pf_update            = tc_common_update;
> -    tc->pf_allocate_textures = tc_common_allocate_textures;
> +    static const struct vlc_gl_importer_ops ops = {
> +        .allocate_textures = tc_common_allocate_textures,
> +        .update_textures = tc_common_update,
> +    };
> +    imp->ops = &ops;
>  
>      /* OpenGL or OpenGL ES2 with GL_EXT_unpack_subimage ext */
>      priv->has_unpack_subimage =
> -        !tc->is_gles || vlc_gl_StrHasToken(tc->glexts, 
> "GL_EXT_unpack_subimage");
> +        !imp->is_gles || vlc_gl_StrHasToken(imp->glexts, 
> "GL_EXT_unpack_subimage");
>  
>      if (allow_dr && priv->has_unpack_subimage)
>      {
> @@ -373,15 +379,19 @@ 
> opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool 
> allow_dr)
>          const bool glver_ok = strverscmp((const char *)ogl_version, 
> "3.0") >= 0;
>  
>          const bool has_pbo = glver_ok &&
> -            (vlc_gl_StrHasToken(tc->glexts, "GL_ARB_pixel_buffer_object") ||
> -             vlc_gl_StrHasToken(tc->glexts, "GL_EXT_pixel_buffer_object"));
> +            (vlc_gl_StrHasToken(imp->glexts, "GL_ARB_pixel_buffer_object") ||
> +             vlc_gl_StrHasToken(imp->glexts, "GL_EXT_pixel_buffer_object"));
>  
>          const bool supports_pbo = has_pbo && tc->vt->BufferData
>              && tc->vt->BufferSubData;
>          if (supports_pbo && pbo_pics_alloc(tc) == VLC_SUCCESS)
>          {
> -            tc->pf_update  = tc_pbo_update;
> -            msg_Dbg(tc->gl, "PBO support enabled");
> +            static const struct vlc_gl_importer_ops pbo_ops = {
> +                .allocate_textures = tc_common_allocate_textures,
> +                .update_textures = tc_pbo_update,
> +            };
> +            imp->ops = &pbo_ops;
> +            msg_Dbg(imp->gl, "PBO support enabled");
>          }
>      }
>  
> @@ -393,9 +403,9 @@ 
> opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool 
> allow_dr)
>  void
>  opengl_tex_converter_generic_deinit(opengl_tex_converter_t *tc)
>  {
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = tc->importer.priv;
>      for (size_t i = 0; i < PBO_DISPLAY_COUNT && 
> priv->pbo.display_pics[i]; ++i)
>          picture_Release(priv->pbo.display_pics[i]);
>      free(priv->texture_temp_buf);
> -    free(tc->priv);
> +    free(priv);
>  }
> diff --git a/modules/video_output/opengl/converter_vaapi.c 
> b/modules/video_output/opengl/converter_vaapi.c
> index 6fb1085ec8..177b9cda41 100644
> --- a/modules/video_output/opengl/converter_vaapi.c
> +++ b/modules/video_output/opengl/converter_vaapi.c
> @@ -62,7 +62,7 @@ struct priv
>  };
>  
>  static EGLImageKHR
> -vaegl_image_create(const opengl_tex_converter_t *tc, EGLint w, EGLint 
> h,
> +vaegl_image_create(const struct vlc_gl_importer *imp, EGLint w, EGLint 
> h,
>                     EGLint fourcc, EGLint fd, EGLint offset, EGLint 
> pitch)
>  {
>      EGLint attribs[] = {
> @@ -75,23 +75,23 @@ vaegl_image_create(const opengl_tex_converter_t 
> *tc, EGLint w, EGLint h,
>          EGL_NONE
>      };
>  
> -    return tc->gl->egl.createImageKHR(tc->gl, EGL_LINUX_DMA_BUF_EXT, NULL,
> -                                      attribs);
> +    return imp->gl->egl.createImageKHR(imp->gl, EGL_LINUX_DMA_BUF_EXT, NULL,
> +                                       attribs);
>  }
>  
>  static void
> -vaegl_image_destroy(const opengl_tex_converter_t *tc, EGLImageKHR image)
> +vaegl_image_destroy(const struct vlc_gl_importer *imp, EGLImageKHR image)
>  {
> -    tc->gl->egl.destroyImageKHR(tc->gl, image);
> +    imp->gl->egl.destroyImageKHR(imp->gl, image);
>  }
>  
>  static void
> -vaegl_release_last_pic(const opengl_tex_converter_t *tc, struct priv *priv)
> +vaegl_release_last_pic(const struct vlc_gl_importer *imp, struct priv *priv)
>  {
> -    vlc_object_t *o = VLC_OBJECT(tc->gl);
> +    vlc_object_t *o = VLC_OBJECT(imp->gl);
>  
>      for (unsigned i = 0; i < priv->last.va_image.num_planes; ++i)
> -        vaegl_image_destroy(tc, priv->last.egl_images[i]);
> +        vaegl_image_destroy(imp, priv->last.egl_images[i]);
>  
>      vlc_vaapi_ReleaseBufferHandle(o, priv->vadpy, priv->last.va_image.buf);
>  
> @@ -149,13 +149,13 @@ vaegl_init_fourcc(const opengl_tex_converter_t 
> *tc, struct priv *priv,
>  }
>  
>  static int
> -tc_vaegl_update(const opengl_tex_converter_t *tc, GLuint *textures,
> +tc_vaegl_update(const struct vlc_gl_importer *imp, GLuint *textures,
>                  const GLsizei *tex_width, const GLsizei *tex_height,
>                  picture_t *pic, const size_t *plane_offset)
>  {
>      (void) plane_offset;
> -    struct priv *priv = tc->priv;
> -    vlc_object_t *o = VLC_OBJECT(tc->gl);
> +    struct priv *priv = imp->priv;
> +    vlc_object_t *o = VLC_OBJECT(imp->gl);
>      VAImage va_image;
>      VABufferInfo va_buffer_info;
>      EGLImageKHR egl_images[3] = { };
> @@ -189,21 +189,21 @@ tc_vaegl_update(const opengl_tex_converter_t *tc, 
> GLuint *textures,
>      for (unsigned i = 0; i < va_image.num_planes; ++i)
>      {
>          egl_images[i] =
> -            vaegl_image_create(tc, tex_width[i], tex_height[i],
> +            vaegl_image_create(imp, tex_width[i], tex_height[i],
>                                 priv->drm_fourccs[i], 
> va_buffer_info.handle,
>                                 va_image.offsets[i], 
> va_image.pitches[i]);
>          if (egl_images[i] == NULL)
>              goto error;
>  
> -        tc->vt->BindTexture(tc->tex_target, textures[i]);
> +        imp->vt->BindTexture(imp->tex_target, textures[i]);
>  
> -        priv->glEGLImageTargetTexture2DOES(tc->tex_target, egl_images[i]);
> +        priv->glEGLImageTargetTexture2DOES(imp->tex_target, egl_images[i]);
>      }
>  
>      if (pic != priv->last.pic)
>      {
>          if (priv->last.pic != NULL)
> -            vaegl_release_last_pic(tc, priv);
> +            vaegl_release_last_pic(imp, priv);
>          priv->last.pic = picture_Hold(pic);
>          priv->last.va_image = va_image;
>          priv->last.va_buffer_info = va_buffer_info;
> @@ -220,7 +220,7 @@ error:
>              vlc_vaapi_ReleaseBufferHandle(o, priv->vadpy, va_image.buf);
>  
>          for (unsigned i = 0; i < 3 && egl_images[i] != NULL; ++i)
> -            vaegl_image_destroy(tc, egl_images[i]);
> +            vaegl_image_destroy(imp, egl_images[i]);
>  
>          vlc_vaapi_DestroyImage(o, priv->vadpy, va_image.image_id);
>      }
> @@ -228,14 +228,14 @@ error:
>  }
>  
>  static picture_pool_t *
> -tc_vaegl_get_pool(const opengl_tex_converter_t *tc, unsigned requested_count)
> +tc_vaegl_get_pool(const struct vlc_gl_importer *imp, unsigned requested_count)
>  {
> -    vlc_object_t *o = VLC_OBJECT(tc->gl);
> -    struct priv *priv = tc->priv;
> +    vlc_object_t *o = VLC_OBJECT(imp->gl);
> +    struct priv *priv = imp->priv;
>  
>      picture_pool_t *pool =
> -        vlc_vaapi_PoolNew(VLC_OBJECT(tc->gl), tc->vctx, priv->vadpy,
> -                          requested_count, &priv->va_surface_ids, &tc->fmt);
> +        vlc_vaapi_PoolNew(o, imp->vctx, priv->vadpy,
> +                          requested_count, &priv->va_surface_ids, &imp->fmt);
>      if (!pool)
>          return NULL;
>  
> @@ -258,17 +258,17 @@ tc_vaegl_get_pool(const opengl_tex_converter_t 
> *tc, unsigned requested_count)
>  
>      for (unsigned i = 0; i < va_image.num_planes; ++i)
>      {
> -        EGLint w = (va_image.width * tc->texs[i].w.num) / 
> tc->texs[i].w.den;
> -        EGLint h = (va_image.height * tc->texs[i].h.num) / 
> tc->texs[i].h.den;
> +        EGLint w = (va_image.width * imp->texs[i].w.num) / 
> imp->texs[i].w.den;
> +        EGLint h = (va_image.height * imp->texs[i].h.num) / 
> imp->texs[i].h.den;
>          EGLImageKHR egl_image =
> -            vaegl_image_create(tc, w, h, priv->drm_fourccs[i], 
> va_buffer_info.handle,
> +            vaegl_image_create(imp, w, h, priv->drm_fourccs[i], 
> va_buffer_info.handle,
>                                 va_image.offsets[i], 
> va_image.pitches[i]);
>          if (egl_image == NULL)
>          {
>              msg_Warn(o, "Can't create Image KHR: kernel too old ?");
>              goto error;
>          }
> -        vaegl_image_destroy(tc, egl_image);
> +        vaegl_image_destroy(imp, egl_image);
>      }
>  
>      success = true;
> @@ -291,12 +291,12 @@ static void
>  Close(vlc_object_t *obj)
>  {
>      opengl_tex_converter_t *tc = (void *)obj;
> -    struct priv *priv = tc->priv;
> +    struct priv *priv = tc->importer.priv;
>  
>      if (priv->last.pic != NULL)
> -        vaegl_release_last_pic(tc, priv);
> +        vaegl_release_last_pic(&tc->importer, priv);
>  
> -    free(tc->priv);
> +    free(priv);
>  }
>  
>  static int strcasecmp_void(const void *a, const void *b)
> @@ -334,14 +334,14 @@ 
> tc_va_check_interop_blacklist(opengl_tex_converter_t *tc, VADisplay 
> *vadpy)
>  }
>  
>  static int
> -tc_va_check_derive_image(opengl_tex_converter_t *tc)
> +tc_va_check_derive_image(const struct vlc_gl_importer *imp)
>  {
> -    vlc_object_t *o = VLC_OBJECT(tc->gl);
> -    struct priv *priv = tc->priv;
> +    vlc_object_t *o = VLC_OBJECT(imp->gl);
> +    struct priv *priv = imp->priv;
>      VASurfaceID *va_surface_ids;
>  
> -    picture_pool_t *pool = vlc_vaapi_PoolNew(o, tc->vctx, priv->vadpy, 1,
> -                                             &va_surface_ids, &tc->fmt);
> +    picture_pool_t *pool = vlc_vaapi_PoolNew(o, imp->vctx, priv->vadpy, 1,
> +                                             &va_surface_ids, &imp->fmt);
>      if (!pool)
>          return VLC_EGENERIC;
>  
> @@ -358,12 +358,13 @@ static int
>  Open(vlc_object_t *obj)
>  {
>      opengl_tex_converter_t *tc = (void *) obj;
> +    struct vlc_gl_importer *imp = &tc->importer;
>  
> -    if (tc->vctx == NULL)
> +    if (imp->vctx == NULL)
>          return VLC_EGENERIC;
> -    vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(tc->vctx);
> +    vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(imp->vctx);
>      if (dec_device->type != VLC_DECODER_DEVICE_VAAPI
> -     || !vlc_vaapi_IsChromaOpaque(tc->fmt.i_chroma)
> +     || !vlc_vaapi_IsChromaOpaque(imp->fmt.i_chroma)
>       || tc->gl->ext != VLC_GL_EXT_EGL
>       || tc->gl->egl.createImageKHR == NULL
>       || tc->gl->egl.destroyImageKHR == NULL)
> @@ -372,7 +373,7 @@ Open(vlc_object_t *obj)
>          return VLC_EGENERIC;
>      }
>  
> -    if (!vlc_gl_StrHasToken(tc->glexts, "GL_OES_EGL_image"))
> +    if (!vlc_gl_StrHasToken(imp->glexts, "GL_OES_EGL_image"))
>      {
>          vlc_decoder_device_Release(dec_device);
>          return VLC_EGENERIC;
> @@ -385,14 +386,14 @@ Open(vlc_object_t *obj)
>          return VLC_EGENERIC;
>      }
>  
> -    struct priv *priv = tc->priv = calloc(1, sizeof(struct priv));
> -    if (unlikely(tc->priv == NULL))
> +    struct priv *priv = imp->priv = calloc(1, sizeof(struct priv));
> +    if (unlikely(priv == NULL))
>          goto error;
>      priv->fourcc = 0;
>  
>      int va_fourcc;
>      int vlc_sw_chroma;
> -    switch (tc->fmt.i_chroma)
> +    switch (imp->fmt.i_chroma)
>      {
>          case VLC_CODEC_VAAPI_420:
>              va_fourcc = VA_FOURCC_NV12;
> @@ -420,16 +421,19 @@ Open(vlc_object_t *obj)
>      if (tc_va_check_interop_blacklist(tc, priv->vadpy))
>          goto error;
>  
> -    if (tc_va_check_derive_image(tc))
> +    if (tc_va_check_derive_image(imp))
>          goto error;
>  
>      tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, vlc_sw_chroma,
> -                                              tc->fmt.space);
> +                                              imp->fmt.space);
>      if (tc->fshader == 0)
>          goto error;
>  
> -    tc->pf_update  = tc_vaegl_update;
> -    tc->pf_get_pool = tc_vaegl_get_pool;
> +    static const struct vlc_gl_importer_ops ops = {
> +        .update_textures = tc_vaegl_update,
> +        .get_pool = tc_vaegl_get_pool,
> +    };
> +    imp->ops = &ops;
>  
>      vlc_decoder_device_Release(dec_device);
>  
> diff --git a/modules/video_output/opengl/converter_vdpau.c 
> b/modules/video_output/opengl/converter_vdpau.c
> index e5b3794e84..6a18090c68 100644
> --- a/modules/video_output/opengl/converter_vdpau.c
> +++ b/modules/video_output/opengl/converter_vdpau.c
> @@ -40,10 +40,10 @@
>  #define INTEROP_CALL(fct, ...) \
>      _##fct(__VA_ARGS__); \
>      { \
> -        GLenum ret = tc->vt->GetError(); \
> +        GLenum ret = imp->vt->GetError(); \
>          if (ret != GL_NO_ERROR) \
>          { \
> -            msg_Err(tc->gl, #fct " failed: 0x%x", ret); \
> +            msg_Err(imp->gl, #fct " failed: 0x%x", ret); \
>              return VLC_EGENERIC; \
>          } \
>      }
> @@ -63,18 +63,18 @@ typedef struct {
>  } converter_sys_t;
>  
>  static picture_pool_t *
> -tc_vdpau_gl_get_pool(opengl_tex_converter_t const *tc,
> +tc_vdpau_gl_get_pool(const struct vlc_gl_importer *imp,
>                       unsigned int requested_count)
>  {
> -    converter_sys_t *sys = tc->priv;
> +    converter_sys_t *sys = imp->priv;
>      vlc_decoder_device *dec_device = sys->dec_device;
>      return vlc_vdp_output_pool_create(GetVDPAUOpaqueDevice(dec_device),
>                                        VDP_RGBA_FORMAT_B8G8R8A8,
> -                                      &tc->fmt, requested_count);
> +                                      &imp->fmt, requested_count);
>  }
>  
>  static int
> -tc_vdpau_gl_update(opengl_tex_converter_t const *tc, GLuint textures[],
> +tc_vdpau_gl_update(const struct vlc_gl_importer *imp, GLuint 
> textures[],
>                     GLsizei const tex_widths[], GLsizei const 
> tex_heights[],
>                     picture_t *pic, size_t const plane_offsets[])
>  {
> @@ -105,7 +105,7 @@ tc_vdpau_gl_update(opengl_tex_converter_t const 
> *tc, GLuint textures[],
>      gl_nv_surface =
>          INTEROP_CALL(glVDPAURegisterOutputSurfaceNV,
>                       (void *)(size_t)p_sys->surface,
> -                     GL_TEXTURE_2D, tc->tex_count, textures);
> +                     GL_TEXTURE_2D, imp->tex_count, textures);
>      INTEROP_CALL(glVDPAUSurfaceAccessNV, gl_nv_surface, GL_READ_ONLY);
>      INTEROP_CALL(glVDPAUMapSurfacesNV, 1, &gl_nv_surface);
>  
> @@ -118,7 +118,7 @@ Close(vlc_object_t *obj)
>  {
>      opengl_tex_converter_t *tc = (void *)obj;
>      _glVDPAUFiniNV(); assert(tc->vt->GetError() == GL_NO_ERROR);
> -    converter_sys_t *sys = tc->priv;
> +    converter_sys_t *sys = tc->importer.priv;
>      vlc_decoder_device *dec_device = sys->dec_device;
>      vlc_decoder_device_Release(dec_device);
>  }
> @@ -127,14 +127,16 @@ static int
>  Open(vlc_object_t *obj)
>  {
>      opengl_tex_converter_t *tc = (void *) obj;
> -    if (tc->vctx == NULL)
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
> +    if (imp->vctx == NULL)
>          return VLC_EGENERIC;
> -    vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(tc->vctx);
> +    vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(imp->vctx);
>      if (GetVDPAUOpaqueDevice(dec_device) == NULL
> -     || (tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_420
> -      && tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_422
> -      && tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_444)
> -     || !vlc_gl_StrHasToken(tc->glexts, "GL_NV_vdpau_interop")
> +     || (imp->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_420
> +      && imp->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_422
> +      && imp->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_444)
> +     || !vlc_gl_StrHasToken(imp->glexts, "GL_NV_vdpau_interop")
>       || tc->gl->surface->type != VOUT_WINDOW_TYPE_XID)
>      {
>          vlc_decoder_device_Release(dec_device);
> @@ -149,7 +151,7 @@ Open(vlc_object_t *obj)
>      }
>      sys->dec_device = dec_device;
>  
> -    tc->fmt.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
> +    imp->fmt.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
>  
>      VdpDevice device;
>      vdpau_decoder_device_t *vdpau_dev = GetVDPAUOpaqueDevice(dec_device);
> @@ -194,9 +196,12 @@ Open(vlc_object_t *obj)
>          return VLC_EGENERIC;
>      }
>  
> -    tc->pf_get_pool = tc_vdpau_gl_get_pool;
> -    tc->pf_update = tc_vdpau_gl_update;
> -    tc->priv = sys;
> +    static const struct vlc_gl_importer_ops ops = {
> +        .get_pool = tc_vdpau_gl_get_pool,
> +        .update_textures = tc_vdpau_gl_update,
> +    };
> +    imp->ops = &ops;
> +    imp->priv = sys;
>  
>      return VLC_SUCCESS;
>  }
> diff --git a/modules/video_output/opengl/fragment_shaders.c 
> b/modules/video_output/opengl/fragment_shaders.c
> index bd9978fda4..7bcb8f52ce 100644
> --- a/modules/video_output/opengl/fragment_shaders.c
> +++ b/modules/video_output/opengl/fragment_shaders.c
> @@ -33,6 +33,7 @@
>  
>  #include <vlc_common.h>
>  #include <vlc_memstream.h>
> +#include "importer.h"
>  #include "internal.h"
>  #include "vout_helper.h"
>  
> @@ -102,10 +103,12 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, 
> GLenum tex_target,
>                   video_color_space_t yuv_space,
>                   bool *swap_uv, const char *swizzle_per_tex[])
>  {
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
>      GLint oneplane_texfmt, oneplane16_texfmt,
>            twoplanes_texfmt, twoplanes16_texfmt;
>  
> -    if (vlc_gl_StrHasToken(tc->glexts, "GL_ARB_texture_rg"))
> +    if (vlc_gl_StrHasToken(imp->glexts, "GL_ARB_texture_rg"))
>      {
>          oneplane_texfmt = GL_RED;
>          oneplane16_texfmt = GL_R16;
> @@ -153,10 +156,10 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, 
> GLenum tex_target,
>  
>          assert(internal != 0 && type != 0);
>  
> -        tc->tex_count = 3;
> -        for (unsigned i = 0; i < tc->tex_count; ++i )
> +        imp->tex_count = 3;
> +        for (unsigned i = 0; i < imp->tex_count; ++i )
>          {
> -            tc->texs[i] = (struct opengl_tex_cfg) {
> +            imp->texs[i] = (struct vlc_gl_tex_cfg) {
>                  { desc->p[i].w.num, desc->p[i].w.den },
>                  { desc->p[i].h.num, desc->p[i].h.den },
>                  internal, oneplane_texfmt, type
> @@ -168,15 +171,15 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, 
> GLenum tex_target,
>      }
>      else if (desc->plane_count == 2)
>      {
> -        tc->tex_count = 2;
> +        imp->tex_count = 2;
>  
>          if (desc->pixel_size == 1)
>          {
> -            tc->texs[0] = (struct opengl_tex_cfg) {
> +            imp->texs[0] = (struct vlc_gl_tex_cfg) {
>                  { 1, 1 }, { 1, 1 }, oneplane_texfmt, oneplane_texfmt,
>                  GL_UNSIGNED_BYTE
>              };
> -            tc->texs[1] = (struct opengl_tex_cfg) {
> +            imp->texs[1] = (struct vlc_gl_tex_cfg) {
>                  { 1, 2 }, { 1, 2 }, twoplanes_texfmt, twoplanes_texfmt,
>                  GL_UNSIGNED_BYTE
>              };
> @@ -187,11 +190,11 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, 
> GLenum tex_target,
>               || GetTexFormatSize(tc, tex_target, twoplanes_texfmt,
>                                   twoplanes16_texfmt, 
> GL_UNSIGNED_SHORT) != 16)
>                  return VLC_EGENERIC;
> -            tc->texs[0] = (struct opengl_tex_cfg) {
> +            imp->texs[0] = (struct vlc_gl_tex_cfg) {
>                  { 1, 1 }, { 1, 1 }, oneplane16_texfmt, oneplane_texfmt,
>                  GL_UNSIGNED_SHORT
>              };
> -            tc->texs[1] = (struct opengl_tex_cfg) {
> +            imp->texs[1] = (struct vlc_gl_tex_cfg) {
>                  { 1, 2 }, { 1, 2 }, twoplanes16_texfmt, 
> twoplanes_texfmt,
>                  GL_UNSIGNED_SHORT
>              };
> @@ -213,8 +216,8 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>      else if (desc->plane_count == 1)
>      {
>          /* Y1 U Y2 V fits in R G B A */
> -        tc->tex_count = 1;
> -        tc->texs[0] = (struct opengl_tex_cfg) {
> +        imp->tex_count = 1;
> +        imp->texs[0] = (struct vlc_gl_tex_cfg) {
>              { 1, 2 }, { 1, 1 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE
>          };
>  
> @@ -302,12 +305,13 @@ tc_rgb_base_init(opengl_tex_converter_t *tc, 
> GLenum tex_target,
>                   vlc_fourcc_t chroma)
>  {
>      (void) tex_target;
> +    struct vlc_gl_importer *imp = &tc->importer;
>  
>      switch (chroma)
>      {
>          case VLC_CODEC_RGB32:
>          case VLC_CODEC_RGBA:
> -            tc->texs[0] = (struct opengl_tex_cfg) {
> +            imp->texs[0] = (struct vlc_gl_tex_cfg) {
>                  { 1, 1 }, { 1, 1 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE
>              };
>              break;
> @@ -315,7 +319,7 @@ tc_rgb_base_init(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>              if (GetTexFormatSize(tc, tex_target, GL_BGRA, GL_RGBA,
>                                   GL_UNSIGNED_BYTE) != 32)
>                  return VLC_EGENERIC;
> -            tc->texs[0] = (struct opengl_tex_cfg) {
> +            imp->texs[0] = (struct vlc_gl_tex_cfg) {
>                  { 1, 1 }, { 1, 1 }, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE
>              };
>              break;
> @@ -323,13 +327,15 @@ tc_rgb_base_init(opengl_tex_converter_t *tc, 
> GLenum tex_target,
>          default:
>              return VLC_EGENERIC;
>      }
> -    tc->tex_count = 1;
> +    imp->tex_count = 1;
>      return VLC_SUCCESS;
>  }
>  
>  static int
>  tc_base_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
>  {
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
>      if (tc->yuv_color)
>      {
>          tc->uloc.Coefficients = tc->vt->GetUniformLocation(program,
> @@ -338,14 +344,14 @@ tc_base_fetch_locations(opengl_tex_converter_t 
> *tc, GLuint program)
>              return VLC_EGENERIC;
>      }
>  
> -    for (unsigned int i = 0; i < tc->tex_count; ++i)
> +    for (unsigned int i = 0; i < imp->tex_count; ++i)
>      {
>          char name[sizeof("TextureX")];
>          snprintf(name, sizeof(name), "Texture%1u", i);
>          tc->uloc.Texture[i] = tc->vt->GetUniformLocation(program, name);
>          if (tc->uloc.Texture[i] == -1)
>              return VLC_EGENERIC;
> -        if (tc->tex_target == GL_TEXTURE_RECTANGLE)
> +        if (imp->tex_target == GL_TEXTURE_RECTANGLE)
>          {
>              snprintf(name, sizeof(name), "TexSize%1u", i);
>              tc->uloc.TexSize[i] = tc->vt->GetUniformLocation(program, name);
> @@ -375,18 +381,19 @@ tc_base_prepare_shader(const opengl_tex_converter_t *tc,
>                         float alpha)
>  {
>      (void) tex_width; (void) tex_height;
> +    const struct vlc_gl_importer *imp = &tc->importer;
>  
>      if (tc->yuv_color)
>          tc->vt->Uniform4fv(tc->uloc.Coefficients, 4, tc->yuv_coefficients);
>  
> -    for (unsigned i = 0; i < tc->tex_count; ++i)
> +    for (unsigned i = 0; i < imp->tex_count; ++i)
>          tc->vt->Uniform1i(tc->uloc.Texture[i], i);
>  
>      tc->vt->Uniform4f(tc->uloc.FillColor, 1.0f, 1.0f, 1.0f, alpha);
>  
> -    if (tc->tex_target == GL_TEXTURE_RECTANGLE)
> +    if (imp->tex_target == GL_TEXTURE_RECTANGLE)
>      {
> -        for (unsigned i = 0; i < tc->tex_count; ++i)
> +        for (unsigned i = 0; i < imp->tex_count; ++i)
>              tc->vt->Uniform2f(tc->uloc.TexSize[i], tex_width[i],
>                                 tex_height[i]);
>      }
> @@ -444,9 +451,11 @@ tc_xyz12_prepare_shader(const opengl_tex_converter_t *tc,
>  static GLuint
>  xyz12_shader_init(opengl_tex_converter_t *tc)
>  {
> -    tc->tex_count = 1;
> -    tc->tex_target = GL_TEXTURE_2D;
> -    tc->texs[0] = (struct opengl_tex_cfg) {
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
> +    imp->tex_count = 1;
> +    imp->tex_target = GL_TEXTURE_2D;
> +    imp->texs[0] = (struct vlc_gl_tex_cfg) {
>          { 1, 1 }, { 1, 1 }, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT
>      };
>  
> @@ -500,6 +509,8 @@ GLuint
>  opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>                                   vlc_fourcc_t chroma, 
> video_color_space_t yuv_space)
>  {
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
>      const char *swizzle_per_tex[PICTURE_PLANE_MAX] = { NULL, };
>      const bool is_yuv = vlc_fourcc_IsYUV(chroma);
>      bool yuv_swap_uv = false;
> @@ -557,7 +568,7 @@ 
> opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>  
>      ADDF("%s", tc->glsl_precision_header);
>  
> -    for (unsigned i = 0; i < tc->tex_count; ++i)
> +    for (unsigned i = 0; i < imp->tex_count; ++i)
>          ADDF("uniform %s Texture%u;\n"
>               "varying vec2 TexCoord%u;\n", sampler, i, i);
>  
> @@ -582,7 +593,7 @@ 
> opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>          dst_space.transfer = var_InheritInteger(tc->gl, "target-trc");
>  
>          pl_shader_color_map(sh, &color_params,
> -                vlc_placebo_ColorSpace(&tc->fmt),
> +                vlc_placebo_ColorSpace(&imp->fmt),
>                  dst_space, NULL, false);
>  
>          struct pl_shader_obj *dither_state = NULL;
> @@ -632,8 +643,8 @@ 
> opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>          ADD(res->glsl);
>      }
>  #else
> -    if (tc->fmt.transfer == TRANSFER_FUNC_SMPTE_ST2084 ||
> -        tc->fmt.primaries == COLOR_PRIMARIES_BT2020)
> +    if (imp->fmt.transfer == TRANSFER_FUNC_SMPTE_ST2084 ||
> +        imp->fmt.primaries == COLOR_PRIMARIES_BT2020)
>      {
>          // no warning for HLG because it's more or less 
> backwards-compatible
>          msg_Warn(tc->gl, "VLC needs to be built with support for 
> libplacebo "
> @@ -643,7 +654,7 @@ 
> opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>  
>      if (tex_target == GL_TEXTURE_RECTANGLE)
>      {
> -        for (unsigned i = 0; i < tc->tex_count; ++i)
> +        for (unsigned i = 0; i < imp->tex_count; ++i)
>              ADDF("uniform vec2 TexSize%u;\n", i);
>      }
>  
> @@ -656,13 +667,13 @@ 
> opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>  
>      if (tex_target == GL_TEXTURE_RECTANGLE)
>      {
> -        for (unsigned i = 0; i < tc->tex_count; ++i)
> +        for (unsigned i = 0; i < imp->tex_count; ++i)
>              ADDF(" vec2 TexCoordRect%u = vec2(TexCoord%u.x * TexSize%u.x, "
>                   "TexCoord%u.y * TexSize%u.y);\n", i, i, i, i, i);
>      }
>  
>      unsigned color_idx = 0;
> -    for (unsigned i = 0; i < tc->tex_count; ++i)
> +    for (unsigned i = 0; i < imp->tex_count; ++i)
>      {
>          const char *swizzle = swizzle_per_tex[i];
>          if (swizzle)
> @@ -743,7 +754,7 @@ 
> opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum 
> tex_target,
>                  (const char *)&chroma, yuv_space, ms.ptr);
>      free(ms.ptr);
>  
> -    tc->tex_target = tex_target;
> +    imp->tex_target = tex_target;
>  
>      tc->pf_fetch_locations = tc_base_fetch_locations;
>      tc->pf_prepare_shader = tc_base_prepare_shader;
> diff --git a/modules/video_output/opengl/importer.h 
> b/modules/video_output/opengl/importer.h
> new file mode 100644
> index 0000000000..d59f425acc
> --- /dev/null
> +++ b/modules/video_output/opengl/importer.h
> @@ -0,0 +1,150 @@
> +/*****************************************************************************
> + * importer.h
> + 
> *****************************************************************************
> + * Copyright (C) 2019 Videolabs
> + *
> + * 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.
> + 
> *****************************************************************************/
> +
> +#ifndef VLC_GL_IMPORTER_H
> +#define VLC_GL_IMPORTER_H
> +
> +#include <vlc_common.h>
> +#include <vlc_opengl.h>
> +#include <vlc_picture.h>
> +#include <vlc_picture_pool.h>
> +
> +#include "gl_common.h"
> +
> +struct vlc_gl_importer;
> +
> +struct vlc_gl_importer_ops {
> +    /**
> +     * Callback to allocate data for bound textures
> +     *
> +     * This function pointer can be NULL. Software converters should 
> call
> +     * glTexImage2D() to allocate textures data (it will be 
> deallocated by the
> +     * caller when calling glDeleteTextures()). Won't be called if
> +     * handle_texs_gen is true.
> +     *
> +     * \param importer the OpenGL importer
> +     * \param textures array of textures to bind (one per plane)
> +     * \param tex_width array of tex width (one per plane)
> +     * \param tex_height array of tex height (one per plane)
> +     * \return VLC_SUCCESS or a VLC error
> +     */
> +    int
> +    (*allocate_textures)(const struct vlc_gl_importer *importer,
> +                         GLuint textures[], const GLsizei tex_width[],
> +                         const GLsizei tex_height[]);
> +
> +    /**
> +     * Callback to update a picture
> +     *
> +     * This function pointer cannot be NULL. The implementation should 
> upload
> +     * every planes of the picture.
> +     *
> +     * \param importer the OpenGL importer
> +     * \param textures array of textures to bind (one per plane)
> +     * \param tex_width array of tex width (one per plane)
> +     * \param tex_height array of tex height (one per plane)
> +     * \param pic picture to update
> +     * \param plane_offset offsets of each picture planes to read data 
> from
> +     * (one per plane, can be NULL)
> +     * \return VLC_SUCCESS or a VLC error
> +     */
> +    int
> +    (*update_textures)(const struct vlc_gl_importer *importer,
> +                       GLuint textures[], const GLsizei tex_width[],
> +                       const GLsizei tex_height[], picture_t *pic,
> +                       const size_t plane_offsets[]);
> +
> +    /**
> +     * Callback to allocate a picture pool
> +     *
> +     * This function pointer *can* be NULL. If NULL, A generic pool 
> with
> +     * pictures allocated from the video_format_t will be used.
> +     *
> +     * \param importer the OpenGL importer
> +     * \param requested_count number of pictures to allocate
> +     * \return the picture pool or NULL in case of error
> +     */
> +     picture_pool_t *
> +     (*get_pool)(const struct vlc_gl_importer *importer,
> +                 unsigned requested_count);
> +
> +    /**
> +     * 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 importer the OpenGL importer
> +     * \return a 4x4 transformatoin matrix (possibly NULL)
> +     */
> +    const float *
> +    (*get_transform_matrix)(const struct vlc_gl_importer *importer);
> +};
> +
> +struct vlc_gl_importer {
> +    vlc_gl_t *gl;
> +    const opengl_vtable_t *vt;
> +    GLenum tex_target;
> +
> +    /* True if the current API is OpenGL ES, set by the caller */
> +    bool is_gles;
> +
> +    /* Available gl extensions (from GL_EXTENSIONS) */
> +    const char *glexts;
> +
> +    /* Can only be changed from the module open function */
> +    video_format_t fmt;
> +
> +    /* Pointer to decoder video context, set by the caller (can be 
> NULL) */
> +    vlc_video_context *vctx;
> +
> +    /* Set to true if textures are generated from pf_update() */
> +    bool handle_texs_gen;
> +
> +    /* Initialized by the importer */
> +    struct vlc_gl_tex_cfg {
> +        /*
> +         * Texture scale factor, cannot be 0.
> +         * In 4:2:0, 1/1 for the Y texture and 1/2 for the UV 
> texture(s)
> +         */
> +        vlc_rational_t w;
> +        vlc_rational_t h;
> +
> +        GLint internal;
> +        GLenum format;
> +        GLenum type;
> +    } texs[PICTURE_PLANE_MAX];
> +    unsigned tex_count;
> +
> +    void *priv;
> +    const struct vlc_gl_importer_ops *ops;
> +};
> +
> +#endif
> diff --git a/modules/video_output/opengl/vout_helper.c 
> b/modules/video_output/opengl/vout_helper.c
> index a8cca1131b..533b554e6c 100644
> --- a/modules/video_output/opengl/vout_helper.c
> +++ b/modules/video_output/opengl/vout_helper.c
> @@ -346,7 +346,7 @@ static GLuint BuildVertexShader(const 
> opengl_tex_converter_t *tc,
>      tc->vt->ShaderSource(shader, 1, (const char **) &code, NULL);
>      if (tc->b_dump_shaders)
>          msg_Dbg(tc->gl, "\n=== Vertex shader for fourcc: %4.4s 
> ===\n%s\n",
> -                (const char *)&tc->fmt.i_chroma, code);
> +                (const char *)&tc->importer.fmt.i_chroma, code);
>      tc->vt->CompileShader(shader);
>      free(code);
>      return shader;
> @@ -357,31 +357,33 @@ GenTextures(const opengl_tex_converter_t *tc,
>              const GLsizei *tex_width, const GLsizei *tex_height,
>              GLuint *textures)
>  {
> -    tc->vt->GenTextures(tc->tex_count, textures);
> +    const struct vlc_gl_importer *imp = &tc->importer;
>  
> -    for (unsigned i = 0; i < tc->tex_count; i++)
> +    tc->vt->GenTextures(imp->tex_count, textures);
> +
> +    for (unsigned i = 0; i < imp->tex_count; i++)
>      {
> -        tc->vt->BindTexture(tc->tex_target, textures[i]);
> +        tc->vt->BindTexture(imp->tex_target, textures[i]);
>  
>  #if !defined(USE_OPENGL_ES2)
>          /* Set the texture parameters */
> -        tc->vt->TexParameterf(tc->tex_target, GL_TEXTURE_PRIORITY, 1.0);
> +        tc->vt->TexParameterf(imp->tex_target, GL_TEXTURE_PRIORITY, 1.0);
>          tc->vt->TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
>  #endif
>  
> -        tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MAG_FILTER, 
> GL_LINEAR);
> -        tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MIN_FILTER, 
> GL_LINEAR);
> -        tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_WRAP_S, 
> GL_CLAMP_TO_EDGE);
> -        tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_WRAP_T, 
> GL_CLAMP_TO_EDGE);
> +        tc->vt->TexParameteri(imp->tex_target, GL_TEXTURE_MAG_FILTER, 
> GL_LINEAR);
> +        tc->vt->TexParameteri(imp->tex_target, GL_TEXTURE_MIN_FILTER, 
> GL_LINEAR);
> +        tc->vt->TexParameteri(imp->tex_target, GL_TEXTURE_WRAP_S, 
> GL_CLAMP_TO_EDGE);
> +        tc->vt->TexParameteri(imp->tex_target, GL_TEXTURE_WRAP_T, 
> GL_CLAMP_TO_EDGE);
>      }
>  
> -    if (tc->pf_allocate_textures != NULL)
> +    if (imp->ops->allocate_textures != NULL)
>      {
> -        int ret = tc->pf_allocate_textures(tc, textures, tex_width, 
> tex_height);
> +        int ret = imp->ops->allocate_textures(&tc->importer, textures, 
> tex_width, tex_height);
>          if (ret != VLC_SUCCESS)
>          {
> -            tc->vt->DeleteTextures(tc->tex_count, textures);
> -            memset(textures, 0, tc->tex_count * sizeof(GLuint));
> +            tc->vt->DeleteTextures(imp->tex_count, textures);
> +            memset(textures, 0, imp->tex_count * sizeof(GLuint));
>              return ret;
>          }
>      }
> @@ -391,16 +393,18 @@ GenTextures(const opengl_tex_converter_t *tc,
>  static void
>  DelTextures(const opengl_tex_converter_t *tc, GLuint *textures)
>  {
> -    tc->vt->DeleteTextures(tc->tex_count, textures);
> -    memset(textures, 0, tc->tex_count * sizeof(GLuint));
> +    const struct vlc_gl_importer *imp = &tc->importer;
> +    tc->vt->DeleteTextures(imp->tex_count, textures);
> +    memset(textures, 0, imp->tex_count * sizeof(GLuint));
>  }
>  
>  static int
>  opengl_link_program(struct prgm *prgm)
>  {
>      opengl_tex_converter_t *tc = prgm->tc;
> +    struct vlc_gl_importer *imp = &tc->importer;
>  
> -    GLuint vertex_shader = BuildVertexShader(tc, tc->tex_count);
> +    GLuint vertex_shader = BuildVertexShader(tc, imp->tex_count);
>      GLuint shaders[] = { tc->fshader, vertex_shader };
>  
>      /* Check shaders messages */
> @@ -474,11 +478,11 @@ opengl_link_program(struct prgm *prgm)
>      GET_ALOC(VertexPosition, "VertexPosition");
>      GET_ALOC(MultiTexCoord[0], "MultiTexCoord0");
>      /* MultiTexCoord 1 and 2 can be optimized out if not used */
> -    if (prgm->tc->tex_count > 1)
> +    if (imp->tex_count > 1)
>          GET_ALOC(MultiTexCoord[1], "MultiTexCoord1");
>      else
>          prgm->aloc.MultiTexCoord[1] = -1;
> -    if (prgm->tc->tex_count > 2)
> +    if (imp->tex_count > 2)
>          GET_ALOC(MultiTexCoord[2], "MultiTexCoord2");
>      else
>          prgm->aloc.MultiTexCoord[2] = -1;
> @@ -505,9 +509,10 @@ static void
>  opengl_deinit_program(vout_display_opengl_t *vgl, struct prgm *prgm)
>  {
>      opengl_tex_converter_t *tc = prgm->tc;
> +    struct vlc_gl_importer *imp = &tc->importer;
>      if (tc->p_module != NULL)
>          module_unneed(tc, tc->p_module);
> -    else if (tc->priv != NULL)
> +    else if (imp->priv != NULL)
>          opengl_tex_converter_generic_deinit(tc);
>      if (prgm->id != 0)
>          vgl->vt.DeleteProgram(prgm->id);
> @@ -532,22 +537,28 @@ opengl_init_program(vout_display_opengl_t *vgl, 
> vlc_video_context *context,
>      if (tc == NULL)
>          return VLC_ENOMEM;
>  
> +    struct vlc_gl_importer *imp = &tc->importer;
> +
>      tc->gl = vgl->gl;
>      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;
> +    imp->is_gles = true;
>      tc->glsl_version = 100;
>      tc->glsl_precision_header = "precision highp float;\n";
>  #else
> -    tc->is_gles = false;
> +    imp->is_gles = false;
>      tc->glsl_version = 120;
>      tc->glsl_precision_header = "";
>  #endif
> -    tc->fmt = *fmt;
> +
> +    imp->ops = NULL;
> +    imp->glexts = glexts;
> +    imp->fmt = *fmt;
> +
> +    imp->gl = tc->gl;
> +    imp->vt = tc->vt;
>  
>  #ifdef HAVE_LIBPLACEBO
>      // Create the main libplacebo context
> @@ -569,13 +580,13 @@ opengl_init_program(vout_display_opengl_t *vgl, 
> vlc_video_context *context,
>      int ret;
>      if (subpics)
>      {
> -        tc->fmt.i_chroma = VLC_CODEC_RGB32;
> +        imp->fmt.i_chroma = VLC_CODEC_RGB32;
>          /* Normal orientation and no projection for subtitles */
> -        tc->fmt.orientation = ORIENT_NORMAL;
> -        tc->fmt.projection_mode = PROJECTION_MODE_RECTANGULAR;
> -        tc->fmt.primaries = COLOR_PRIMARIES_UNDEF;
> -        tc->fmt.transfer = TRANSFER_FUNC_UNDEF;
> -        tc->fmt.space = COLOR_SPACE_UNDEF;
> +        imp->fmt.orientation = ORIENT_NORMAL;
> +        imp->fmt.projection_mode = PROJECTION_MODE_RECTANGULAR;
> +        imp->fmt.primaries = COLOR_PRIMARIES_UNDEF;
> +        imp->fmt.transfer = TRANSFER_FUNC_UNDEF;
> +        imp->fmt.space = COLOR_SPACE_UNDEF;
>  
>          ret = opengl_tex_converter_generic_init(tc, false);
>      }
> @@ -592,7 +603,7 @@ opengl_init_program(vout_display_opengl_t *vgl, 
> vlc_video_context *context,
>          if (desc->plane_count == 0)
>          {
>              /* Opaque chroma: load a module to handle it */
> -            tc->vctx = context;
> +            imp->vctx = context;
>              tc->p_module = module_need_var(tc, "glconv", "glconv");
>          }
>  
> @@ -612,8 +623,11 @@ opengl_init_program(vout_display_opengl_t *vgl, 
> vlc_video_context *context,
>          return VLC_EGENERIC;
>      }
>  
> -    assert(tc->fshader != 0 && tc->tex_target != 0 && tc->tex_count > 0 &&
> -           tc->pf_update != NULL && tc->pf_fetch_locations != NULL &&
> +    assert(tc->fshader != 0 &&
> +           imp->tex_target != 0 &&
> +           imp->tex_count > 0 &&
> +           imp->ops->update_textures != NULL &&
> +           tc->pf_fetch_locations != NULL &&
>             tc->pf_prepare_shader != NULL);
>  
>      prgm->tc = tc;
> @@ -625,9 +639,9 @@ opengl_init_program(vout_display_opengl_t *vgl, 
> vlc_video_context *context,
>          return VLC_EGENERIC;
>      }
>  
> -    getOrientationTransformMatrix(tc->fmt.orientation,
> +    getOrientationTransformMatrix(imp->fmt.orientation,
>                                    prgm->var.OrientationMatrix);
> -    getViewpointMatrixes(vgl, tc->fmt.projection_mode, prgm);
> +    getViewpointMatrixes(vgl, imp->fmt.projection_mode, prgm);
>  
>      return VLC_SUCCESS;
>  }
> @@ -838,18 +852,19 @@ vout_display_opengl_t 
> *vout_display_opengl_New(video_format_t *fmt,
>          return NULL;
>      }
>      GL_ASSERT_NOERROR();
> +
> +    const struct vlc_gl_importer *imp = &vgl->prgm->tc->importer;
>      /* Update the fmt to main program one */
> -    vgl->fmt = vgl->prgm->tc->fmt;
> +    vgl->fmt = imp->fmt;
>      /* The orientation is handled by the orientation matrix */
>      vgl->fmt.orientation = fmt->orientation;
>  
>      /* Texture size */
> -    const opengl_tex_converter_t *tc = vgl->prgm->tc;
> -    for (unsigned j = 0; j < tc->tex_count; j++) {
> -        const GLsizei w = vgl->fmt.i_visible_width  * tc->texs[j].w.num
> -                        / tc->texs[j].w.den;
> -        const GLsizei h = vgl->fmt.i_visible_height * tc->texs[j].h.num
> -                        / tc->texs[j].h.den;
> +    for (unsigned j = 0; j < imp->tex_count; j++) {
> +        const GLsizei w = vgl->fmt.i_visible_width  * 
> imp->texs[j].w.num
> +                        / imp->texs[j].w.den;
> +        const GLsizei h = vgl->fmt.i_visible_height * 
> imp->texs[j].h.num
> +                        / imp->texs[j].h.den;
>          if (vgl->supports_npot) {
>              vgl->tex_width[j]  = w;
>              vgl->tex_height[j] = h;
> @@ -860,9 +875,9 @@ vout_display_opengl_t 
> *vout_display_opengl_New(video_format_t *fmt,
>      }
>  
>      /* Allocates our textures */
> -    assert(!vgl->sub_prgm->tc->handle_texs_gen);
> +    assert(!vgl->sub_prgm->tc->importer.handle_texs_gen);
>  
> -    if (!vgl->prgm->tc->handle_texs_gen)
> +    if (!imp->handle_texs_gen)
>      {
>          ret = GenTextures(vgl->prgm->tc, vgl->tex_width, 
> vgl->tex_height,
>                            vgl->texture);
> @@ -883,7 +898,7 @@ vout_display_opengl_t 
> *vout_display_opengl_New(video_format_t *fmt,
>  
>      vgl->vt.GenBuffers(1, &vgl->vertex_buffer_object);
>      vgl->vt.GenBuffers(1, &vgl->index_buffer_object);
> -    vgl->vt.GenBuffers(vgl->prgm->tc->tex_count, vgl->texture_buffer_object);
> +    vgl->vt.GenBuffers(imp->tex_count, vgl->texture_buffer_object);
>  
>      /* Initial number of allocated buffer objects for subpictures, 
> will grow dynamically. */
>      int subpicture_buffer_object_count = 8;
> @@ -924,8 +939,9 @@ void 
> vout_display_opengl_Delete(vout_display_opengl_t *vgl)
>      vgl->vt.Finish();
>      vgl->vt.Flush();
>  
> -    const size_t main_tex_count = vgl->prgm->tc->tex_count;
> -    const bool main_del_texs = !vgl->prgm->tc->handle_texs_gen;
> +    const struct vlc_gl_importer *imp = &vgl->prgm->tc->importer;
> +    const size_t main_tex_count = imp->tex_count;
> +    const bool main_del_texs = !imp->handle_texs_gen;
>  
>      if (vgl->pool)
>          picture_pool_Release(vgl->pool);
> @@ -1031,7 +1047,8 @@ void 
> vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
>  bool vout_display_opengl_HasPool(const vout_display_opengl_t *vgl)
>  {
>      opengl_tex_converter_t *tc = vgl->prgm->tc;
> -    return tc->pf_get_pool != NULL;
> +    struct vlc_gl_importer *imp = &tc->importer;
> +    return imp->ops->get_pool != NULL;
>  }
>  
>  picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t 
> *vgl, unsigned requested_count)
> @@ -1042,10 +1059,11 @@ picture_pool_t 
> *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned
>          return vgl->pool;
>  
>      opengl_tex_converter_t *tc = vgl->prgm->tc;
> +    const struct vlc_gl_importer *imp = &tc->importer;
>      requested_count = __MIN(VLCGL_PICTURE_MAX, requested_count);
>      /* Allocate with tex converter pool callback if it exists */
> -    assert(tc->pf_get_pool != NULL);
> -    vgl->pool = tc->pf_get_pool(tc, requested_count);
> +    assert(imp->ops->get_pool != NULL);
> +    vgl->pool = imp->ops->get_pool(imp, requested_count);
>      if (!vgl->pool)
>          goto error;
>      return vgl->pool;
> @@ -1061,10 +1079,11 @@ int 
> vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
>      GL_ASSERT_NOERROR();
>  
>      opengl_tex_converter_t *tc = vgl->prgm->tc;
> +    struct vlc_gl_importer *imp = &tc->importer;
>  
>      /* Update the texture */
> -    int ret = tc->pf_update(tc, vgl->texture, vgl->tex_width, 
> vgl->tex_height,
> -                            picture, NULL);
> +    int ret = imp->ops->update_textures(imp, vgl->texture, 
> vgl->tex_width, vgl->tex_height,
> +                                        picture, NULL);
>      if (ret != VLC_SUCCESS)
>          return ret;
>  
> @@ -1075,6 +1094,7 @@ int 
> vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
>      vgl->region       = NULL;
>  
>      tc = vgl->sub_prgm->tc;
> +    imp = &tc->importer;
>      if (subpicture) {
>  
>          int count = 0;
> @@ -1132,8 +1152,9 @@ int 
> vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
>              /* Use the visible pitch of the region */
>              r->p_picture->p[0].i_visible_pitch = r->fmt.i_visible_width
>                                                 * 
> r->p_picture->p[0].i_pixel_pitch;
> -            ret = tc->pf_update(tc, &glr->texture, &glr->width, 
> &glr->height,
> -                                r->p_picture, &pixels_offset);
> +            ret = imp->ops->update_textures(imp, &glr->texture,
> +                                            &glr->width, &glr->height,
> +                                            r->p_picture, 
> &pixels_offset);
>          }
>      }
>      for (int i = 0; i < last_count; i++) {
> @@ -1420,6 +1441,8 @@ static int SetupCoords(vout_display_opengl_t *vgl,
>                         const float *left, const float *top,
>                         const float *right, const float *bottom)
>  {
> +    const struct vlc_gl_importer *imp = &vgl->prgm->tc->importer;
> +
>      GLfloat *vertexCoord, *textureCoord;
>      GLushort *indices;
>      unsigned nbVertices, nbIndices;
> @@ -1428,19 +1451,19 @@ static int SetupCoords(vout_display_opengl_t 
> *vgl,
>      switch (vgl->fmt.projection_mode)
>      {
>      case PROJECTION_MODE_RECTANGULAR:
> -        i_ret = BuildRectangle(vgl->prgm->tc->tex_count,
> +        i_ret = BuildRectangle(imp->tex_count,
>                                 &vertexCoord, &textureCoord, 
> &nbVertices,
>                                 &indices, &nbIndices,
>                                 left, top, right, bottom);
>          break;
>      case PROJECTION_MODE_EQUIRECTANGULAR:
> -        i_ret = BuildSphere(vgl->prgm->tc->tex_count,
> +        i_ret = BuildSphere(imp->tex_count,
>                              &vertexCoord, &textureCoord, &nbVertices,
>                              &indices, &nbIndices,
>                              left, top, right, bottom);
>          break;
>      case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:
> -        i_ret = BuildCube(vgl->prgm->tc->tex_count,
> +        i_ret = BuildCube(imp->tex_count,
>                            (float)vgl->fmt.i_cubemap_padding / 
> vgl->fmt.i_width,
>                            (float)vgl->fmt.i_cubemap_padding / 
> vgl->fmt.i_height,
>                            &vertexCoord, &textureCoord, &nbVertices,
> @@ -1455,7 +1478,7 @@ static int SetupCoords(vout_display_opengl_t *vgl,
>      if (i_ret != VLC_SUCCESS)
>          return i_ret;
>  
> -    for (unsigned j = 0; j < vgl->prgm->tc->tex_count; j++)
> +    for (unsigned j = 0; j < imp->tex_count; j++)
>      {
>          vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->texture_buffer_object[j]);
>          vgl->vt.BufferData(GL_ARRAY_BUFFER, nbVertices * 2 * sizeof(GLfloat),
> @@ -1482,12 +1505,13 @@ static int SetupCoords(vout_display_opengl_t *vgl,
>  static void DrawWithShaders(vout_display_opengl_t *vgl, struct prgm *prgm)
>  {
>      opengl_tex_converter_t *tc = prgm->tc;
> +    const struct vlc_gl_importer *imp = &tc->importer;
>      tc->pf_prepare_shader(tc, vgl->tex_width, vgl->tex_height, 1.0f);
>  
> -    for (unsigned j = 0; j < vgl->prgm->tc->tex_count; j++) {
> +    for (unsigned j = 0; j < imp->tex_count; j++) {
>          assert(vgl->texture[j] != 0);
>          vgl->vt.ActiveTexture(GL_TEXTURE0+j);
> -        vgl->vt.BindTexture(tc->tex_target, vgl->texture[j]);
> +        vgl->vt.BindTexture(imp->tex_target, vgl->texture[j]);
>  
>          vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->texture_buffer_object[j]);
>  
> @@ -1502,8 +1526,9 @@ 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;
> +    const GLfloat *tm = NULL;
> +    if (imp->ops && imp->ops->get_transform_matrix)
> +        tm = imp->ops->get_transform_matrix(imp);
>      if (!tm)
>          tm = identity;
>  
> @@ -1544,6 +1569,8 @@ static void 
> TextureCropForStereo(vout_display_opengl_t *vgl,
>                                   float *left, float *top,
>                                   float *right, float *bottom)
>  {
> +    const struct vlc_gl_importer *imp = &vgl->prgm->tc->importer;
> +
>      float stereoCoefs[2];
>      float stereoOffsets[2];
>  
> @@ -1553,7 +1580,7 @@ static void 
> TextureCropForStereo(vout_display_opengl_t *vgl,
>          // Display only the left eye.
>          stereoCoefs[0] = 1; stereoCoefs[1] = 0.5;
>          stereoOffsets[0] = 0; stereoOffsets[1] = 0;
> -        GetTextureCropParamsForStereo(vgl->prgm->tc->tex_count,
> +        GetTextureCropParamsForStereo(imp->tex_count,
>                                        stereoCoefs, stereoOffsets,
>                                        left, top, right, bottom);
>          break;
> @@ -1561,7 +1588,7 @@ static void 
> TextureCropForStereo(vout_display_opengl_t *vgl,
>          // Display only the left eye.
>          stereoCoefs[0] = 0.5; stereoCoefs[1] = 1;
>          stereoOffsets[0] = 0; stereoOffsets[1] = 0;
> -        GetTextureCropParamsForStereo(vgl->prgm->tc->tex_count,
> +        GetTextureCropParamsForStereo(imp->tex_count,
>                                        stereoCoefs, stereoOffsets,
>                                        left, top, right, bottom);
>          break;
> @@ -1592,11 +1619,12 @@ int 
> vout_display_opengl_Display(vout_display_opengl_t *vgl,
>          float right[PICTURE_PLANE_MAX];
>          float bottom[PICTURE_PLANE_MAX];
>          const opengl_tex_converter_t *tc = vgl->prgm->tc;
> -        for (unsigned j = 0; j < tc->tex_count; j++)
> +        const struct vlc_gl_importer *imp = &tc->importer;
> +        for (unsigned j = 0; j < tc->importer.tex_count; j++)
>          {
> -            float scale_w = (float)tc->texs[j].w.num / 
> tc->texs[j].w.den
> +            float scale_w = (float)imp->texs[j].w.num / 
> imp->texs[j].w.den
>                            / vgl->tex_width[j];
> -            float scale_h = (float)tc->texs[j].h.num / 
> tc->texs[j].h.den
> +            float scale_h = (float)imp->texs[j].h.num / 
> imp->texs[j].h.den
>                            / vgl->tex_height[j];
>  
>              /* Warning: if NPOT is not supported a larger texture is
> @@ -1633,6 +1661,7 @@ int 
> vout_display_opengl_Display(vout_display_opengl_t *vgl,
>      struct prgm *prgm = vgl->sub_prgm;
>      GLuint program = prgm->id;
>      opengl_tex_converter_t *tc = prgm->tc;
> +    const struct vlc_gl_importer *imp = &tc->importer;
>      vgl->vt.UseProgram(program);
>  
>      vgl->vt.Enable(GL_BLEND);
> @@ -1672,7 +1701,7 @@ int 
> vout_display_opengl_Display(vout_display_opengl_t *vgl,
>          };
>  
>          assert(glr->texture != 0);
> -        vgl->vt.BindTexture(tc->tex_target, glr->texture);
> +        vgl->vt.BindTexture(imp->tex_target, glr->texture);
>  
>          tc->pf_prepare_shader(tc, &glr->width, &glr->height, glr->alpha);
>  
> -- 
> 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