[vlc-devel] [PATCH 01/41] opengl: factorize program creation
Romain Vimont
rom1v at videolabs.io
Fri Feb 7 17:41:47 CET 2020
Expose a single function to create an OpenGL program for a vertex shader
and a fragment shader.
This simplify the code, and handles the errors in the same way
everywhere.
---
modules/video_output/Makefile.am | 1 +
.../video_output/opengl/fragment_shaders.c | 35 ++--
modules/video_output/opengl/gl_util.c | 132 +++++++++++++++
modules/video_output/opengl/gl_util.h | 22 +++
modules/video_output/opengl/internal.h | 2 +-
modules/video_output/opengl/renderer.c | 83 +++-------
modules/video_output/opengl/sub_renderer.c | 153 +++---------------
7 files changed, 211 insertions(+), 217 deletions(-)
create mode 100644 modules/video_output/opengl/gl_util.c
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 566e7b5fd8..c509483f65 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -5,6 +5,7 @@ EXTRA_DIST += video_output/README
OPENGL_COMMONSOURCES = video_output/opengl/vout_helper.c \
video_output/opengl/gl_common.h \
+ video_output/opengl/gl_util.c \
video_output/opengl/gl_util.h \
video_output/opengl/interop.h \
video_output/opengl/vout_helper.h \
diff --git a/modules/video_output/opengl/fragment_shaders.c b/modules/video_output/opengl/fragment_shaders.c
index fc3391c32f..dfc4f51d1e 100644
--- a/modules/video_output/opengl/fragment_shaders.c
+++ b/modules/video_output/opengl/fragment_shaders.c
@@ -323,10 +323,9 @@ renderer_xyz12_prepare_shader(const struct vlc_gl_renderer *renderer,
vt->Uniform1i(renderer->uloc.Texture[0], 0);
}
-static GLuint
+static char *
xyz12_shader_init(struct vlc_gl_renderer *renderer)
{
- const opengl_vtable_t *vt = renderer->vt;
renderer->pf_fetch_locations = renderer_xyz12_fetch_locations;
renderer->pf_prepare_shader = renderer_xyz12_prepare_shader;
@@ -365,13 +364,9 @@ xyz12_shader_init(struct vlc_gl_renderer *renderer)
char *code;
if (asprintf(&code, template, renderer->glsl_version,
renderer->glsl_precision_header) < 0)
- return 0;
+ return NULL;
- GLuint fragment_shader = vt->CreateShader(GL_FRAGMENT_SHADER);
- vt->ShaderSource(fragment_shader, 1, (const char **) &code, NULL);
- vt->CompileShader(fragment_shader);
- free(code);
- return fragment_shader;
+ return code;
}
static int
@@ -433,7 +428,7 @@ opengl_init_swizzle(const struct vlc_gl_interop *interop,
return VLC_SUCCESS;
}
-GLuint
+char *
opengl_fragment_shader_init(struct vlc_gl_renderer *renderer, GLenum tex_target,
vlc_fourcc_t chroma, video_color_space_t yuv_space)
{
@@ -446,7 +441,7 @@ opengl_fragment_shader_init(struct vlc_gl_renderer *renderer, GLenum tex_target,
const vlc_chroma_description_t *desc = vlc_fourcc_GetChromaDescription(chroma);
if (desc == NULL)
- return 0;
+ return NULL;
if (chroma == VLC_CODEC_XYZ12)
return xyz12_shader_init(renderer);
@@ -455,10 +450,10 @@ opengl_fragment_shader_init(struct vlc_gl_renderer *renderer, GLenum tex_target,
{
ret = renderer_yuv_base_init(renderer, chroma, desc, yuv_space);
if (ret != VLC_SUCCESS)
- return 0;
+ return NULL;
ret = opengl_init_swizzle(renderer->interop, swizzle_per_tex, chroma, desc);
if (ret != VLC_SUCCESS)
- return 0;
+ return NULL;
}
const char *sampler, *lookup, *coord_name;
@@ -485,7 +480,7 @@ opengl_fragment_shader_init(struct vlc_gl_renderer *renderer, GLenum tex_target,
struct vlc_memstream ms;
if (vlc_memstream_open(&ms) != 0)
- return 0;
+ return NULL;
#define ADD(x) vlc_memstream_puts(&ms, x)
#define ADDF(x, ...) vlc_memstream_printf(&ms, x, ##__VA_ARGS__)
@@ -644,24 +639,14 @@ opengl_fragment_shader_init(struct vlc_gl_renderer *renderer, GLenum tex_target,
#undef ADDF
if (vlc_memstream_close(&ms) != 0)
- return 0;
+ return NULL;
- GLuint fragment_shader = vt->CreateShader(GL_FRAGMENT_SHADER);
- if (fragment_shader == 0)
- {
- free(ms.ptr);
- return 0;
- }
- GLint length = ms.length;
- vt->ShaderSource(fragment_shader, 1, (const char **)&ms.ptr, &length);
- vt->CompileShader(fragment_shader);
if (renderer->b_dump_shaders)
msg_Dbg(renderer->gl, "\n=== Fragment shader for fourcc: %4.4s, colorspace: %d ===\n%s\n",
(const char *)&chroma, yuv_space, ms.ptr);
- free(ms.ptr);
renderer->pf_fetch_locations = renderer_base_fetch_locations;
renderer->pf_prepare_shader = renderer_base_prepare_shader;
- return fragment_shader;
+ return ms.ptr;
}
diff --git a/modules/video_output/opengl/gl_util.c b/modules/video_output/opengl/gl_util.c
new file mode 100644
index 0000000000..fd3ced5283
--- /dev/null
+++ b/modules/video_output/opengl/gl_util.c
@@ -0,0 +1,132 @@
+/*****************************************************************************
+ * gl_util.c
+ *****************************************************************************
+ * Copyright (C) 2020 VLC authors and VideoLAN
+ *
+ * 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 "gl_util.h"
+
+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,
+ GLsizei count, const GLchar **src)
+{
+ GLuint shader = vt->CreateShader(type);
+ if (!shader)
+ return 0;
+
+ vt->ShaderSource(shader, count, 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;
+}
+
+
+GLuint
+vlc_gl_BuildProgram(vlc_object_t *obj, const opengl_vtable_t *vt,
+ GLsizei vstring_count, const GLchar **vstrings,
+ GLsizei fstring_count, const GLchar **fstrings)
+{
+ GLuint program = 0;
+
+ GLuint vertex_shader = CreateShader(obj, vt, GL_VERTEX_SHADER,
+ vstring_count, vstrings);
+ if (!vertex_shader)
+ return 0;
+
+ GLuint fragment_shader = CreateShader(obj, vt, GL_FRAGMENT_SHADER,
+ fstring_count, fstrings);
+ 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;
+}
diff --git a/modules/video_output/opengl/gl_util.h b/modules/video_output/opengl/gl_util.h
index 21734aae21..f368d93c31 100644
--- a/modules/video_output/opengl/gl_util.h
+++ b/modules/video_output/opengl/gl_util.h
@@ -25,6 +25,7 @@
# include "config.h"
#endif
+#include "gl_common.h"
#include <vlc_common.h>
/** Return the smallest larger or equal power of 2 */
@@ -34,4 +35,25 @@ static inline unsigned vlc_align_pot(unsigned x)
return ((align >> 1) == x) ? x : align;
}
+/**
+ * Build an OpenGL program
+ *
+ * Both the fragment shader and fragment shader are passed as a list of
+ * strings, forming the shader source code once concatenated, like
+ * glShaderSource().
+ *
+ * \param obj a VLC object, used to log messages
+ * \param vt the OpenGL virtual table
+ * \param vstring_count the number of strings in vstrings
+ * \param vstrings a list of NUL-terminated strings containing the vertex
+ * shader source code
+ * \param fstring_count the number of strings in fstrings
+ * \param fstrings a list of NUL-terminated strings containing the fragment
+ * shader source code
+ */
+GLuint
+vlc_gl_BuildProgram(vlc_object_t *obj, const opengl_vtable_t *vt,
+ GLsizei vstring_count, const GLchar **vstrings,
+ GLsizei fstring_count, const GLchar **fstrings);
+
#endif
diff --git a/modules/video_output/opengl/internal.h b/modules/video_output/opengl/internal.h
index e7143e1a05..f4ed495252 100644
--- a/modules/video_output/opengl/internal.h
+++ b/modules/video_output/opengl/internal.h
@@ -28,7 +28,7 @@ int
opengl_interop_init_impl(struct vlc_gl_interop *interop, GLenum tex_target,
vlc_fourcc_t chroma, video_color_space_t yuv_space);
-GLuint
+char *
opengl_fragment_shader_init(struct vlc_gl_renderer *rendeer,
GLenum, vlc_fourcc_t, video_color_space_t);
int
diff --git a/modules/video_output/opengl/renderer.c b/modules/video_output/opengl/renderer.c
index 0969c99dc2..416530ffea 100644
--- a/modules/video_output/opengl/renderer.c
+++ b/modules/video_output/opengl/renderer.c
@@ -169,11 +169,9 @@ static void getOrientationTransformMatrix(video_orientation_t orientation,
}
}
-static GLuint BuildVertexShader(const struct vlc_gl_renderer *renderer,
- unsigned plane_count)
+static char *
+BuildVertexShader(const struct vlc_gl_renderer *renderer, unsigned plane_count)
{
- const opengl_vtable_t *vt = renderer->vt;
-
/* Basic vertex shader */
static const char *template =
"#version %u\n"
@@ -205,16 +203,12 @@ static GLuint BuildVertexShader(const struct vlc_gl_renderer *renderer,
char *code;
if (asprintf(&code, template, renderer->glsl_version, coord1_header,
coord2_header, coord1_code, coord2_code) < 0)
- return 0;
+ return NULL;
- GLuint shader = vt->CreateShader(GL_VERTEX_SHADER);
- vt->ShaderSource(shader, 1, (const char **) &code, NULL);
if (renderer->b_dump_shaders)
msg_Dbg(renderer->gl, "\n=== Vertex shader for fourcc: %4.4s ===\n%s\n",
(const char *) &renderer->interop->fmt.i_chroma, code);
- vt->CompileShader(shader);
- free(code);
- return shader;
+ return code;
}
static int
@@ -223,16 +217,19 @@ opengl_link_program(struct vlc_gl_renderer *renderer)
struct vlc_gl_interop *interop = renderer->interop;
const opengl_vtable_t *vt = renderer->vt;
- GLuint vertex_shader = BuildVertexShader(renderer, interop->tex_count);
+ char *vertex_shader = BuildVertexShader(renderer, interop->tex_count);
if (!vertex_shader)
return VLC_EGENERIC;
- GLuint fragment_shader =
+ char *fragment_shader =
opengl_fragment_shader_init(renderer, interop->tex_target,
interop->sw_fmt.i_chroma,
interop->sw_fmt.space);
if (!fragment_shader)
+ {
+ free(vertex_shader);
return VLC_EGENERIC;
+ }
assert(interop->tex_target != 0 &&
interop->tex_count > 0 &&
@@ -240,58 +237,14 @@ opengl_link_program(struct vlc_gl_renderer *renderer)
renderer->pf_fetch_locations != NULL &&
renderer->pf_prepare_shader != NULL);
- GLuint shaders[] = { fragment_shader, vertex_shader };
-
- /* Check shaders messages */
- for (unsigned i = 0; i < 2; i++) {
- int infoLength;
- vt->GetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &infoLength);
- if (infoLength <= 1)
- continue;
-
- char *infolog = malloc(infoLength);
- if (infolog != NULL)
- {
- int charsWritten;
- vt->GetShaderInfoLog(shaders[i], infoLength, &charsWritten,
- infolog);
- msg_Err(renderer->gl, "shader %u: %s", i, infolog);
- free(infolog);
- }
- }
-
- GLuint program_id = renderer->program_id = vt->CreateProgram();
- vt->AttachShader(program_id, fragment_shader);
- vt->AttachShader(program_id, vertex_shader);
- vt->LinkProgram(program_id);
-
- vt->DeleteShader(vertex_shader);
- vt->DeleteShader(fragment_shader);
-
- /* Check program messages */
- int infoLength = 0;
- vt->GetProgramiv(program_id, GL_INFO_LOG_LENGTH, &infoLength);
- if (infoLength > 1)
- {
- char *infolog = malloc(infoLength);
- if (infolog != NULL)
- {
- int charsWritten;
- vt->GetProgramInfoLog(program_id, infoLength, &charsWritten,
- infolog);
- msg_Err(renderer->gl, "shader program: %s", infolog);
- free(infolog);
- }
-
- /* If there is some message, better to check linking is ok */
- GLint link_status = GL_TRUE;
- vt->GetProgramiv(program_id, GL_LINK_STATUS, &link_status);
- if (link_status == GL_FALSE)
- {
- msg_Err(renderer->gl, "Unable to use program");
- goto error;
- }
- }
+ GLuint program_id =
+ vlc_gl_BuildProgram(VLC_OBJECT(renderer->gl), vt,
+ 1, (const char **) &vertex_shader,
+ 1, (const char **) &fragment_shader);
+ free(vertex_shader);
+ free(fragment_shader);
+ if (!program_id)
+ return VLC_EGENERIC;
/* Fetch UniformLocations and AttribLocations */
#define GET_LOC(type, x, str) do { \
@@ -332,6 +285,8 @@ opengl_link_program(struct vlc_gl_renderer *renderer)
goto error;
}
+ renderer->program_id = program_id;
+
return VLC_SUCCESS;
error:
diff --git a/modules/video_output/opengl/sub_renderer.c b/modules/video_output/opengl/sub_renderer.c
index f91e663eec..d235b5681b 100644
--- a/modules/video_output/opengl/sub_renderer.c
+++ b/modules/video_output/opengl/sub_renderer.c
@@ -82,132 +82,6 @@ struct vlc_gl_sub_renderer
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"
- "uniform float alpha;\n"
- "varying vec2 tex_coords;\n"
- "void main() {\n"
- " vec4 color = texture2D(sampler, tex_coords);\n"
- " color.a *= alpha;\n"
- " gl_FragColor = color;\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)
{
@@ -260,7 +134,32 @@ vlc_gl_sub_renderer_New(vlc_gl_t *gl, const opengl_vtable_t *vt,
sr->region_count = 0;
sr->regions = NULL;
- sr->program_id = CreateProgram(VLC_OBJECT(sr->gl), 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"
+ "uniform float alpha;\n"
+ "varying vec2 tex_coords;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sampler, tex_coords);\n"
+ " color.a *= alpha;\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+
+ sr->program_id =
+ vlc_gl_BuildProgram(VLC_OBJECT(sr->gl), vt,
+ 1, (const char **) &VERTEX_SHADER_SRC,
+ 1, (const char **) &FRAGMENT_SHADER_SRC);
if (!sr->program_id)
goto error_2;
--
2.25.0
More information about the vlc-devel
mailing list