[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