[vlc-devel] [PATCH 12/24] opengl: implement subpictures renderer

Alexandre Janniaux ajanni at videolabs.io
Tue Jan 28 16:53:56 CET 2020


Hi,

I haven't checked everything yet, but as it is code extraction
maybe previous copyrights notice must be copied with them?

Regards,
--
Alexandre Janniaux
Videolabs

On Mon, Jan 27, 2020 at 09:20:02PM +0100, Romain Vimont wrote:
> Extract the subpictures rendering into a separate component, using its
> own simplified vertex and fragment shaders.
>
> This simplifies vout_helper.c.
> ---
>  modules/video_output/Makefile.am           |   4 +-
>  modules/video_output/opengl/sub_renderer.c | 451 +++++++++++++++++++++
>  modules/video_output/opengl/sub_renderer.h |  79 ++++
>  modules/video_output/opengl/vout_helper.c  | 286 ++-----------
>  4 files changed, 564 insertions(+), 256 deletions(-)
>  create mode 100644 modules/video_output/opengl/sub_renderer.c
>  create mode 100644 modules/video_output/opengl/sub_renderer.h
>
> diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
> index 6bccecf006..e8f35f2bd0 100644
> --- a/modules/video_output/Makefile.am
> +++ b/modules/video_output/Makefile.am
> @@ -7,7 +7,9 @@ OPENGL_COMMONSOURCES = video_output/opengl/vout_helper.c \
>  	video_output/opengl/gl_common.h video_output/opengl/interop.h \
>  	video_output/opengl/vout_helper.h video_output/opengl/converter.h \
>  	video_output/opengl/internal.h video_output/opengl/fragment_shaders.c \
> -	video_output/opengl/interop.c video_output/opengl/interop_sw.c
> +	video_output/opengl/interop.c video_output/opengl/interop_sw.c \
> +	video_output/opengl/sub_renderer.c \
> +	video_output/opengl/sub_renderer.h
>  if HAVE_LIBPLACEBO
>  OPENGL_COMMONSOURCES += video_output/placebo_utils.c video_output/placebo_utils.h
>  endif
> diff --git a/modules/video_output/opengl/sub_renderer.c b/modules/video_output/opengl/sub_renderer.c
> new file mode 100644
> index 0000000000..1a60fb86b9
> --- /dev/null
> +++ b/modules/video_output/opengl/sub_renderer.c
> @@ -0,0 +1,451 @@
> +/*****************************************************************************
> + * sub_renderer.c
> + *****************************************************************************
> + * Copyright (C) 2020 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.
> + *****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include "sub_renderer.h"
> +
> +#include <assert.h>
> +#include <vlc_common.h>
> +#include <vlc_es.h>
> +#include <vlc_subpicture.h>
> +
> +#include "interop.h"
> +#include "vout_helper.h"
> +
> +typedef struct {
> +    GLuint   texture;
> +    GLsizei  width;
> +    GLsizei  height;
> +
> +    float    alpha;
> +
> +    float    top;
> +    float    left;
> +    float    bottom;
> +    float    right;
> +
> +    float    tex_width;
> +    float    tex_height;
> +} gl_region_t;
> +
> +struct vlc_gl_sub_renderer
> +{
> +    vlc_gl_t *gl;
> +    const opengl_vtable_t *vt;
> +
> +    struct vlc_gl_interop *interop;
> +
> +    bool supports_npot;
> +    gl_region_t *regions;
> +    unsigned region_count;
> +
> +    GLuint program_id;
> +    struct {
> +        GLint vertex_pos;
> +        GLint tex_coords_in;
> +    } aloc;
> +    struct {
> +        GLint sampler;
> +    } uloc;
> +
> +    GLuint *buffer_objects;
> +    unsigned buffer_object_count;
> +};
> +
> +static void
> +LogShaderErrors(vlc_object_t *obj, const opengl_vtable_t *vt, GLuint id)
> +{
> +    GLint info_len;
> +    vt->GetShaderiv(id, GL_INFO_LOG_LENGTH, &info_len);
> +    if (info_len > 0)
> +    {
> +        char *info_log = malloc(info_len);
> +        if (info_log)
> +        {
> +            GLsizei written;
> +            vt->GetShaderInfoLog(id, info_len, &written, info_log);
> +            msg_Err(obj, "shader: %s", info_log);
> +            free(info_log);
> +        }
> +    }
> +}
> +
> +static void
> +LogProgramErrors(vlc_object_t *obj, const opengl_vtable_t *vt, GLuint id)
> +{
> +    GLint info_len;
> +    vt->GetProgramiv(id, GL_INFO_LOG_LENGTH, &info_len);
> +    if (info_len > 0)
> +    {
> +        char *info_log = malloc(info_len);
> +        if (info_log)
> +        {
> +            GLsizei written;
> +            vt->GetProgramInfoLog(id, info_len, &written, info_log);
> +            msg_Err(obj, "program: %s", info_log);
> +            free(info_log);
> +        }
> +    }
> +}
> +
> +static GLuint
> +CreateShader(vlc_object_t *obj, const opengl_vtable_t *vt, GLenum type,
> +             const char *src)
> +{
> +    GLuint shader = vt->CreateShader(type);
> +    if (!shader)
> +        return 0;
> +
> +    vt->ShaderSource(shader, 1, &src, NULL);
> +    vt->CompileShader(shader);
> +
> +    LogShaderErrors(obj, vt, shader);
> +
> +    GLint compiled;
> +    vt->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
> +    if (!compiled)
> +    {
> +        msg_Err(obj, "Failed to compile shader");
> +        vt->DeleteShader(shader);
> +        return 0;
> +    }
> +
> +    return shader;
> +}
> +
> +static GLuint
> +CreateProgram(vlc_object_t *obj, const opengl_vtable_t *vt)
> +{
> +    static const char *const VERTEX_SHADER_SRC =
> +        "#version 100\n"
> +        "attribute vec2 vertex_pos;\n"
> +        "attribute vec2 tex_coords_in;\n"
> +        "varying vec2 tex_coords;\n"
> +        "void main() {\n"
> +        "  tex_coords = tex_coords_in;\n"
> +        "  gl_Position = vec4(vertex_pos, 0.0, 1.0);\n"
> +        "}\n";
> +
> +    static const char *const FRAGMENT_SHADER_SRC =
> +        "#version 100\n"
> +        "precision mediump float;\n"
> +        "uniform sampler2D sampler;\n"
> +        "varying vec2 tex_coords;\n"
> +        "void main(void) {\n"
> +        "  gl_FragColor = texture2D(sampler, tex_coords);\n"
> +        "}\n";
> +
> +    GLuint program = 0;
> +
> +    GLuint vertex_shader = CreateShader(obj, vt, GL_VERTEX_SHADER,
> +                                        VERTEX_SHADER_SRC);
> +    if (!vertex_shader)
> +        return 0;
> +
> +    GLuint fragment_shader = CreateShader(obj, vt, GL_FRAGMENT_SHADER,
> +                                          FRAGMENT_SHADER_SRC);
> +    if (!fragment_shader)
> +        goto finally_1;
> +
> +    program = vt->CreateProgram();
> +    if (!program)
> +        goto finally_2;
> +
> +    vt->AttachShader(program, vertex_shader);
> +    vt->AttachShader(program, fragment_shader);
> +
> +    vt->LinkProgram(program);
> +
> +    LogProgramErrors(obj, vt, program);
> +
> +    GLint linked;
> +    vt->GetProgramiv(program, GL_LINK_STATUS, &linked);
> +    if (!linked)
> +    {
> +        msg_Err(obj, "Failed to link program");
> +        vt->DeleteProgram(program);
> +        program = 0;
> +    }
> +
> +finally_2:
> +    vt->DeleteShader(fragment_shader);
> +finally_1:
> +    vt->DeleteShader(vertex_shader);
> +
> +    return program;
> +}
> +
> +static int
> +FetchLocations(struct vlc_gl_sub_renderer *sr)
> +{
> +    assert(sr->program_id);
> +
> +    const opengl_vtable_t *vt = sr->vt;
> +
> +#define GET_LOC(type, x, str) do { \
> +    x = vt->Get##type##Location(sr->program_id, str); \
> +    assert(x != -1); \
> +    if (x == -1) { \
> +        msg_Err(sr->gl, "Unable to Get"#type"Location(%s)", str); \
> +        return VLC_EGENERIC; \
> +    } \
> +} while (0)
> +#define GET_ULOC(x, str) GET_LOC(Uniform, x, str)
> +#define GET_ALOC(x, str) GET_LOC(Attrib, x, str)
> +    GET_ULOC(sr->uloc.sampler, "sampler");
> +    GET_ALOC(sr->aloc.vertex_pos, "vertex_pos");
> +    GET_ALOC(sr->aloc.tex_coords_in, "tex_coords_in");
> +
> +#undef GET_LOC
> +#undef GET_ULOC
> +#undef GET_ALOC
> +
> +    return VLC_SUCCESS;
> +}
> +
> +struct vlc_gl_sub_renderer *
> +vlc_gl_sub_renderer_New(vlc_gl_t *gl, const opengl_vtable_t *vt,
> +                        bool supports_npot)
> +{
> +    struct vlc_gl_sub_renderer *sr = malloc(sizeof(*sr));
> +    if (!sr)
> +        return NULL;
> +
> +    video_format_t fmt;
> +    video_format_Init(&fmt, VLC_CODEC_RGB32);
> +    sr->interop = vlc_gl_interop_New(gl, vt, NULL, &fmt, true);
> +    if (!sr->interop)
> +        goto error_1;
> +
> +    /* Allocates our textures */
> +    assert(!sr->interop->handle_texs_gen);
> +
> +    sr->gl = gl;
> +    sr->vt = vt;
> +    sr->supports_npot = supports_npot;
> +    sr->region_count = 0;
> +    sr->regions = NULL;
> +
> +    sr->program_id = CreateProgram(VLC_OBJECT(sr->gl), vt);
> +    if (!sr->program_id)
> +        goto error_2;
> +
> +    int ret = FetchLocations(sr);
> +    if (ret != VLC_SUCCESS)
> +        goto error_3;
> +
> +    /* Initial number of allocated buffer objects for subpictures, will grow dynamically. */
> +    static const unsigned INITIAL_BUFFER_OBJECT_COUNT = 8;
> +    sr->buffer_objects = vlc_alloc(INITIAL_BUFFER_OBJECT_COUNT, sizeof(GLuint));
> +    if (!sr->buffer_objects)
> +        goto error_3;
> +
> +    sr->buffer_object_count = INITIAL_BUFFER_OBJECT_COUNT;
> +
> +    vt->GenBuffers(sr->buffer_object_count, sr->buffer_objects);
> +
> +    return sr;
> +
> +error_3:
> +    vt->DeleteProgram(sr->program_id);
> +error_2:
> +    vlc_object_delete(sr->interop);
> +error_1:
> +    free(sr);
> +
> +    return NULL;
> +}
> +
> +void
> +vlc_gl_sub_renderer_Delete(struct vlc_gl_sub_renderer *sr)
> +{
> +    if (sr->buffer_object_count)
> +        sr->vt->DeleteBuffers(sr->buffer_object_count, sr->buffer_objects);
> +    free(sr->buffer_objects);
> +
> +    for (unsigned i = 0; i < sr->region_count; ++i)
> +    {
> +        if (sr->regions[i].texture)
> +            sr->vt->DeleteTextures(1, &sr->regions[i].texture);
> +    }
> +    free(sr->regions);
> +
> +    vlc_gl_interop_Delete(sr->interop);
> +
> +    free(sr);
> +}
> +
> +int
> +vlc_gl_sub_renderer_Prepare(struct vlc_gl_sub_renderer *sr, subpicture_t *subpicture)
> +{
> +    const struct vlc_gl_interop *interop = sr->interop;
> +
> +    int last_count = sr->region_count;
> +    gl_region_t *last = sr->regions;
> +
> +    if (subpicture) {
> +        int count = 0;
> +        for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
> +            count++;
> +
> +        gl_region_t *regions = calloc(count, sizeof(*regions));
> +        if (!regions)
> +            return VLC_ENOMEM;
> +
> +        sr->region_count = count;
> +        sr->regions = regions;
> +
> +        int i = 0;
> +        for (subpicture_region_t *r = subpicture->p_region;
> +             r; r = r->p_next, i++) {
> +            gl_region_t *glr = &sr->regions[i];
> +
> +            glr->width  = r->fmt.i_visible_width;
> +            glr->height = r->fmt.i_visible_height;
> +            if (!sr->supports_npot) {
> +                glr->width  = vout_display_opengl_GetAlignedSize(glr->width);
> +                glr->height = vout_display_opengl_GetAlignedSize(glr->height);
> +                glr->tex_width  = (float) r->fmt.i_visible_width  / glr->width;
> +                glr->tex_height = (float) r->fmt.i_visible_height / glr->height;
> +            } else {
> +                glr->tex_width  = 1.0;
> +                glr->tex_height = 1.0;
> +            }
> +            glr->alpha  = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
> +            glr->left   =  2.0 * (r->i_x                          ) / subpicture->i_original_picture_width  - 1.0;
> +            glr->top    = -2.0 * (r->i_y                          ) / subpicture->i_original_picture_height + 1.0;
> +            glr->right  =  2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width  - 1.0;
> +            glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
> +
> +            glr->texture = 0;
> +            /* Try to recycle the textures allocated by the previous
> +               call to this function. */
> +            for (int j = 0; j < last_count; j++) {
> +                if (last[j].texture &&
> +                    last[j].width  == glr->width &&
> +                    last[j].height == glr->height) {
> +                    glr->texture = last[j].texture;
> +                    memset(&last[j], 0, sizeof(last[j]));
> +                    break;
> +                }
> +            }
> +
> +            const size_t pixels_offset =
> +                r->fmt.i_y_offset * r->p_picture->p->i_pitch +
> +                r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
> +            if (!glr->texture)
> +            {
> +                /* Could not recycle a previous texture, generate a new one. */
> +                int ret = vlc_gl_interop_GenTextures(interop, &glr->width,
> +                                                     &glr->height,
> +                                                     &glr->texture);
> +                if (ret != VLC_SUCCESS)
> +                    break;
> +            }
> +            /* 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;
> +            int ret = interop->ops->update_textures(interop, &glr->texture,
> +                                                    &glr->width, &glr->height,
> +                                                    r->p_picture, &pixels_offset);
> +            if (ret != VLC_SUCCESS)
> +                break;
> +        }
> +    }
> +    else
> +    {
> +        sr->region_count = 0;
> +        sr->regions = NULL;
> +    }
> +
> +    for (int i = 0; i < last_count; i++) {
> +        if (last[i].texture)
> +            vlc_gl_interop_DelTextures(interop, &last[i].texture);
> +    }
> +    free(last);
> +
> +    return VLC_SUCCESS;
> +}
> +
> +int
> +vlc_gl_sub_renderer_Draw(struct vlc_gl_sub_renderer *sr)
> +{
> +    const struct vlc_gl_interop *interop = sr->interop;
> +    const opengl_vtable_t *vt = sr->vt;
> +
> +    assert(sr->program_id);
> +    vt->UseProgram(sr->program_id);
> +
> +    vt->Enable(GL_BLEND);
> +    vt->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> +
> +    /* We need two buffer objects for each region: for vertex and texture coordinates. */
> +    if (2 * sr->region_count > sr->buffer_object_count) {
> +        if (sr->buffer_object_count > 0)
> +            vt->DeleteBuffers(sr->buffer_object_count, sr->buffer_objects);
> +        sr->buffer_object_count = 0;
> +
> +        int new_count = 2 * sr->region_count;
> +        sr->buffer_objects = realloc_or_free(sr->buffer_objects, new_count * sizeof(GLuint));
> +        if (!sr->buffer_objects)
> +            return VLC_ENOMEM;
> +
> +        sr->buffer_object_count = new_count;
> +        vt->GenBuffers(sr->buffer_object_count, sr->buffer_objects);
> +    }
> +
> +    vt->ActiveTexture(GL_TEXTURE0 + 0);
> +    for (unsigned i = 0; i < sr->region_count; i++) {
> +        gl_region_t *glr = &sr->regions[i];
> +        const GLfloat vertexCoord[] = {
> +            glr->left,  glr->top,
> +            glr->left,  glr->bottom,
> +            glr->right, glr->top,
> +            glr->right, glr->bottom,
> +        };
> +        const GLfloat textureCoord[] = {
> +            0.0, 0.0,
> +            0.0, glr->tex_height,
> +            glr->tex_width, 0.0,
> +            glr->tex_width, glr->tex_height,
> +        };
> +
> +        assert(glr->texture != 0);
> +        vt->BindTexture(interop->tex_target, glr->texture);
> +
> +        vt->BindBuffer(GL_ARRAY_BUFFER, sr->buffer_objects[2 * i]);
> +        vt->BufferData(GL_ARRAY_BUFFER, sizeof(textureCoord), textureCoord, GL_STATIC_DRAW);
> +        vt->EnableVertexAttribArray(sr->aloc.tex_coords_in);
> +        vt->VertexAttribPointer(sr->aloc.tex_coords_in, 2, GL_FLOAT, 0, 0, 0);
> +
> +        vt->BindBuffer(GL_ARRAY_BUFFER, sr->buffer_objects[2 * i + 1]);
> +        vt->BufferData(GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW);
> +        vt->EnableVertexAttribArray(sr->aloc.vertex_pos);
> +        vt->VertexAttribPointer(sr->aloc.vertex_pos, 2, GL_FLOAT, 0, 0, 0);
> +
> +        vt->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
> +    }
> +    vt->Disable(GL_BLEND);
> +
> +    return VLC_SUCCESS;
> +}
> diff --git a/modules/video_output/opengl/sub_renderer.h b/modules/video_output/opengl/sub_renderer.h
> new file mode 100644
> index 0000000000..48c0ebea59
> --- /dev/null
> +++ b/modules/video_output/opengl/sub_renderer.h
> @@ -0,0 +1,79 @@
> +/*****************************************************************************
> + * sub_renderer.h
> + *****************************************************************************
> + * Copyright (C) 2020 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_SUB_RENDERER_H
> +#define VLC_SUB_RENDERER_H
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_opengl.h>
> +
> +#include "gl_common.h"
> +
> +/**
> + * A subpictures renderer handles the rendering of RGB subpictures.
> + */
> +struct vlc_gl_sub_renderer;
> +
> +/**
> + * Create a new subpictures renderer
> + *
> + * \param gl the GL context
> + * \param vt the OpenGL functions vtable
> + * \param supports_npot indicate if the implementation supports non-power-of-2
> + *                      texture size
> + */
> +struct vlc_gl_sub_renderer *
> +vlc_gl_sub_renderer_New(vlc_gl_t *gl, const opengl_vtable_t *vt,
> +                        bool supports_npot);
> +
> +/**
> + * Delete a subpictures renderer
> + *
> + * \param sr the renderer
> + */
> +void
> +vlc_gl_sub_renderer_Delete(struct vlc_gl_sub_renderer *sr);
> +
> +/**
> + * Prepare the fragment shader
> + *
> + * Concretely, it allocates OpenGL textures if necessary and uploads the
> + * picture.
> + *
> + * \param sr the renderer
> + * \param subpicture the subpicture to render
> + */
> +int
> +vlc_gl_sub_renderer_Prepare(struct vlc_gl_sub_renderer *sr,
> +                            subpicture_t *subpicture);
> +
> +/**
> + * Draw the prepared subpicture
> + *
> + * \param sr the renderer
> + */
> +int
> +vlc_gl_sub_renderer_Draw(struct vlc_gl_sub_renderer *sr);
> +
> +#endif
> diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
> index f2846e5a4e..2196de52fd 100644
> --- a/modules/video_output/opengl/vout_helper.c
> +++ b/modules/video_output/opengl/vout_helper.c
> @@ -41,6 +41,7 @@
>
>  #include "vout_helper.h"
>  #include "internal.h"
> +#include "sub_renderer.h"
>
>  #define SPHERE_RADIUS 1.f
>
> @@ -71,22 +72,6 @@
>  # define GL_ASSERT_NOERROR()
>  #endif
>
> -typedef struct {
> -    GLuint   texture;
> -    GLsizei  width;
> -    GLsizei  height;
> -
> -    float    alpha;
> -
> -    float    top;
> -    float    left;
> -    float    bottom;
> -    float    right;
> -
> -    float    tex_width;
> -    float    tex_height;
> -} gl_region_t;
> -
>  struct prgm
>  {
>      GLuint id;
> @@ -124,22 +109,13 @@ struct vout_display_opengl_t {
>
>      GLuint     texture[PICTURE_PLANE_MAX];
>
> -    int         region_count;
> -    gl_region_t *region;
> -
> -    /* One YUV program and one RGBA program (for subpics) */
> -    struct prgm prgms[2];
> -    struct prgm *prgm; /* Main program */
> -    struct prgm *sub_prgm; /* Subpicture program */
> +    struct prgm prgm;
>
>      unsigned nb_indices;
>      GLuint vertex_buffer_object;
>      GLuint index_buffer_object;
>      GLuint texture_buffer_object[PICTURE_PLANE_MAX];
>
> -    GLuint *subpicture_buffer_object;
> -    int    subpicture_buffer_object_count;
> -
>      struct {
>          unsigned int i_x_offset;
>          unsigned int i_y_offset;
> @@ -159,6 +135,8 @@ struct vout_display_opengl_t {
>      float f_fovy; /* to avoid recalculating them when needed.      */
>      float f_z;    /* Position of the camera on the shpere radius vector */
>      float f_sar;
> +
> +    struct vlc_gl_sub_renderer *sub_renderer;
>  };
>
>  static const vlc_fourcc_t gl_subpicture_chromas[] = {
> @@ -720,35 +698,30 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
>
>      bool b_dump_shaders = var_InheritInteger(gl, "verbose") >= 4;
>
> -    vgl->prgm = &vgl->prgms[0];
> -    vgl->sub_prgm = &vgl->prgms[1];
> -
> -    GL_ASSERT_NOERROR();
> -    int ret;
> -    ret = opengl_init_program(vgl, context, vgl->prgm, fmt, false,
> -                              b_dump_shaders);
> -    if (ret != VLC_SUCCESS)
> +    vgl->sub_renderer =
> +        vlc_gl_sub_renderer_New(vgl->gl, &vgl->vt, vgl->supports_npot);
> +    if (!vgl->sub_renderer)
>      {
> -        msg_Warn(gl, "could not init tex converter for %4.4s",
> -                 (const char *) &fmt->i_chroma);
> +        msg_Err(gl, "Could not create sub renderer");
>          free(vgl);
>          return NULL;
>      }
>
>      GL_ASSERT_NOERROR();
> -    ret = opengl_init_program(vgl, context, vgl->sub_prgm, fmt, true,
> -                              b_dump_shaders);
> +    int ret = opengl_init_program(vgl, context, &vgl->prgm, fmt, false,
> +                                  b_dump_shaders);
>      if (ret != VLC_SUCCESS)
>      {
> -        msg_Warn(gl, "could not init subpictures tex converter for %4.4s",
> +        msg_Warn(gl, "could not init tex converter for %4.4s",
>                   (const char *) &fmt->i_chroma);
> -        opengl_deinit_program(vgl, vgl->prgm);
> +        vlc_gl_sub_renderer_Delete(vgl->sub_renderer);
>          free(vgl);
>          return NULL;
>      }
> +
>      GL_ASSERT_NOERROR();
>
> -    const struct vlc_gl_interop *interop = vgl->prgm->tc->interop;
> +    const struct vlc_gl_interop *interop = vgl->prgm.tc->interop;
>      /* Update the fmt to main program one */
>      vgl->fmt = interop->fmt;
>      /* The orientation is handled by the orientation matrix */
> @@ -769,13 +742,11 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
>          }
>      }
>
> -    /* Allocates our textures */
> -    assert(!vgl->sub_prgm->tc->interop->handle_texs_gen);
> -
>      if (!interop->handle_texs_gen)
>      {
> -        ret = vlc_gl_interop_GenTextures(vgl->prgm->tc->interop, vgl->tex_width,
> -                                         vgl->tex_height, vgl->texture);
> +        ret = vlc_gl_interop_GenTextures(vgl->prgm.tc->interop,
> +                                         vgl->tex_width, vgl->tex_height,
> +                                         vgl->texture);
>          if (ret != VLC_SUCCESS)
>          {
>              vout_display_opengl_Delete(vgl);
> @@ -795,20 +766,6 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
>      vgl->vt.GenBuffers(1, &vgl->index_buffer_object);
>      vgl->vt.GenBuffers(interop->tex_count, vgl->texture_buffer_object);
>
> -    /* Initial number of allocated buffer objects for subpictures, will grow dynamically. */
> -    int subpicture_buffer_object_count = 8;
> -    vgl->subpicture_buffer_object = vlc_alloc(subpicture_buffer_object_count, sizeof(GLuint));
> -    if (!vgl->subpicture_buffer_object) {
> -        vout_display_opengl_Delete(vgl);
> -        return NULL;
> -    }
> -    vgl->subpicture_buffer_object_count = subpicture_buffer_object_count;
> -    vgl->vt.GenBuffers(vgl->subpicture_buffer_object_count, vgl->subpicture_buffer_object);
> -
> -    /* */
> -    vgl->region_count = 0;
> -    vgl->region = NULL;
> -
>      if (vgl->fmt.projection_mode != PROJECTION_MODE_RECTANGULAR
>       && vout_display_opengl_SetViewpoint(vgl, viewpoint) != VLC_SUCCESS)
>      {
> @@ -833,31 +790,21 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
>      vgl->vt.Finish();
>      vgl->vt.Flush();
>
> -    const struct vlc_gl_interop *interop = vgl->prgm->tc->interop;
> +    const struct vlc_gl_interop *interop = vgl->prgm.tc->interop;
>      const size_t main_tex_count = interop->tex_count;
>      const bool main_del_texs = !interop->handle_texs_gen;
>
> -    opengl_deinit_program(vgl, vgl->prgm);
> -    opengl_deinit_program(vgl, vgl->sub_prgm);
> +    vlc_gl_sub_renderer_Delete(vgl->sub_renderer);
> +
> +    opengl_deinit_program(vgl, &vgl->prgm);
>
>      vgl->vt.DeleteBuffers(1, &vgl->vertex_buffer_object);
>      vgl->vt.DeleteBuffers(1, &vgl->index_buffer_object);
>      vgl->vt.DeleteBuffers(main_tex_count, vgl->texture_buffer_object);
>
> -    if (vgl->subpicture_buffer_object_count > 0)
> -        vgl->vt.DeleteBuffers(vgl->subpicture_buffer_object_count,
> -                              vgl->subpicture_buffer_object);
> -    free(vgl->subpicture_buffer_object);
> -
>      if (main_del_texs)
>          vgl->vt.DeleteTextures(main_tex_count, vgl->texture);
>
> -    for (int i = 0; i < vgl->region_count; i++)
> -    {
> -        if (vgl->region[i].texture)
> -            vgl->vt.DeleteTextures(1, &vgl->region[i].texture);
> -    }
> -    free(vgl->region);
>      GL_ASSERT_NOERROR();
>
>      free(vgl);
> @@ -912,7 +859,7 @@ int vout_display_opengl_SetViewpoint(vout_display_opengl_t *vgl,
>          UpdateFOVy(vgl);
>          UpdateZ(vgl);
>      }
> -    getViewpointMatrixes(vgl, vgl->fmt.projection_mode, vgl->prgm);
> +    getViewpointMatrixes(vgl, vgl->fmt.projection_mode, &vgl->prgm);
>
>      return VLC_SUCCESS;
>  }
> @@ -927,7 +874,7 @@ void vout_display_opengl_SetWindowAspectRatio(vout_display_opengl_t *vgl,
>      vgl->f_sar = f_sar;
>      UpdateFOVy(vgl);
>      UpdateZ(vgl);
> -    getViewpointMatrixes(vgl, vgl->fmt.projection_mode, vgl->prgm);
> +    getViewpointMatrixes(vgl, vgl->fmt.projection_mode, &vgl->prgm);
>  }
>
>  void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
> @@ -936,102 +883,12 @@ void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
>      vgl->vt.Viewport(x, y, width, height);
>  }
>
> -static int
> -vout_display_opengl_PrepareSubPicture(vout_display_opengl_t *vgl,
> -                                      subpicture_t *subpicture)
> -{
> -    opengl_tex_converter_t *tc = vgl->sub_prgm->tc;
> -    const struct vlc_gl_interop *interop = tc->interop;
> -
> -    int last_count = vgl->region_count;
> -    gl_region_t *last = vgl->region;
> -
> -    if (subpicture) {
> -        int count = 0;
> -        for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
> -            count++;
> -
> -        vgl->region_count = count;
> -        vgl->region       = calloc(count, sizeof(*vgl->region));
> -
> -        int i = 0;
> -        for (subpicture_region_t *r = subpicture->p_region;
> -             r; r = r->p_next, i++) {
> -            gl_region_t *glr = &vgl->region[i];
> -
> -            glr->width  = r->fmt.i_visible_width;
> -            glr->height = r->fmt.i_visible_height;
> -            if (!vgl->supports_npot) {
> -                glr->width  = vout_display_opengl_GetAlignedSize(glr->width);
> -                glr->height = vout_display_opengl_GetAlignedSize(glr->height);
> -                glr->tex_width  = (float) r->fmt.i_visible_width  / glr->width;
> -                glr->tex_height = (float) r->fmt.i_visible_height / glr->height;
> -            } else {
> -                glr->tex_width  = 1.0;
> -                glr->tex_height = 1.0;
> -            }
> -            glr->alpha  = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
> -            glr->left   =  2.0 * (r->i_x                          ) / subpicture->i_original_picture_width  - 1.0;
> -            glr->top    = -2.0 * (r->i_y                          ) / subpicture->i_original_picture_height + 1.0;
> -            glr->right  =  2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width  - 1.0;
> -            glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
> -
> -            glr->texture = 0;
> -            /* Try to recycle the textures allocated by the previous
> -               call to this function. */
> -            for (int j = 0; j < last_count; j++) {
> -                if (last[j].texture &&
> -                    last[j].width  == glr->width &&
> -                    last[j].height == glr->height) {
> -                    glr->texture = last[j].texture;
> -                    memset(&last[j], 0, sizeof(last[j]));
> -                    break;
> -                }
> -            }
> -
> -            const size_t pixels_offset =
> -                r->fmt.i_y_offset * r->p_picture->p->i_pitch +
> -                r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
> -            if (!glr->texture)
> -            {
> -                /* Could not recycle a previous texture, generate a new one. */
> -                int ret = vlc_gl_interop_GenTextures(interop, &glr->width,
> -                                                     &glr->height,
> -                                                     &glr->texture);
> -                if (ret != VLC_SUCCESS)
> -                    break;
> -            }
> -            /* 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;
> -            int ret = interop->ops->update_textures(interop, &glr->texture,
> -                                                    &glr->width, &glr->height,
> -                                                    r->p_picture, &pixels_offset);
> -            if (ret != VLC_SUCCESS)
> -                break;
> -        }
> -    }
> -    else
> -    {
> -        vgl->region_count = 0;
> -        vgl->region = NULL;
> -    }
> -
> -    for (int i = 0; i < last_count; i++) {
> -        if (last[i].texture)
> -            vlc_gl_interop_DelTextures(interop, &last[i].texture);
> -    }
> -    free(last);
> -
> -    return VLC_SUCCESS;
> -}
> -
>  int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
>                                  picture_t *picture, subpicture_t *subpicture)
>  {
>      GL_ASSERT_NOERROR();
>
> -    opengl_tex_converter_t *tc = vgl->prgm->tc;
> +    opengl_tex_converter_t *tc = vgl->prgm.tc;
>      const struct vlc_gl_interop *interop = tc->interop;
>
>      /* Update the texture */
> @@ -1040,7 +897,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
>      if (ret != VLC_SUCCESS)
>          return ret;
>
> -    ret = vout_display_opengl_PrepareSubPicture(vgl, subpicture);
> +    ret = vlc_gl_sub_renderer_Prepare(vgl->sub_renderer, subpicture);
>      GL_ASSERT_NOERROR();
>      return ret;
>  }
> @@ -1317,7 +1174,7 @@ static int SetupCoords(vout_display_opengl_t *vgl,
>                         const float *left, const float *top,
>                         const float *right, const float *bottom)
>  {
> -    const struct vlc_gl_interop *interop = vgl->prgm->tc->interop;
> +    const struct vlc_gl_interop *interop = vgl->prgm.tc->interop;
>
>      GLfloat *vertexCoord, *textureCoord;
>      GLushort *indices;
> @@ -1445,7 +1302,7 @@ static void TextureCropForStereo(vout_display_opengl_t *vgl,
>                                   float *left, float *top,
>                                   float *right, float *bottom)
>  {
> -    const struct vlc_gl_interop *interop = vgl->prgm->tc->interop;
> +    const struct vlc_gl_interop *interop = vgl->prgm.tc->interop;
>
>      float stereoCoefs[2];
>      float stereoOffsets[2];
> @@ -1473,87 +1330,6 @@ static void TextureCropForStereo(vout_display_opengl_t *vgl,
>      }
>  }
>
> -static int
> -vout_display_opengl_DrawSubPicture(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_interop *interop = tc->interop;
> -    vgl->vt.UseProgram(program);
> -
> -    vgl->vt.Enable(GL_BLEND);
> -    vgl->vt.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> -
> -    /* We need two buffer objects for each region: for vertex and texture coordinates. */
> -    if (2 * vgl->region_count > vgl->subpicture_buffer_object_count) {
> -        if (vgl->subpicture_buffer_object_count > 0)
> -            vgl->vt.DeleteBuffers(vgl->subpicture_buffer_object_count,
> -                                  vgl->subpicture_buffer_object);
> -        vgl->subpicture_buffer_object_count = 0;
> -
> -        int new_count = 2 * vgl->region_count;
> -        vgl->subpicture_buffer_object = realloc_or_free(vgl->subpicture_buffer_object, new_count * sizeof(GLuint));
> -        if (!vgl->subpicture_buffer_object)
> -            return VLC_ENOMEM;
> -
> -        vgl->subpicture_buffer_object_count = new_count;
> -        vgl->vt.GenBuffers(vgl->subpicture_buffer_object_count,
> -                           vgl->subpicture_buffer_object);
> -    }
> -
> -    vgl->vt.ActiveTexture(GL_TEXTURE0 + 0);
> -    for (int i = 0; i < vgl->region_count; i++) {
> -        gl_region_t *glr = &vgl->region[i];
> -        const GLfloat vertexCoord[] = {
> -            glr->left,  glr->top,
> -            glr->left,  glr->bottom,
> -            glr->right, glr->top,
> -            glr->right, glr->bottom,
> -        };
> -        const GLfloat textureCoord[] = {
> -            0.0, 0.0,
> -            0.0, glr->tex_height,
> -            glr->tex_width, 0.0,
> -            glr->tex_width, glr->tex_height,
> -        };
> -
> -        assert(glr->texture != 0);
> -        vgl->vt.BindTexture(interop->tex_target, glr->texture);
> -
> -        tc->pf_prepare_shader(tc, &glr->width, &glr->height, glr->alpha);
> -
> -        vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->subpicture_buffer_object[2 * i]);
> -        vgl->vt.BufferData(GL_ARRAY_BUFFER, sizeof(textureCoord), textureCoord, GL_STATIC_DRAW);
> -        vgl->vt.EnableVertexAttribArray(prgm->aloc.MultiTexCoord[0]);
> -        vgl->vt.VertexAttribPointer(prgm->aloc.MultiTexCoord[0], 2, GL_FLOAT,
> -                                    0, 0, 0);
> -
> -        vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->subpicture_buffer_object[2 * i + 1]);
> -        vgl->vt.BufferData(GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW);
> -        vgl->vt.EnableVertexAttribArray(prgm->aloc.VertexPosition);
> -        vgl->vt.VertexAttribPointer(prgm->aloc.VertexPosition, 2, GL_FLOAT,
> -                                    0, 0, 0);
> -
> -        vgl->vt.UniformMatrix4fv(prgm->uloc.TransformMatrix, 1, GL_FALSE,
> -                                 identity);
> -
> -        vgl->vt.UniformMatrix4fv(prgm->uloc.OrientationMatrix, 1, GL_FALSE,
> -                                 prgm->var.OrientationMatrix);
> -        vgl->vt.UniformMatrix4fv(prgm->uloc.ProjectionMatrix, 1, GL_FALSE,
> -                                 prgm->var.ProjectionMatrix);
> -        vgl->vt.UniformMatrix4fv(prgm->uloc.ViewMatrix, 1, GL_FALSE,
> -                                 prgm->var.ViewMatrix);
> -        vgl->vt.UniformMatrix4fv(prgm->uloc.ZoomMatrix, 1, GL_FALSE,
> -                                 prgm->var.ZoomMatrix);
> -
> -        vgl->vt.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
> -    }
> -    vgl->vt.Disable(GL_BLEND);
> -
> -    return VLC_SUCCESS;
> -}
> -
>  int vout_display_opengl_Display(vout_display_opengl_t *vgl,
>                                  const video_format_t *source)
>  {
> @@ -1564,7 +1340,7 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
>         Currently, the OS X provider uses it to get a smooth window resizing */
>      vgl->vt.Clear(GL_COLOR_BUFFER_BIT);
>
> -    vgl->vt.UseProgram(vgl->prgm->id);
> +    vgl->vt.UseProgram(vgl->prgm.id);
>
>      if (source->i_x_offset != vgl->last_source.i_x_offset
>       || source->i_y_offset != vgl->last_source.i_y_offset
> @@ -1575,7 +1351,7 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
>          float top[PICTURE_PLANE_MAX];
>          float right[PICTURE_PLANE_MAX];
>          float bottom[PICTURE_PLANE_MAX];
> -        const opengl_tex_converter_t *tc = vgl->prgm->tc;
> +        const opengl_tex_converter_t *tc = vgl->prgm.tc;
>          const struct vlc_gl_interop *interop = tc->interop;
>          for (unsigned j = 0; j < interop->tex_count; j++)
>          {
> @@ -1611,9 +1387,9 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
>          vgl->last_source.i_visible_width = source->i_visible_width;
>          vgl->last_source.i_visible_height = source->i_visible_height;
>      }
> -    DrawWithShaders(vgl, vgl->prgm);
> +    DrawWithShaders(vgl, &vgl->prgm);
>
> -    int ret = vout_display_opengl_DrawSubPicture(vgl);
> +    int ret = vlc_gl_sub_renderer_Draw(vgl->sub_renderer);
>      if (ret != VLC_SUCCESS)
>          return ret;
>
> --
> 2.25.0
>
> _______________________________________________
> 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