[vlc-devel] [PATCH 1/2] vout/opengl: add direct rendering support (OpenGL 4.4)

Thomas Guillem thomas at gllm.fr
Thu Jan 5 15:31:34 CET 2017



On Tue, Jan 3, 2017, at 17:18, Hugo Beauzée-Luyssen wrote:
> On 01/03/2017 04:45 PM, Thomas Guillem wrote:
> > This commit adds support for direct rendering with YUV/RGB software chromas.
> > This is done using Pixel Buffer Object (PBO, A Buffer Object that is used for
> > asynchronous pixel transfer operations) [1][2]. PBO are present since a long
> > time for OpenGL and since 3.0 for OpenGLES.
> >
> > But there is a problem, VLC software decoders and video filters might need to
> > read pictures buffers while they're being displayed. Therefore, the basic use
> > case of PBOs can't work (since you need to unmap the buffer before displaying
> > it).
> >
> > To solve this issue, we need to use persistent mapped buffers[3]. This can be
> > done using the glBufferStorage() function with the GL_MAP_PERSISTENT_BIT flag.
> >
> > Unfortunately, this new API is only present since OpenGL 4.4 and as an
> > extension since OpenGLES 3.1 (so no Android, macos and ios support).
> >
> > References:
> > [1]: https://www.khronos.org/opengl/wiki/Pixel_Buffer_Object
> > [2]: http://www.songho.ca/opengl/gl_pbo.html
> > [3]: https://www.khronos.org/opengl/wiki/Buffer_Object_Streaming
> > ---
> >  NEWS                                      |   1 +
> >  modules/video_output/opengl/converters.c  | 300 +++++++++++++++++++++++++++++-
> >  modules/video_output/opengl/internal.h    |  22 +++
> >  modules/video_output/opengl/vout_helper.c |  24 +++
> >  4 files changed, 340 insertions(+), 7 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index 8aba9cfc4d..350098fcbe 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -150,6 +150,7 @@ Video ouput:
> >   * EFL Evas video output with Tizen TBM Surface support
> >   * New OpenGL provider for Windows
> >   * Drop OpenGL 1.x and OpenGL ES 1 support
> > + * Direct rendering with OpenGL (starting OpenGL 4.4)
> >
> >  Text renderer:
> >   * CTL support through Harfbuzz in the Freetype module
> > diff --git a/modules/video_output/opengl/converters.c b/modules/video_output/opengl/converters.c
> > index 8b6b4b40a6..f278bb96ae 100644
> > --- a/modules/video_output/opengl/converters.c
> > +++ b/modules/video_output/opengl/converters.c
> > @@ -22,10 +22,11 @@
> >  # include "config.h"
> >  #endif
> >
> > -#include <vlc_memory.h>
> > -
> >  #include <assert.h>
> > +#include <limits.h>
> > +#include <stdlib.h>
> >
> > +#include <vlc_memory.h>
> >  #include "internal.h"
> >
> >  #ifndef GL_RED
> > @@ -35,6 +36,30 @@
> >  #define GL_R16 0
> >  #endif
> >
> > +#ifdef VLCGL_HAS_PBO
> > +# ifndef GL_UNPACK_ROW_LENGTH
> > +#  error "PBO without GL_UNPACK_ROW_LENGTH"
> 
> Shouldn't this be done in opengl/internal.h to conditionally enable PBO 
> support instead?

Actually, this is not needed anymore.

> 
> > +# endif
> > +#endif
> > +
> > +#ifndef NDEBUG
> > +static __thread bool dbg_is_glthread = false;
> 
> I'm not sure this plays well on all compilers

I'll remove it, it was for debug and now I'm sure that these asserts
can't happen.

> 
> > +#define ASSERT_GLTHREAD() assert(dbg_is_glthread)
> > +#else
> > +#define ASSERT_GLTHREAD()
> > +#endif
> > +
> > +#ifdef VLCGL_HAS_PBO
> > +struct picture_sys_t
> > +{
> > +    const opengl_tex_converter_t *tc;
> > +    GLuint      buffers[PICTURE_PLANE_MAX];
> > +    size_t      bytes[PICTURE_PLANE_MAX];
> 
> Wouldn't it be clearer to have a struct { GLuint, size_t 
> }[PICTURE_PLANE_MAX] ?

Yes but less convenient, there are some operations that are done on a
array of GLuint (glGenBuffers/glDeleteBuffers).

> 
> > +    GLsync      fence;
> > +    unsigned    index;
> > +};
> > +#endif
> > +
> >  struct priv
> >  {
> >      GLint  tex_internal;
> > @@ -45,6 +70,12 @@ struct priv
> >      void * texture_temp_buf;
> >      size_t texture_temp_buf_size;
> >  #endif
> > +#ifdef VLCGL_HAS_PBO
> > +    struct {
> > +        picture_t *pics[VLCGL_PICTURE_MAX];
> > +        unsigned long long list;
> > +    } ongpu;
> > +#endif
> >  };
> >
> >  struct yuv_priv
> > @@ -53,6 +84,242 @@ struct yuv_priv
> >      GLfloat local_value[16];
> >  };
> >
> > +#ifdef VLCGL_HAS_PBO
> > +static int
> > +pbo_map(const opengl_tex_converter_t *tc, picture_t *pic)
> > +{
> > +    picture_sys_t *picsys = pic->p_sys;
> > +
> > +    tc->api->GenBuffers(pic->i_planes, picsys->buffers);
> > +
> > +    const GLbitfield access = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT |
> > +                              GL_MAP_PERSISTENT_BIT;
> > +    for (int i = 0; i < pic->i_planes; ++i)
> > +    {
> > +        tc->api->BindBuffer(GL_PIXEL_UNPACK_BUFFER, picsys->buffers[i]);
> > +        tc->api->BufferStorage(GL_PIXEL_UNPACK_BUFFER, picsys->bytes[i], NULL,
> > +                               access);
> > +
> > +        pic->p[i].p_pixels =
> > +            tc->api->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, picsys->bytes[i],
> > +                                    access);
> > +
> > +        if (pic->p[i].p_pixels == NULL)
> > +        {
> > +            msg_Err(tc->parent, "could not map PBO buffers");
> > +            for (i = i - 1; i >= 0; --i)
> > +            {
> > +                tc->api->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
> > +                                    picsys->buffers[i]);
> > +                tc->api->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
> > +            }
> > +            tc->api->DeleteBuffers(pic->i_planes, picsys->buffers);
> > +            memset(picsys->buffers, 0, PICTURE_PLANE_MAX * sizeof(GLuint));
> > +            return VLC_EGENERIC;
> > +        }
> > +    }
> > +    return VLC_SUCCESS;
> > +}
> > +
> > +/** Find next (bit) set */
> > +static int fnsll(unsigned long long x, unsigned i)
> 
> This could be inlined
> 
> > +{
> > +    if (i >= CHAR_BIT * sizeof (x))
> > +        return 0;
> > +    return ffsll(x & ~((1ULL << i) - 1));
> > +}
> > +
> > +static void
> > +pbo_release_gpupics(const opengl_tex_converter_t *tc, bool force)
> > +{
> > +    struct priv *priv = tc->priv;
> > +
> > +    /* Release all pictures that are not used by the GPU anymore */
> > +    for (unsigned i = ffsll(priv->ongpu.list); i;
> > +         i = fnsll(priv->ongpu.list, i))
> > +    {
> > +        assert(priv->ongpu.pics[i - 1] != NULL);
> > +
> > +        picture_t *pic = priv->ongpu.pics[i - 1];
> > +        picture_sys_t *picsys = pic->p_sys;
> > +
> > +        assert(picsys->fence != NULL);
> > +        GLenum wait = force ? GL_ALREADY_SIGNALED
> > +                            : tc->api->ClientWaitSync(picsys->fence, 0, 0);
> > +
> > +        if (wait == GL_ALREADY_SIGNALED || wait == GL_CONDITION_SATISFIED)
> > +        {
> > +            tc->api->DeleteSync(picsys->fence);
> > +            picsys->fence = NULL;
> > +
> > +            priv->ongpu.list &= ~(1ULL << (i - 1));
> > +            priv->ongpu.pics[i - 1] = NULL;
> > +            picture_Release(pic);
> > +        }
> > +    }
> > +}
> > +
> > +static int
> > +pbo_common_update(const opengl_tex_converter_t *tc, const GLuint *textures,
> > +                  unsigned width, unsigned height, picture_t *pic)
> > +{
> > +    struct priv *priv = tc->priv;
> > +    picture_sys_t *picsys = pic->p_sys;
> > +
> > +    for (int i = 0; i < pic->i_planes; i++)
> > +    {
> > +        tc->api->BindBuffer(GL_PIXEL_UNPACK_BUFFER, picsys->buffers[i]);
> > +        if (picsys->fence == NULL)
> > +            tc->api->FlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,
> > +                                            picsys->bytes[i]);
> > +        glActiveTexture(GL_TEXTURE0 + i);
> > +        glClientActiveTexture(GL_TEXTURE0 + i);
> > +        glBindTexture(tc->tex_target, textures[i]);
> > +
> > +        glPixelStorei(GL_UNPACK_ROW_LENGTH,
> > +                      pic->p[i].i_pitch / pic->p[i].i_pixel_pitch);
> > +
> > +        glTexSubImage2D(tc->tex_target, 0, 0, 0,
> > +                        width * tc->desc->p[i].w.num / tc->desc->p[i].w.den,
> > +                        height * tc->desc->p[i].h.num / tc->desc->p[i].h.den,
> > +                        priv->tex_format, priv->tex_type, NULL);
> > +    }
> > +
> > +    bool hold;
> > +    if (picsys->fence == NULL)
> > +        hold = true;
> > +    else
> > +    {
> > +        /* The picture is already held */
> > +        hold = false;
> > +        tc->api->DeleteSync(picsys->fence);
> > +    }
> > +
> > +    picsys->fence = tc->api->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
> > +    if (pic->p_sys->fence == NULL)
> > +    {
> > +        /* Error (corner case): don't hold the picture */
> > +        hold = false;
> > +    }
> > +
> > +    pbo_release_gpupics(tc, false);
> > +
> > +    if (hold)
> > +    {
> > +        /* Hold the picture while it's used by the GPU */
> > +        unsigned index = pic->p_sys->index;
> > +
> > +        priv->ongpu.list |= 1ULL << index;
> > +        assert(priv->ongpu.pics[index] == NULL);
> > +        priv->ongpu.pics[index] = pic;
> > +        picture_Hold(pic);
> > +    }
> > +
> > +    /* turn off pbo */
> > +    tc->api->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
> > +
> > +    return VLC_SUCCESS;
> > +}
> > +
> > +static void
> > +picture_destroy_cb(picture_t *pic)
> > +{
> > +    picture_sys_t *picsys = pic->p_sys;
> > +    const opengl_tex_converter_t *tc = picsys->tc;
> > +
> > +    ASSERT_GLTHREAD();
> > +
> > +    if (picsys->buffers[0] != 0)
> > +    {
> > +        for (int i = 0; i < pic->i_planes; ++i)
> > +        {
> > +            tc->api->BindBuffer(GL_PIXEL_UNPACK_BUFFER, picsys->buffers[i]);
> > +            tc->api->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
> > +        }
> > +        tc->api->DeleteBuffers(pic->i_planes, picsys->buffers);
> > +    }
> > +    free(picsys);
> > +    free(pic);
> > +}
> > +
> > +static picture_pool_t *
> > +tc_common_get_pool(const opengl_tex_converter_t *tc, const video_format_t *fmt,
> > +                   unsigned requested_count, const GLuint *textures)
> > +{
> > +    struct priv *priv = tc->priv;
> > +    picture_t *pictures[VLCGL_PICTURE_MAX];
> > +    unsigned count;
> > +    (void) textures;
> > +
> > +    ASSERT_GLTHREAD();
> > +    priv->ongpu.list = 0;
> > +
> > +    for (count = 0; count < requested_count; count++)
> > +    {
> > +        picture_sys_t *picsys = calloc(1, sizeof(*picsys));
> > +        if (unlikely(picsys == NULL))
> > +            break;
> > +        picsys->tc = tc;
> > +        picsys->index = count;
> > +        picture_resource_t rsc = {
> > +            .p_sys = picsys,
> > +            .pf_destroy = picture_destroy_cb,
> > +        };
> > +
> > +        picture_t *pic = pictures[count] = picture_NewFromResource(fmt, &rsc);
> > +        if (pic == NULL)
> > +        {
> > +            free(picsys);
> > +            break;
> > +        }
> > +        if (picture_Setup(pic, fmt))
> > +        {
> > +            picture_Release(pic);
> > +            break;
> > +        }
> > +
> > +        assert(pic->i_planes > 0
> > +            && (unsigned) pic->i_planes == tc->desc->plane_count);
> > +
> > +        for (int i = 0; i < pic->i_planes; ++i)
> > +        {
> > +            const plane_t *p = &pic->p[i];
> > +
> > +            if( p->i_pitch < 0 || p->i_lines <= 0 ||
> > +                (size_t)p->i_pitch > SIZE_MAX/p->i_lines )
> > +                goto error;
> > +            picsys->bytes[i] = (p->i_pitch * p->i_lines) + 15 / 16 * 16;
> > +            assert(picsys->bytes[i] == pictures[0]->p_sys->bytes[i]);
> > +        }
> > +
> > +        if (pbo_map(tc, pic) != VLC_SUCCESS)
> > +        {
> > +            picture_Release(pic);
> > +            break;
> > +        }
> > +    }
> > +
> > +    /* We need minumum 2 pbo buffers */
> > +    if (count <= 1)
> > +        goto error;
> > +
> > +    /* turn off pbo */
> > +    tc->api->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
> > +
> > +    /* Wrap the pictures into a pool */
> > +    picture_pool_t *pool = picture_pool_New(count, pictures);
> > +    if (!pool)
> > +        goto error;
> > +    return pool;
> > +
> > +error:
> > +    for (unsigned i = 0; i < count; i++)
> > +        picture_Release(pictures[i]);
> > +
> > +    return NULL;
> > +}
> > +#endif /* VLCGL_HAS_PBO */
> > +
> >  static int
> >  tc_common_gen_textures(const opengl_tex_converter_t *tc,
> >                         const GLsizei *tex_width, const GLsizei *tex_height,
> > @@ -153,6 +420,11 @@ tc_common_update(const opengl_tex_converter_t *tc, const GLuint *textures,
> >                   unsigned width, unsigned height,
> >                   picture_t *pic, const size_t *plane_offset)
> >  {
> > +#ifdef VLCGL_HAS_PBO
> > +    if (pic->p_sys != NULL)
> > +        return pbo_common_update(tc, textures, width, height, pic);
> > +#endif
> > +
> >      int ret = VLC_SUCCESS;
> >      for (unsigned i = 0; i < tc->desc->plane_count && ret == VLC_SUCCESS; i++)
> >      {
> > @@ -174,12 +446,17 @@ tc_common_update(const opengl_tex_converter_t *tc, const GLuint *textures,
> >  static void
> >  tc_common_release(const opengl_tex_converter_t *tc)
> >  {
> > -    tc->api->DeleteShader(tc->fragment_shader);
> > +    if (tc->fragment_shader != 0)
> > +        tc->api->DeleteShader(tc->fragment_shader);
> >
> >  #ifndef GL_UNPACK_ROW_LENGTH
> >      struct priv *priv = tc->priv;
> >      free(priv->texture_temp_buf);
> >  #endif
> > +#ifdef VLCGL_HAS_PBO
> > +    pbo_release_gpupics(tc, true);
> > +#endif
> > +
> >      free(tc->priv);
> >  }
> >
> > @@ -200,11 +477,20 @@ common_init(opengl_tex_converter_t *tc, size_t priv_size, vlc_fourcc_t chroma,
> >      tc->pf_update       = tc_common_update;
> >      tc->pf_release      = tc_common_release;
> >
> > +#ifdef VLCGL_HAS_PBO
> > +    if (tc->supports_pbo)
> > +        tc->pf_get_pool = tc_common_get_pool;
> > +#endif
> > +
> >      tc->tex_target      = GL_TEXTURE_2D;
> >      priv->tex_internal  = tex_internal;
> >      priv->tex_format    = tex_format;
> >      priv->tex_type      = tex_type;
> >
> > +#ifndef NDEBUG
> > +    dbg_is_glthread = true;
> > +#endif
> > +
> >      return VLC_SUCCESS;
> >  }
> >
> > @@ -258,7 +544,7 @@ opengl_tex_converter_rgba_init(const video_format_t *fmt,
> >      tc->fragment_shader = tc->api->CreateShader(GL_FRAGMENT_SHADER);
> >      if (tc->fragment_shader == 0)
> >      {
> > -        free(tc->priv);
> > +        tc_common_release(tc);
> >          return VLC_EGENERIC;
> >      }
> >      tc->api->ShaderSource(tc->fragment_shader, 1, &code, NULL);
> > @@ -432,7 +718,7 @@ opengl_tex_converter_yuv_init(const video_format_t *fmt,
> >                   swap_uv ? 'z' : 'y',
> >                   swap_uv ? 'y' : 'z') < 0)
> >      {
> > -        free(tc->priv);
> > +        tc_common_release(tc);
> >          return VLC_ENOMEM;
> >      }
> >
> > @@ -448,7 +734,7 @@ opengl_tex_converter_yuv_init(const video_format_t *fmt,
> >      tc->fragment_shader = tc->api->CreateShader(GL_FRAGMENT_SHADER);
> >      if (tc->fragment_shader == 0)
> >      {
> > -        free(tc->priv);
> > +        tc_common_release(tc);
> >          free(code);
> >          return VLC_EGENERIC;
> >      }
> > @@ -515,7 +801,7 @@ opengl_tex_converter_xyz12_init(const video_format_t *fmt,
> >      tc->fragment_shader = tc->api->CreateShader(GL_FRAGMENT_SHADER);
> >      if (tc->fragment_shader == 0)
> >      {
> > -        free(tc->priv);
> > +        tc_common_release(tc);
> >          return VLC_EGENERIC;
> >      }
> >      tc->api->ShaderSource(tc->fragment_shader, 1, &code, NULL);
> > diff --git a/modules/video_output/opengl/internal.h b/modules/video_output/opengl/internal.h
> > index d925561b81..020f9b5cd3 100644
> > --- a/modules/video_output/opengl/internal.h
> > +++ b/modules/video_output/opengl/internal.h
> > @@ -33,6 +33,9 @@
> >  #   define GLSL_VERSION "120"
> >  #   define VLCGL_TEXTURE_COUNT 1
> >  #   define VLCGL_PICTURE_MAX 128
> > +#   ifdef GL_VERSION_4_4
> > +#       define VLCGL_HAS_PBO
> > +#   endif
> >  #   define PRECISION ""
> >  #endif
> >
> > @@ -61,6 +64,15 @@
> >  #   define PFNGLGENBUFFERSPROC               typeof(glGenBuffers)*
> >  #   define PFNGLBINDBUFFERPROC               typeof(glBindBuffer)*
> >  #   define PFNGLBUFFERDATAPROC               typeof(glBufferData)*
> > +#   ifdef VLCGL_HAS_PBO
> > +#    define PFNGLBUFFERSTORAGEPROC           typeof(glBufferStorage)*
> > +#    define PFNGLMAPBUFFERRANGEPROC          typeof(glMapBufferRange)*
> > +#    define PFNGLFLUSHMAPPEDBUFFERRANGEPROC  typeof(glFlushMappedBufferRange)*
> > +#    define PFNGLUNMAPBUFFERPROC             typeof(glUnmapBuffer)*
> > +#    define PFNGLFENCESYNCPROC               typeof(glFenceSync)*
> > +#    define PFNGLDELETESYNCPROC              typeof(glDeleteSync)*
> > +#    define PFNGLCLIENTWAITSYNCPROC          typeof(glClientWaitSync)*
> > +#   endif
> >  #   define PFNGLDELETEBUFFERSPROC            typeof(glDeleteBuffers)*
> >  #if defined(__APPLE__)
> >  #   import <CoreFoundation/CoreFoundation.h>
> > @@ -104,6 +116,15 @@ typedef struct {
> >      PFNGLGENBUFFERSPROC    GenBuffers;
> >      PFNGLBINDBUFFERPROC    BindBuffer;
> >      PFNGLBUFFERDATAPROC    BufferData;
> > +#ifdef VLCGL_HAS_PBO
> > +    PFNGLBUFFERSTORAGEPROC          BufferStorage;
> > +    PFNGLMAPBUFFERRANGEPROC         MapBufferRange;
> > +    PFNGLFLUSHMAPPEDBUFFERRANGEPROC FlushMappedBufferRange;
> > +    PFNGLUNMAPBUFFERPROC            UnmapBuffer;
> > +    PFNGLFENCESYNCPROC              FenceSync;
> > +    PFNGLDELETESYNCPROC             DeleteSync;
> > +    PFNGLCLIENTWAITSYNCPROC         ClientWaitSync;
> > +#endif
> >      PFNGLDELETEBUFFERSPROC DeleteBuffers;
> >
> >  #if defined(_WIN32)
> > @@ -137,6 +158,7 @@ typedef int (*opengl_tex_converter_init_cb)(const video_format_t *fmt,
> >   */
> >  struct opengl_tex_converter_t
> >  {
> > +    bool supports_pbo;
> >      /* Pointer to object parent, set by the caller of the init cb */
> >      vlc_object_t *parent;
> >      /* Function pointer to shaders commands, set by the caller of the init cb */
> > diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
> > index 4d0b6a676e..5c0185ef78 100644
> > --- a/modules/video_output/opengl/vout_helper.c
> > +++ b/modules/video_output/opengl/vout_helper.c
> > @@ -220,6 +220,15 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
> >      api->BindBuffer    = GET_PROC_ADDR(glBindBuffer);
> >      api->BufferData    = GET_PROC_ADDR(glBufferData);
> >      api->DeleteBuffers = GET_PROC_ADDR(glDeleteBuffers);
> > +#ifdef VLCGL_HAS_PBO
> > +    api->BufferStorage          = GET_PROC_ADDR(glBufferStorage);
> > +    api->MapBufferRange         = GET_PROC_ADDR(glMapBufferRange);
> > +    api->FlushMappedBufferRange = GET_PROC_ADDR(glFlushMappedBufferRange);
> > +    api->UnmapBuffer            = GET_PROC_ADDR(glUnmapBuffer);
> > +    api->FenceSync              = GET_PROC_ADDR(glFenceSync);
> > +    api->DeleteSync             = GET_PROC_ADDR(glDeleteSync);
> > +    api->ClientWaitSync         = GET_PROC_ADDR(glClientWaitSync);
> > +#endif
> >  #undef GET_PROC_ADDR
> >
> >      if (!vgl->api.CreateShader || !vgl->api.ShaderSource || !vgl->api.CreateProgram)
> > @@ -249,6 +258,19 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
> >                           HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot");
> >  #endif
> >
> > +#if defined (VLCGL_HAS_PBO)
> > +    const bool supports_pbo = vgl->supports_npot && api->BufferStorage
> > +        && api->MapBufferRange && api->FlushMappedBufferRange
> > +        && api->UnmapBuffer && api->FenceSync && api->DeleteSync
> > +        && api->ClientWaitSync
> > +        && HasExtension(extensions, "GL_ARB_pixel_buffer_object")
> > +        && HasExtension(extensions, "GL_ARB_buffer_storage");
> > +#else
> > +    const bool supports_pbo = false;
> > +#endif
> > +    msg_Dbg(gl, "PBO support (for direct rendering): %s",
> > +            supports_pbo ? "On" : "Off");
> > +
> >      /* Initialize with default chroma */
> >      vgl->fmt = *fmt;
> >      vgl->fmt.i_chroma = VLC_CODEC_RGB32;
> > @@ -263,6 +285,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
> >  #   endif
> >      opengl_tex_converter_t tex_conv;
> >      opengl_tex_converter_t rgba_tex_conv = {
> > +        .supports_pbo = supports_pbo,
> >          .parent = VLC_OBJECT(vgl->gl),
> >          .api = &vgl->api,
> >          .orientation = fmt->orientation,
> > @@ -279,6 +302,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
> >      for (size_t i = 0; i < ARRAY_SIZE(opengl_tex_converter_init_cbs); ++i)
> >      {
> >          tex_conv = (opengl_tex_converter_t) {
> > +            .supports_pbo = supports_pbo,
> >              .parent = VLC_OBJECT(vgl->gl),
> >              .api = &vgl->api,
> >              .orientation = fmt->orientation,
> >
> 
> _______________________________________________
> 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