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

Romain Vimont rom1v at videolabs.io
Wed Jan 29 12:11:39 CET 2020



On 1/28/20 4:53 PM, Alexandre Janniaux wrote:
> Hi,
> 
> I haven't checked everything yet, but as it is code extraction
> maybe previous copyrights notice must be copied with them?

Good point. I copied the copyrights and authors section from vout_helper 
to renderer.c and sub_renderer.c. Thank you.

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