[vlc-devel] [PATCH 12/24] opengl: implement subpictures renderer
Romain Vimont
rom1v at videolabs.io
Mon Jan 27 21:20:02 CET 2020
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
More information about the vlc-devel
mailing list