[vlc-devel] [PATCH 06/27] opengl: add "direct" sampler
Romain Vimont
rom1v at videolabs.io
Thu Jun 25 14:22:53 CEST 2020
A sampler exposes the VLC input picture via a GLSL function
vlc_texture().
Until now, the input picture always came from the interop (initialized
from a picture_t). With filters, the input picture may now be the output
picture of the previous filter, already stored in a OpenGL texture.
In that case, we need a sampler able to expose this input via
vlc_texture().
---
modules/video_output/opengl/sampler.c | 104 ++++++++++++++++++++-
modules/video_output/opengl/sampler_priv.h | 41 +++++++-
modules/video_output/opengl/vout_helper.c | 4 +-
3 files changed, 139 insertions(+), 10 deletions(-)
diff --git a/modules/video_output/opengl/sampler.c b/modules/video_output/opengl/sampler.c
index 0b58ffb0f6..3b7802be2f 100644
--- a/modules/video_output/opengl/sampler.c
+++ b/modules/video_output/opengl/sampler.c
@@ -81,7 +81,16 @@ struct vlc_gl_sampler_priv {
unsigned int i_visible_height;
} last_source;
+ /* A sampler supports 2 kinds of input.
+ * - created with _NewFromInterop(), it receives input pictures from VLC
+ * (picture_t) via _UpdatePicture();
+ * - created with _NewDirect() (interop is NULL), it receives directly
+ * OpenGL textures via _UpdateTexture().
+ */
struct vlc_gl_interop *interop;
+
+ /* Only used for "direct" sampler (when interop == NULL) */
+ video_format_t direct_fmt;
};
#define PRIV(sampler) container_of(sampler, struct vlc_gl_sampler_priv, sampler)
@@ -936,7 +945,7 @@ opengl_fragment_shader_init(struct vlc_gl_sampler *sampler, GLenum tex_target,
}
struct vlc_gl_sampler *
-vlc_gl_sampler_New(struct vlc_gl_interop *interop)
+vlc_gl_sampler_NewFromInterop(struct vlc_gl_interop *interop)
{
struct vlc_gl_sampler_priv *priv = calloc(1, sizeof(*priv));
if (!priv)
@@ -1024,16 +1033,85 @@ vlc_gl_sampler_New(struct vlc_gl_interop *interop)
return sampler;
}
+
+static void
+sampler_direct_fetch_locations(struct vlc_gl_sampler *sampler, GLuint program)
+{
+ struct vlc_gl_sampler_priv *priv = PRIV(sampler);
+ const opengl_vtable_t *vt = priv->vt;
+
+ priv->uloc.Textures[0] =
+ vt->GetUniformLocation(program, "vlc_input_texture");
+ assert(priv->uloc.Textures[0] != -1);
+}
+
+static void
+sampler_direct_load(const struct vlc_gl_sampler *sampler)
+{
+ struct vlc_gl_sampler_priv *priv = PRIV(sampler);
+ const opengl_vtable_t *vt = priv->vt;
+
+ GLuint texture = priv->textures[0];
+
+ vt->ActiveTexture(GL_TEXTURE0);
+ vt->BindTexture(GL_TEXTURE_2D, texture);
+ vt->Uniform1i(priv->uloc.Textures[0], 0);
+}
+
+struct vlc_gl_sampler *
+vlc_gl_sampler_NewDirect(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
+ const video_format_t *fmt)
+{
+ struct vlc_gl_sampler_priv *priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return NULL;
+
+ struct vlc_gl_sampler *sampler = &priv->sampler;
+
+ priv->interop = NULL;
+ priv->gl = gl;
+ priv->vt = &api->vt;
+
+ sampler->fmt = *fmt;
+ /* this is the only allocated field, and we don't need it */
+ sampler->fmt.p_palette = NULL;
+
+ static const char *const SHADER_BODY =
+ "uniform sampler2D vlc_input_texture;\n"
+ "vec4 vlc_texture(vec2 pic_coords) {\n"
+ " return texture2D(vlc_input_texture, pic_coords);\n"
+ "}\n";
+
+ sampler->shader.body = strdup(SHADER_BODY);
+ if (!sampler->shader.body)
+ {
+ free(priv);
+ return NULL;
+ }
+
+ /* No extension required */
+ sampler->shader.extensions = NULL;
+
+ static const struct vlc_gl_sampler_ops ops = {
+ .fetch_locations = sampler_direct_fetch_locations,
+ .load = sampler_direct_load,
+ };
+ sampler->ops = &ops;
+
+ return sampler;
+}
+
void
vlc_gl_sampler_Delete(struct vlc_gl_sampler *sampler)
{
struct vlc_gl_sampler_priv *priv = PRIV(sampler);
struct vlc_gl_interop *interop = priv->interop;
- const opengl_vtable_t *vt = interop->vt;
-
- if (!interop->handle_texs_gen)
+ if (interop && !interop->handle_texs_gen)
+ {
+ const opengl_vtable_t *vt = interop->vt;
vt->DeleteTextures(interop->tex_count, priv->textures);
+ }
#ifdef HAVE_LIBPLACEBO
FREENULL(priv->uloc.pl_vars);
@@ -1048,11 +1126,13 @@ vlc_gl_sampler_Delete(struct vlc_gl_sampler *sampler)
}
int
-vlc_gl_sampler_Update(struct vlc_gl_sampler *sampler, picture_t *picture)
+vlc_gl_sampler_UpdatePicture(struct vlc_gl_sampler *sampler, picture_t *picture)
{
struct vlc_gl_sampler_priv *priv = PRIV(sampler);
const struct vlc_gl_interop *interop = priv->interop;
+ assert(interop);
+
const video_format_t *source = &picture->format;
if (source->i_x_offset != priv->last_source.i_x_offset
@@ -1140,3 +1220,17 @@ vlc_gl_sampler_Update(struct vlc_gl_sampler *sampler, picture_t *picture)
priv->tex_widths, priv->tex_heights,
picture, NULL);
}
+
+int
+vlc_gl_sampler_UpdateTexture(struct vlc_gl_sampler *sampler, GLuint texture,
+ GLsizei tex_width, GLsizei tex_height)
+{
+ struct vlc_gl_sampler_priv *priv = PRIV(sampler);
+ assert(!priv->interop);
+
+ priv->textures[0] = texture;
+ priv->tex_widths[0] = tex_width;
+ priv->tex_heights[0] = tex_height;
+
+ return VLC_SUCCESS;
+}
diff --git a/modules/video_output/opengl/sampler_priv.h b/modules/video_output/opengl/sampler_priv.h
index ccd96b60c4..20513b9f6d 100644
--- a/modules/video_output/opengl/sampler_priv.h
+++ b/modules/video_output/opengl/sampler_priv.h
@@ -23,17 +23,35 @@
#include <vlc_common.h>
+#include "gl_api.h"
#include "sampler.h"
struct vlc_gl_interop;
/**
- * Create a new sampler
+ * Create a new sampler from an interop
+ *
+ * It receives input pictures from `picture_t`, and uses the interop to
+ * uploaded them to OpenGL textures.
*
* \param interop the interop
*/
struct vlc_gl_sampler *
-vlc_gl_sampler_New(struct vlc_gl_interop *interop);
+vlc_gl_sampler_NewFromInterop(struct vlc_gl_interop *interop);
+
+/**
+ * Create a new direct sampler
+ *
+ * It receives input textures directly (typically the output of a previous
+ * filter).
+ *
+ * \param gl the OpenGL context
+ * \param api the OpenGL API
+ * \param fmt the input format
+ */
+struct vlc_gl_sampler *
+vlc_gl_sampler_NewDirect(struct vlc_gl_t *gl, const struct vlc_gl_api *api,
+ const video_format_t *fmt);
/**
* Delete a sampler
@@ -48,10 +66,27 @@ vlc_gl_sampler_Delete(struct vlc_gl_sampler *sampler);
*
* This changes the current input picture, available from the fragment shader.
*
+ * Warning: only call on sampler created by vlc_gl_sampler_NewFromInterop().
+ *
* \param sampler the sampler
* \param picture the new picture
*/
int
-vlc_gl_sampler_Update(struct vlc_gl_sampler *sampler, picture_t *picture);
+vlc_gl_sampler_UpdatePicture(struct vlc_gl_sampler *sampler,
+ picture_t *picture);
+
+/**
+ * Update the input texture
+ *
+ * Warning: only call on sampler created by vlc_gl_sampler_NewDirect().
+ *
+ * \param sampler the sampler
+ * \param texture the new current texture
+ * \param tex_width the texture width
+ * \param tex_height the texture height
+ */
+int
+vlc_gl_sampler_UpdateTexture(struct vlc_gl_sampler *sampler, GLuint texture,
+ GLsizei tex_width, GLsizei tex_height);
#endif
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index 8eed276d54..726bff56bd 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -144,7 +144,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
goto free_vgl;
}
- vgl->sampler = vlc_gl_sampler_New(vgl->interop);
+ vgl->sampler = vlc_gl_sampler_NewFromInterop(vgl->interop);
if (!vgl->sampler)
{
msg_Err(gl, "Could not create sampler");
@@ -266,7 +266,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
{
GL_ASSERT_NOERROR(&vgl->api.vt);
- int ret = vlc_gl_sampler_Update(vgl->sampler, picture);
+ int ret = vlc_gl_sampler_UpdatePicture(vgl->sampler, picture);
if (ret != VLC_SUCCESS)
return ret;
--
2.27.0
More information about the vlc-devel
mailing list