[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