[vlc-devel] [PATCH v2 02/21] opengl: extract interop from converter
Romain Vimont
rom1v at videolabs.io
Tue Jan 7 12:41:38 CET 2020
Extract fields specific to texture interop into a separate structure.
For now, it is still embedded in opengl_tex_converter_t.
---
modules/video_output/opengl/converter.h | 105 +----------
.../video_output/opengl/converter_android.c | 66 +++----
modules/video_output/opengl/converter_cvpx.c | 111 ++++++------
modules/video_output/opengl/converter_sw.c | 138 ++++++++-------
modules/video_output/opengl/converter_vaapi.c | 92 +++++-----
modules/video_output/opengl/converter_vdpau.c | 41 +++--
.../video_output/opengl/fragment_shaders.c | 71 ++++----
modules/video_output/opengl/interop.h | 150 ++++++++++++++++
modules/video_output/opengl/vout_helper.c | 165 ++++++++++--------
9 files changed, 529 insertions(+), 410 deletions(-)
create mode 100644 modules/video_output/opengl/interop.h
diff --git a/modules/video_output/opengl/converter.h b/modules/video_output/opengl/converter.h
index 211d7e07c4..a7780ef8db 100644
--- a/modules/video_output/opengl/converter.h
+++ b/modules/video_output/opengl/converter.h
@@ -27,6 +27,7 @@
#include <vlc_picture_pool.h>
#include <vlc_plugin.h>
#include "gl_common.h"
+#include "interop.h"
struct pl_context;
struct pl_shader;
@@ -47,9 +48,6 @@ struct opengl_tex_converter_t
/* Pointer to object gl, set by the caller */
vlc_gl_t *gl;
- /* Pointer to decoder video context, set by the caller (can be NULL) */
- vlc_video_context *vctx;
-
/* libplacebo context, created by the caller (optional) */
struct pl_context *pl_ctx;
@@ -64,45 +62,16 @@ struct opengl_tex_converter_t
GLuint (*pf_fragment_shader_init)(opengl_tex_converter_t *, GLenum,
vlc_fourcc_t, video_color_space_t);
- /* Available gl extensions (from GL_EXTENSIONS) */
- const char *glexts;
-
- /* True if the current API is OpenGL ES, set by the caller */
- bool is_gles;
/* GLSL version, set by the caller. 100 for GLSL ES, 120 for desktop GLSL */
unsigned glsl_version;
/* Precision header, set by the caller. In OpenGLES, the fragment language
* has no default precision qualifier for floating point types. */
const char *glsl_precision_header;
- /* Can only be changed from the module open function */
- video_format_t fmt;
-
/* Fragment shader, must be set from the module open function. It will be
* deleted by the caller. */
GLuint fshader;
- /* Number of textures, cannot be 0 */
- unsigned tex_count;
-
- /* Texture mapping (usually: GL_TEXTURE_2D), cannot be 0 */
- GLenum tex_target;
-
- /* Set to true if textures are generated from pf_update() */
- bool handle_texs_gen;
-
- struct opengl_tex_cfg {
- /* Texture scale factor, cannot be 0 */
- vlc_rational_t w;
- vlc_rational_t h;
-
- /* The following is used and filled by the opengl_fragment_shader_init
- * function. */
- GLint internal;
- GLenum format;
- GLenum type;
- } texs[PICTURE_PLANE_MAX];
-
/* The following is used and filled by the opengl_fragment_shader_init
* function. */
struct {
@@ -118,57 +87,7 @@ struct opengl_tex_converter_t
struct pl_shader *pl_sh;
const struct pl_shader_res *pl_sh_res;
- /* Private context */
- void *priv;
-
- /**
- * Callback to allocate data for bound textures
- *
- * This function pointer can be NULL. Software converters should call
- * glTexImage2D() to allocate textures data (it will be deallocated by the
- * caller when calling glDeleteTextures()). Won't be called if
- * handle_texs_gen is true.
- *
- * \param tc OpenGL tex converter
- * \param textures array of textures to bind (one per plane)
- * \param tex_width array of tex width (one per plane)
- * \param tex_height array of tex height (one per plane)
- * \return VLC_SUCCESS or a VLC error
- */
- int (*pf_allocate_textures)(const opengl_tex_converter_t *tc, GLuint *textures,
- const GLsizei *tex_width, const GLsizei *tex_height);
-
- /**
- * Callback to allocate a picture pool
- *
- * This function pointer *can* be NULL. If NULL, A generic pool with
- * pictures allocated from the video_format_t will be used.
- *
- * \param tc OpenGL tex converter
- * \param requested_count number of pictures to allocate
- * \return the picture pool or NULL in case of error
- */
- picture_pool_t *(*pf_get_pool)(const opengl_tex_converter_t *tc,
- unsigned requested_count);
-
- /**
- * Callback to update a picture
- *
- * This function pointer cannot be NULL. The implementation should upload
- * every planes of the picture.
- *
- * \param tc OpenGL tex converter
- * \param textures array of textures to bind (one per plane)
- * \param tex_width array of tex width (one per plane)
- * \param tex_height array of tex height (one per plane)
- * \param pic picture to update
- * \param plane_offset offsets of each picture planes to read data from
- * (one per plane, can be NULL)
- * \return VLC_SUCCESS or a VLC error
- */
- int (*pf_update)(const opengl_tex_converter_t *tc, GLuint *textures,
- const GLsizei *tex_width, const GLsizei *tex_height,
- picture_t *pic, const size_t *plane_offset);
+ struct vlc_gl_interop interop;
/**
* Callback to fetch locations of uniform or attributes variables
@@ -196,26 +115,6 @@ struct opengl_tex_converter_t
void (*pf_prepare_shader)(const opengl_tex_converter_t *tc,
const GLsizei *tex_width, const GLsizei *tex_height,
float alpha);
-
- /**
- * Callback to retrieve the transform matrix to apply to texture coordinates
- *
- * This function pointer can be NULL. If it is set, it may return NULL.
- *
- * Otherwise, it must return a 4x4 matrix, as an array of 16 floats in
- * column-major order.
- *
- * This transform matrix maps 2D homogeneous texture coordinates of the
- * form (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the
- * texture coordinate that should be used to sample that location from the
- * texture.
- *
- * The returned pointer is owned by the converter module, and must not be
- * freed before the module is closed.
- *
- * \param tc OpenGL tex converter
- */
- const float *(*pf_get_transform_matrix)(const opengl_tex_converter_t *tc);
};
/**
diff --git a/modules/video_output/opengl/converter_android.c b/modules/video_output/opengl/converter_android.c
index 6468068640..0bdca07c2c 100644
--- a/modules/video_output/opengl/converter_android.c
+++ b/modules/video_output/opengl/converter_android.c
@@ -38,15 +38,15 @@ struct priv
};
static int
-tc_anop_allocate_textures(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_anop_allocate_textures(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height)
{
(void) tex_width; (void) tex_height;
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
assert(textures[0] != 0);
if (SurfaceTexture_attachToGLContext(priv->awh, textures[0]) != 0)
{
- msg_Err(tc->gl, "SurfaceTexture_attachToGLContext failed");
+ msg_Err(interop->gl, "SurfaceTexture_attachToGLContext failed");
return VLC_EGENERIC;
}
priv->stex_attached = true;
@@ -54,7 +54,7 @@ tc_anop_allocate_textures(const opengl_tex_converter_t *tc, GLuint *textures,
}
static int
-tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_anop_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
picture_t *pic, const size_t *plane_offset)
{
@@ -65,7 +65,7 @@ tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
if (plane_offset != NULL)
return VLC_EGENERIC;
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
if (!priv->avctx->render(pic->context))
return VLC_SUCCESS; /* already rendered */
@@ -77,16 +77,16 @@ tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
return VLC_EGENERIC;
}
- tc->vt->ActiveTexture(GL_TEXTURE0);
- tc->vt->BindTexture(tc->tex_target, textures[0]);
+ interop->vt->ActiveTexture(GL_TEXTURE0);
+ interop->vt->BindTexture(interop->tex_target, textures[0]);
return VLC_SUCCESS;
}
static const float *
-tc_get_transform_matrix(const opengl_tex_converter_t *tc)
+tc_get_transform_matrix(const struct vlc_gl_interop *interop)
{
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
return priv->transform_mtx;
}
@@ -94,7 +94,7 @@ static void
Close(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *)obj;
- struct priv *priv = tc->priv;
+ struct priv *priv = tc->interop.priv;
if (priv->stex_attached)
SurfaceTexture_detachFromGLContext(priv->awh);
@@ -106,60 +106,64 @@ static int
Open(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *) obj;
+ struct vlc_gl_interop *interop = &tc->interop;
- if (tc->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE
- || !tc->gl->surface->handle.anativewindow
- || !tc->vctx)
+ if (interop->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE
+ || !interop->gl->surface->handle.anativewindow
+ || !interop->vctx)
return VLC_EGENERIC;
android_video_context_t *avctx =
- vlc_video_context_GetPrivate(tc->vctx, VLC_VIDEO_CONTEXT_AWINDOW);
+ vlc_video_context_GetPrivate(interop->vctx, VLC_VIDEO_CONTEXT_AWINDOW);
if (avctx->id != AWindow_SurfaceTexture)
return VLC_EGENERIC;
- tc->priv = malloc(sizeof(struct priv));
- if (unlikely(tc->priv == NULL))
+ interop->priv = malloc(sizeof(struct priv));
+ if (unlikely(interop->priv == NULL))
return VLC_ENOMEM;
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
priv->avctx = avctx;
- priv->awh = tc->gl->surface->handle.anativewindow;
+ priv->awh = interop->gl->surface->handle.anativewindow;
priv->transform_mtx = NULL;
priv->stex_attached = false;
- tc->pf_allocate_textures = tc_anop_allocate_textures;
- tc->pf_update = tc_anop_update;
- tc->pf_get_transform_matrix = tc_get_transform_matrix;
+ static const struct vlc_gl_interop_ops ops = {
+ .allocate_textures = tc_anop_allocate_textures,
+ .update_textures = tc_anop_update,
+ .get_transform_matrix = tc_get_transform_matrix,
+ };
+ interop->ops = &ops;
/* The transform Matrix (uSTMatrix) given by the SurfaceTexture is not
* using the same origin than us. Ask the caller to rotate textures
* coordinates, via the vertex shader, by forcing an orientation. */
- switch (tc->fmt.orientation)
+ switch (interop->fmt.orientation)
{
case ORIENT_TOP_LEFT:
- tc->fmt.orientation = ORIENT_BOTTOM_LEFT;
+ interop->fmt.orientation = ORIENT_BOTTOM_LEFT;
break;
case ORIENT_TOP_RIGHT:
- tc->fmt.orientation = ORIENT_BOTTOM_RIGHT;
+ interop->fmt.orientation = ORIENT_BOTTOM_RIGHT;
break;
case ORIENT_BOTTOM_LEFT:
- tc->fmt.orientation = ORIENT_TOP_LEFT;
+ interop->fmt.orientation = ORIENT_TOP_LEFT;
break;
case ORIENT_BOTTOM_RIGHT:
- tc->fmt.orientation = ORIENT_TOP_RIGHT;
+ interop->fmt.orientation = ORIENT_TOP_RIGHT;
break;
case ORIENT_LEFT_TOP:
- tc->fmt.orientation = ORIENT_RIGHT_TOP;
+ interop->fmt.orientation = ORIENT_RIGHT_TOP;
break;
case ORIENT_LEFT_BOTTOM:
- tc->fmt.orientation = ORIENT_RIGHT_BOTTOM;
+ interop->fmt.orientation = ORIENT_RIGHT_BOTTOM;
break;
case ORIENT_RIGHT_TOP:
- tc->fmt.orientation = ORIENT_LEFT_TOP;
+ interop->fmt.orientation = ORIENT_LEFT_TOP;
break;
case ORIENT_RIGHT_BOTTOM:
- tc->fmt.orientation = ORIENT_LEFT_BOTTOM;
+ interop->fmt.orientation = ORIENT_LEFT_BOTTOM;
break;
}
@@ -168,7 +172,7 @@ Open(vlc_object_t *obj)
COLOR_SPACE_UNDEF);
if (!tc->fshader)
{
- free(tc->priv);
+ free(priv);
return VLC_EGENERIC;
}
diff --git a/modules/video_output/opengl/converter_cvpx.c b/modules/video_output/opengl/converter_cvpx.c
index df93a90f56..c5978a23b2 100644
--- a/modules/video_output/opengl/converter_cvpx.c
+++ b/modules/video_output/opengl/converter_cvpx.c
@@ -47,16 +47,16 @@ struct priv
#if TARGET_OS_IPHONE
/* CVOpenGLESTextureCache version (ios) */
static int
-tc_cvpx_update(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
CVPixelBufferRef pixelBuffer = cvpxpic_get_ref(pic);
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
{
if (likely(priv->last_cvtexs[i]))
{
@@ -67,28 +67,28 @@ tc_cvpx_update(const opengl_tex_converter_t *tc, GLuint *textures,
CVOpenGLESTextureCacheFlush(priv->cache, 0);
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
{
CVOpenGLESTextureRef cvtex;
CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(
kCFAllocatorDefault, priv->cache, pixelBuffer, NULL,
- tc->tex_target, tc->texs[i].internal, tex_width[i], tex_height[i],
- tc->texs[i].format, tc->texs[i].type, i, &cvtex);
+ interop->tex_target, interop->texs[i].internal, tex_width[i], tex_height[i],
+ interop->texs[i].format, interop->texs[i].type, i, &cvtex);
if (err != noErr)
{
- msg_Err(tc->gl,
+ msg_Err(interop->gl,
"CVOpenGLESTextureCacheCreateTextureFromImage failed: %d",
err);
return VLC_EGENERIC;
}
textures[i] = CVOpenGLESTextureGetName(cvtex);
- tc->vt->BindTexture(tc->tex_target, textures[i]);
- tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- tc->vt->TexParameterf(tc->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- tc->vt->TexParameterf(tc->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- tc->vt->BindTexture(tc->tex_target, 0);
+ interop->vt->BindTexture(interop->tex_target, textures[i]);
+ interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ interop->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ interop->vt->TexParameterf(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ interop->vt->TexParameterf(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ interop->vt->BindTexture(interop->tex_target, 0);
priv->last_cvtexs[i] = cvtex;
}
@@ -98,32 +98,32 @@ tc_cvpx_update(const opengl_tex_converter_t *tc, GLuint *textures,
#else
/* IOSurface version (macos) */
static int
-tc_cvpx_update(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_cvpx_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
CVPixelBufferRef pixelBuffer = cvpxpic_get_ref(pic);
IOSurfaceRef surface = CVPixelBufferGetIOSurface(pixelBuffer);
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
{
- tc->vt->ActiveTexture(GL_TEXTURE0 + i);
- tc->vt->BindTexture(tc->tex_target, textures[i]);
+ interop->vt->ActiveTexture(GL_TEXTURE0 + i);
+ interop->vt->BindTexture(interop->tex_target, textures[i]);
CGLError err =
- CGLTexImageIOSurface2D(priv->gl_ctx, tc->tex_target,
- tc->texs[i].internal,
+ CGLTexImageIOSurface2D(priv->gl_ctx, interop->tex_target,
+ interop->texs[i].internal,
tex_width[i], tex_height[i],
- tc->texs[i].format,
- tc->texs[i].type,
+ interop->texs[i].format,
+ interop->texs[i].type,
surface, i);
if (err != kCGLNoError)
{
- msg_Err(tc->gl, "CGLTexImageIOSurface2D error: %u: %s", i,
+ msg_Err(interop->gl, "CGLTexImageIOSurface2D error: %u: %s", i,
CGLErrorString(err));
return VLC_EGENERIC;
}
@@ -144,10 +144,11 @@ static void
Close(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *)obj;
- struct priv *priv = tc->priv;
+ struct vlc_gl_interop *interop = &tc->interop;
+ struct priv *priv = interop->priv;
#if TARGET_OS_IPHONE
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
{
if (likely(priv->last_cvtexs[i]))
CFRelease(priv->last_cvtexs[i]);
@@ -157,18 +158,20 @@ Close(vlc_object_t *obj)
if (priv->last_pic != NULL)
picture_Release(priv->last_pic);
#endif
- free(tc->priv);
+ free(priv);
}
static int
Open(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *) obj;
- if (tc->fmt.i_chroma != VLC_CODEC_CVPX_UYVY
- && tc->fmt.i_chroma != VLC_CODEC_CVPX_NV12
- && tc->fmt.i_chroma != VLC_CODEC_CVPX_I420
- && tc->fmt.i_chroma != VLC_CODEC_CVPX_BGRA
- && tc->fmt.i_chroma != VLC_CODEC_CVPX_P010)
+ struct vlc_gl_interop *interop = &tc->interop;
+
+ if (interop->fmt.i_chroma != VLC_CODEC_CVPX_UYVY
+ && interop->fmt.i_chroma != VLC_CODEC_CVPX_NV12
+ && interop->fmt.i_chroma != VLC_CODEC_CVPX_I420
+ && interop->fmt.i_chroma != VLC_CODEC_CVPX_BGRA
+ && interop->fmt.i_chroma != VLC_CODEC_CVPX_P010)
return VLC_EGENERIC;
struct priv *priv = calloc(1, sizeof(struct priv));
@@ -179,10 +182,10 @@ Open(vlc_object_t *obj)
const GLenum tex_target = GL_TEXTURE_2D;
{
- CVEAGLContext eagl_ctx = var_InheritAddress(tc->gl, "ios-eaglcontext");
+ CVEAGLContext eagl_ctx = var_InheritAddress(interop->gl, "ios-eaglcontext");
if (!eagl_ctx)
{
- msg_Err(tc->gl, "can't find ios-eaglcontext");
+ msg_Err(interop->gl, "can't find ios-eaglcontext");
free(priv);
return VLC_EGENERIC;
}
@@ -191,7 +194,7 @@ Open(vlc_object_t *obj)
eagl_ctx, NULL, &priv->cache);
if (err != noErr)
{
- msg_Err(tc->gl, "CVOpenGLESTextureCacheCreate failed: %d", err);
+ msg_Err(interop->gl, "CVOpenGLESTextureCacheCreate failed: %d", err);
free(priv);
return VLC_EGENERIC;
}
@@ -199,10 +202,10 @@ Open(vlc_object_t *obj)
#else
const GLenum tex_target = GL_TEXTURE_RECTANGLE;
{
- priv->gl_ctx = var_InheritAddress(tc->gl, "macosx-glcontext");
+ priv->gl_ctx = var_InheritAddress(interop->gl, "macosx-glcontext");
if (!priv->gl_ctx)
{
- msg_Err(tc->gl, "can't find macosx-glcontext");
+ msg_Err(interop->gl, "can't find macosx-glcontext");
free(priv);
return VLC_EGENERIC;
}
@@ -210,7 +213,7 @@ Open(vlc_object_t *obj)
#endif
GLuint fragment_shader;
- switch (tc->fmt.i_chroma)
+ switch (interop->fmt.i_chroma)
{
case VLC_CODEC_CVPX_UYVY:
/* Generate a VLC_CODEC_VYUY shader in order to use the "gbr"
@@ -221,41 +224,41 @@ Open(vlc_object_t *obj)
fragment_shader =
opengl_fragment_shader_init(tc, tex_target, VLC_CODEC_VYUY,
- tc->fmt.space);
- tc->texs[0].internal = GL_RGB;
- tc->texs[0].format = GL_RGB_422_APPLE;
- tc->texs[0].type = GL_UNSIGNED_SHORT_8_8_APPLE;
- tc->texs[0].w = tc->texs[0].h = (vlc_rational_t) { 1, 1 };
+ interop->fmt.space);
+ interop->texs[0].internal = GL_RGB;
+ interop->texs[0].format = GL_RGB_422_APPLE;
+ interop->texs[0].type = GL_UNSIGNED_SHORT_8_8_APPLE;
+ interop->texs[0].w = interop->texs[0].h = (vlc_rational_t) { 1, 1 };
break;
case VLC_CODEC_CVPX_NV12:
{
fragment_shader =
opengl_fragment_shader_init(tc, tex_target, VLC_CODEC_NV12,
- tc->fmt.space);
+ interop->fmt.space);
break;
}
case VLC_CODEC_CVPX_P010:
{
fragment_shader =
opengl_fragment_shader_init(tc, tex_target, VLC_CODEC_P010,
- tc->fmt.space);
+ interop->fmt.space);
break;
}
case VLC_CODEC_CVPX_I420:
fragment_shader =
opengl_fragment_shader_init(tc, tex_target, VLC_CODEC_I420,
- tc->fmt.space);
+ interop->fmt.space);
break;
case VLC_CODEC_CVPX_BGRA:
fragment_shader =
opengl_fragment_shader_init(tc, tex_target, VLC_CODEC_RGB32,
COLOR_SPACE_UNDEF);
- tc->texs[0].internal = GL_RGBA;
- tc->texs[0].format = GL_BGRA;
+ interop->texs[0].internal = GL_RGBA;
+ interop->texs[0].format = GL_BGRA;
#if TARGET_OS_IPHONE
- tc->texs[0].type = GL_UNSIGNED_BYTE;
+ interop->texs[0].type = GL_UNSIGNED_BYTE;
#else
- tc->texs[0].type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ interop->texs[0].type = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
default:
@@ -269,10 +272,14 @@ Open(vlc_object_t *obj)
}
#if TARGET_OS_IPHONE
- tc->handle_texs_gen = true;
+ interop->handle_texs_gen = true;
#endif
- tc->priv = priv;
- tc->pf_update = tc_cvpx_update;
+ interop->priv = priv;
+ static const struct vlc_gl_interop_ops ops = {
+ .update_textures = tc_cvpx_update,
+ };
+ interop->ops = &ops;
+
tc->fshader = fragment_shader;
return VLC_SUCCESS;
diff --git a/modules/video_output/opengl/converter_sw.c b/modules/video_output/opengl/converter_sw.c
index 3eb3eeb3ae..2b6b9612bb 100644
--- a/modules/video_output/opengl/converter_sw.c
+++ b/modules/video_output/opengl/converter_sw.c
@@ -72,6 +72,8 @@ pbo_picture_destroy(picture_t *pic)
static picture_t *
pbo_picture_create(const opengl_tex_converter_t *tc)
{
+ const struct vlc_gl_interop *interop = &tc->interop;
+
picture_sys_t *picsys = calloc(1, sizeof(*picsys));
if (unlikely(picsys == NULL))
return NULL;
@@ -80,7 +82,7 @@ pbo_picture_create(const opengl_tex_converter_t *tc)
.p_sys = picsys,
.pf_destroy = pbo_picture_destroy,
};
- picture_t *pic = picture_NewFromResource(&tc->fmt, &rsc);
+ picture_t *pic = picture_NewFromResource(&interop->fmt, &rsc);
if (pic == NULL)
{
free(picsys);
@@ -91,14 +93,14 @@ pbo_picture_create(const opengl_tex_converter_t *tc)
picsys->DeleteBuffers = tc->vt->DeleteBuffers;
/* XXX: needed since picture_NewFromResource override pic planes */
- if (picture_Setup(pic, &tc->fmt))
+ if (picture_Setup(pic, &interop->fmt))
{
picture_Release(pic);
return NULL;
}
assert(pic->i_planes > 0
- && (unsigned) pic->i_planes == tc->tex_count);
+ && (unsigned) pic->i_planes == interop->tex_count);
for (int i = 0; i < pic->i_planes; ++i)
{
@@ -141,7 +143,7 @@ pbo_data_alloc(const opengl_tex_converter_t *tc, picture_t *pic)
static int
pbo_pics_alloc(const opengl_tex_converter_t *tc)
{
- struct priv *priv = tc->priv;
+ struct priv *priv = tc->interop.priv;
for (size_t i = 0; i < PBO_DISPLAY_COUNT; ++i)
{
picture_t *pic = priv->pbo.display_pics[i] = pbo_picture_create(tc);
@@ -163,12 +165,12 @@ error:
}
static int
-tc_pbo_update(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_pbo_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset; assert(plane_offset == NULL);
- struct priv *priv = tc->priv;
+ struct priv *priv = interop->priv;
picture_t *display_pic = priv->pbo.display_pics[priv->pbo.display_idx];
picture_sys_t *p_sys = display_pic->p_sys;
@@ -178,53 +180,52 @@ tc_pbo_update(const opengl_tex_converter_t *tc, GLuint *textures,
{
GLsizeiptr size = pic->p[i].i_lines * pic->p[i].i_pitch;
const GLvoid *data = pic->p[i].p_pixels;
- tc->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
+ interop->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
p_sys->buffers[i]);
- tc->vt->BufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, data);
+ interop->vt->BufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, data);
- tc->vt->ActiveTexture(GL_TEXTURE0 + i);
- tc->vt->BindTexture(tc->tex_target, textures[i]);
+ interop->vt->ActiveTexture(GL_TEXTURE0 + i);
+ interop->vt->BindTexture(interop->tex_target, textures[i]);
- tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[i].i_pitch
+ interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[i].i_pitch
* tex_width[i] / (pic->p[i].i_visible_pitch ? pic->p[i].i_visible_pitch : 1));
- tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, tex_width[i], tex_height[i],
- tc->texs[i].format, tc->texs[i].type, NULL);
-
- tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, tex_width[i], tex_height[i],
+ interop->texs[i].format, interop->texs[i].type, NULL);
+ interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
/* turn off pbo */
- tc->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ interop->vt->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
return VLC_SUCCESS;
}
static int
-tc_common_allocate_textures(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_common_allocate_textures(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height)
{
- for (unsigned i = 0; i < tc->tex_count; i++)
+ for (unsigned i = 0; i < interop->tex_count; i++)
{
- tc->vt->BindTexture(tc->tex_target, textures[i]);
- tc->vt->TexImage2D(tc->tex_target, 0, tc->texs[i].internal,
- tex_width[i], tex_height[i], 0, tc->texs[i].format,
- tc->texs[i].type, NULL);
+ interop->vt->BindTexture(interop->tex_target, textures[i]);
+ interop->vt->TexImage2D(interop->tex_target, 0, interop->texs[i].internal,
+ tex_width[i], tex_height[i], 0, interop->texs[i].format,
+ interop->texs[i].type, NULL);
}
return VLC_SUCCESS;
}
static int
-upload_plane(const opengl_tex_converter_t *tc, unsigned tex_idx,
+upload_plane(const struct vlc_gl_interop *interop, unsigned tex_idx,
GLsizei width, GLsizei height,
unsigned pitch, unsigned visible_pitch, const void *pixels)
{
- struct priv *priv = tc->priv;
- GLenum tex_format = tc->texs[tex_idx].format;
- GLenum tex_type = tc->texs[tex_idx].type;
+ struct priv *priv = interop->priv;
+ GLenum tex_format = interop->texs[tex_idx].format;
+ GLenum tex_type = interop->texs[tex_idx].type;
/* This unpack alignment is the default, but setting it just in case. */
- tc->vt->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ interop->vt->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (!priv->has_unpack_subimage)
{
@@ -255,41 +256,41 @@ upload_plane(const opengl_tex_converter_t *tc, unsigned tex_idx,
source += pitch;
destination += visible_pitch;
}
- tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, width, height,
- tex_format, tex_type, priv->texture_temp_buf);
+ interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
+ tex_format, tex_type, priv->texture_temp_buf);
}
else
{
- tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, width, height,
- tex_format, tex_type, pixels);
+ interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
+ tex_format, tex_type, pixels);
}
}
else
{
- tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pitch * width / (visible_pitch ? visible_pitch : 1));
- tc->vt->TexSubImage2D(tc->tex_target, 0, 0, 0, width, height,
- tex_format, tex_type, pixels);
- tc->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, pitch * width / (visible_pitch ? visible_pitch : 1));
+ interop->vt->TexSubImage2D(interop->tex_target, 0, 0, 0, width, height,
+ tex_format, tex_type, pixels);
+ interop->vt->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
return VLC_SUCCESS;
}
static int
-tc_common_update(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_common_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
picture_t *pic, const size_t *plane_offset)
{
int ret = VLC_SUCCESS;
- for (unsigned i = 0; i < tc->tex_count && ret == VLC_SUCCESS; i++)
+ for (unsigned i = 0; i < interop->tex_count && ret == VLC_SUCCESS; i++)
{
assert(textures[i] != 0);
- tc->vt->ActiveTexture(GL_TEXTURE0 + i);
- tc->vt->BindTexture(tc->tex_target, textures[i]);
+ interop->vt->ActiveTexture(GL_TEXTURE0 + i);
+ interop->vt->BindTexture(interop->tex_target, textures[i]);
const void *pixels = plane_offset != NULL ?
&pic->p[i].p_pixels[plane_offset[i]] :
pic->p[i].p_pixels;
- ret = upload_plane(tc, i, tex_width[i], tex_height[i],
+ ret = upload_plane(interop, i, tex_width[i], tex_height[i],
pic->p[i].i_pitch, pic->p[i].i_visible_pitch, pixels);
}
return ret;
@@ -298,21 +299,23 @@ tc_common_update(const opengl_tex_converter_t *tc, GLuint *textures,
int
opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr)
{
+ struct vlc_gl_interop *interop = &tc->interop;
+
GLuint fragment_shader = 0;
video_color_space_t space;
const vlc_fourcc_t *list;
- if (vlc_fourcc_IsYUV(tc->fmt.i_chroma))
+ if (vlc_fourcc_IsYUV(interop->fmt.i_chroma))
{
GLint max_texture_units = 0;
tc->vt->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
if (max_texture_units < 3)
return VLC_EGENERIC;
- list = vlc_fourcc_GetYUVFallback(tc->fmt.i_chroma);
- space = tc->fmt.space;
+ list = vlc_fourcc_GetYUVFallback(interop->fmt.i_chroma);
+ space = interop->fmt.space;
}
- else if (tc->fmt.i_chroma == VLC_CODEC_XYZ12)
+ else if (interop->fmt.i_chroma == VLC_CODEC_XYZ12)
{
static const vlc_fourcc_t xyz12_list[] = { VLC_CODEC_XYZ12, 0 };
list = xyz12_list;
@@ -320,7 +323,7 @@ opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr)
}
else
{
- list = vlc_fourcc_GetRGBFallback(tc->fmt.i_chroma);
+ list = vlc_fourcc_GetRGBFallback(interop->fmt.i_chroma);
space = COLOR_SPACE_UNDEF;
}
@@ -330,20 +333,20 @@ opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr)
opengl_fragment_shader_init(tc, GL_TEXTURE_2D, *list, space);
if (fragment_shader != 0)
{
- tc->fmt.i_chroma = *list;
+ interop->fmt.i_chroma = *list;
- if (tc->fmt.i_chroma == VLC_CODEC_RGB32)
+ if (interop->fmt.i_chroma == VLC_CODEC_RGB32)
{
#if defined(WORDS_BIGENDIAN)
- tc->fmt.i_rmask = 0xff000000;
- tc->fmt.i_gmask = 0x00ff0000;
- tc->fmt.i_bmask = 0x0000ff00;
+ interop->fmt.i_rmask = 0xff000000;
+ interop->fmt.i_gmask = 0x00ff0000;
+ interop->fmt.i_bmask = 0x0000ff00;
#else
- tc->fmt.i_rmask = 0x000000ff;
- tc->fmt.i_gmask = 0x0000ff00;
- tc->fmt.i_bmask = 0x00ff0000;
+ interop->fmt.i_rmask = 0x000000ff;
+ interop->fmt.i_gmask = 0x0000ff00;
+ interop->fmt.i_bmask = 0x00ff0000;
#endif
- video_format_FixRgb(&tc->fmt);
+ video_format_FixRgb(&interop->fmt);
}
break;
}
@@ -352,19 +355,22 @@ opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr)
if (fragment_shader == 0)
return VLC_EGENERIC;
- struct priv *priv = tc->priv = calloc(1, sizeof(struct priv));
+ struct priv *priv = interop->priv = calloc(1, sizeof(struct priv));
if (unlikely(priv == NULL))
{
tc->vt->DeleteShader(fragment_shader);
return VLC_ENOMEM;
}
- tc->pf_update = tc_common_update;
- tc->pf_allocate_textures = tc_common_allocate_textures;
+ static const struct vlc_gl_interop_ops ops = {
+ .allocate_textures = tc_common_allocate_textures,
+ .update_textures = tc_common_update,
+ };
+ interop->ops = &ops;
/* OpenGL or OpenGL ES2 with GL_EXT_unpack_subimage ext */
priv->has_unpack_subimage =
- !tc->is_gles || vlc_gl_StrHasToken(tc->glexts, "GL_EXT_unpack_subimage");
+ !interop->is_gles || vlc_gl_StrHasToken(interop->glexts, "GL_EXT_unpack_subimage");
if (allow_dr && priv->has_unpack_subimage)
{
@@ -373,15 +379,19 @@ opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr)
const bool glver_ok = strverscmp((const char *)ogl_version, "3.0") >= 0;
const bool has_pbo = glver_ok &&
- (vlc_gl_StrHasToken(tc->glexts, "GL_ARB_pixel_buffer_object") ||
- vlc_gl_StrHasToken(tc->glexts, "GL_EXT_pixel_buffer_object"));
+ (vlc_gl_StrHasToken(interop->glexts, "GL_ARB_pixel_buffer_object") ||
+ vlc_gl_StrHasToken(interop->glexts, "GL_EXT_pixel_buffer_object"));
const bool supports_pbo = has_pbo && tc->vt->BufferData
&& tc->vt->BufferSubData;
if (supports_pbo && pbo_pics_alloc(tc) == VLC_SUCCESS)
{
- tc->pf_update = tc_pbo_update;
- msg_Dbg(tc->gl, "PBO support enabled");
+ static const struct vlc_gl_interop_ops pbo_ops = {
+ .allocate_textures = tc_common_allocate_textures,
+ .update_textures = tc_pbo_update,
+ };
+ interop->ops = &pbo_ops;
+ msg_Dbg(interop->gl, "PBO support enabled");
}
}
@@ -393,9 +403,9 @@ opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr)
void
opengl_tex_converter_generic_deinit(opengl_tex_converter_t *tc)
{
- struct priv *priv = tc->priv;
+ struct priv *priv = tc->interop.priv;
for (size_t i = 0; i < PBO_DISPLAY_COUNT && priv->pbo.display_pics[i]; ++i)
picture_Release(priv->pbo.display_pics[i]);
free(priv->texture_temp_buf);
- free(tc->priv);
+ free(priv);
}
diff --git a/modules/video_output/opengl/converter_vaapi.c b/modules/video_output/opengl/converter_vaapi.c
index 6fb1085ec8..7e6e106fe2 100644
--- a/modules/video_output/opengl/converter_vaapi.c
+++ b/modules/video_output/opengl/converter_vaapi.c
@@ -62,7 +62,7 @@ struct priv
};
static EGLImageKHR
-vaegl_image_create(const opengl_tex_converter_t *tc, EGLint w, EGLint h,
+vaegl_image_create(const struct vlc_gl_interop *interop, EGLint w, EGLint h,
EGLint fourcc, EGLint fd, EGLint offset, EGLint pitch)
{
EGLint attribs[] = {
@@ -75,23 +75,23 @@ vaegl_image_create(const opengl_tex_converter_t *tc, EGLint w, EGLint h,
EGL_NONE
};
- return tc->gl->egl.createImageKHR(tc->gl, EGL_LINUX_DMA_BUF_EXT, NULL,
- attribs);
+ return interop->gl->egl.createImageKHR(interop->gl, EGL_LINUX_DMA_BUF_EXT,
+ NULL, attribs);
}
static void
-vaegl_image_destroy(const opengl_tex_converter_t *tc, EGLImageKHR image)
+vaegl_image_destroy(const struct vlc_gl_interop *interop, EGLImageKHR image)
{
- tc->gl->egl.destroyImageKHR(tc->gl, image);
+ interop->gl->egl.destroyImageKHR(interop->gl, image);
}
static void
-vaegl_release_last_pic(const opengl_tex_converter_t *tc, struct priv *priv)
+vaegl_release_last_pic(const struct vlc_gl_interop *interop, struct priv *priv)
{
- vlc_object_t *o = VLC_OBJECT(tc->gl);
+ vlc_object_t *o = VLC_OBJECT(interop->gl);
for (unsigned i = 0; i < priv->last.va_image.num_planes; ++i)
- vaegl_image_destroy(tc, priv->last.egl_images[i]);
+ vaegl_image_destroy(interop, priv->last.egl_images[i]);
vlc_vaapi_ReleaseBufferHandle(o, priv->vadpy, priv->last.va_image.buf);
@@ -149,13 +149,13 @@ vaegl_init_fourcc(const opengl_tex_converter_t *tc, struct priv *priv,
}
static int
-tc_vaegl_update(const opengl_tex_converter_t *tc, GLuint *textures,
+tc_vaegl_update(const struct vlc_gl_interop *interop, GLuint *textures,
const GLsizei *tex_width, const GLsizei *tex_height,
picture_t *pic, const size_t *plane_offset)
{
(void) plane_offset;
- struct priv *priv = tc->priv;
- vlc_object_t *o = VLC_OBJECT(tc->gl);
+ struct priv *priv = interop->priv;
+ vlc_object_t *o = VLC_OBJECT(interop->gl);
VAImage va_image;
VABufferInfo va_buffer_info;
EGLImageKHR egl_images[3] = { };
@@ -189,21 +189,21 @@ tc_vaegl_update(const opengl_tex_converter_t *tc, GLuint *textures,
for (unsigned i = 0; i < va_image.num_planes; ++i)
{
egl_images[i] =
- vaegl_image_create(tc, tex_width[i], tex_height[i],
+ vaegl_image_create(interop, tex_width[i], tex_height[i],
priv->drm_fourccs[i], va_buffer_info.handle,
va_image.offsets[i], va_image.pitches[i]);
if (egl_images[i] == NULL)
goto error;
- tc->vt->BindTexture(tc->tex_target, textures[i]);
+ interop->vt->BindTexture(interop->tex_target, textures[i]);
- priv->glEGLImageTargetTexture2DOES(tc->tex_target, egl_images[i]);
+ priv->glEGLImageTargetTexture2DOES(interop->tex_target, egl_images[i]);
}
if (pic != priv->last.pic)
{
if (priv->last.pic != NULL)
- vaegl_release_last_pic(tc, priv);
+ vaegl_release_last_pic(interop, priv);
priv->last.pic = picture_Hold(pic);
priv->last.va_image = va_image;
priv->last.va_buffer_info = va_buffer_info;
@@ -220,7 +220,7 @@ error:
vlc_vaapi_ReleaseBufferHandle(o, priv->vadpy, va_image.buf);
for (unsigned i = 0; i < 3 && egl_images[i] != NULL; ++i)
- vaegl_image_destroy(tc, egl_images[i]);
+ vaegl_image_destroy(interop, egl_images[i]);
vlc_vaapi_DestroyImage(o, priv->vadpy, va_image.image_id);
}
@@ -228,14 +228,14 @@ error:
}
static picture_pool_t *
-tc_vaegl_get_pool(const opengl_tex_converter_t *tc, unsigned requested_count)
+tc_vaegl_get_pool(const struct vlc_gl_interop *interop, unsigned requested_count)
{
- vlc_object_t *o = VLC_OBJECT(tc->gl);
- struct priv *priv = tc->priv;
+ vlc_object_t *o = VLC_OBJECT(interop->gl);
+ struct priv *priv = interop->priv;
picture_pool_t *pool =
- vlc_vaapi_PoolNew(VLC_OBJECT(tc->gl), tc->vctx, priv->vadpy,
- requested_count, &priv->va_surface_ids, &tc->fmt);
+ vlc_vaapi_PoolNew(o, interop->vctx, priv->vadpy,
+ requested_count, &priv->va_surface_ids, &interop->fmt);
if (!pool)
return NULL;
@@ -258,17 +258,17 @@ tc_vaegl_get_pool(const opengl_tex_converter_t *tc, unsigned requested_count)
for (unsigned i = 0; i < va_image.num_planes; ++i)
{
- EGLint w = (va_image.width * tc->texs[i].w.num) / tc->texs[i].w.den;
- EGLint h = (va_image.height * tc->texs[i].h.num) / tc->texs[i].h.den;
+ EGLint w = (va_image.width * interop->texs[i].w.num) / interop->texs[i].w.den;
+ EGLint h = (va_image.height * interop->texs[i].h.num) / interop->texs[i].h.den;
EGLImageKHR egl_image =
- vaegl_image_create(tc, w, h, priv->drm_fourccs[i], va_buffer_info.handle,
+ vaegl_image_create(interop, w, h, priv->drm_fourccs[i], va_buffer_info.handle,
va_image.offsets[i], va_image.pitches[i]);
if (egl_image == NULL)
{
msg_Warn(o, "Can't create Image KHR: kernel too old ?");
goto error;
}
- vaegl_image_destroy(tc, egl_image);
+ vaegl_image_destroy(interop, egl_image);
}
success = true;
@@ -291,12 +291,12 @@ static void
Close(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *)obj;
- struct priv *priv = tc->priv;
+ struct priv *priv = tc->interop.priv;
if (priv->last.pic != NULL)
- vaegl_release_last_pic(tc, priv);
+ vaegl_release_last_pic(&tc->interop, priv);
- free(tc->priv);
+ free(priv);
}
static int strcasecmp_void(const void *a, const void *b)
@@ -334,14 +334,14 @@ tc_va_check_interop_blacklist(opengl_tex_converter_t *tc, VADisplay *vadpy)
}
static int
-tc_va_check_derive_image(opengl_tex_converter_t *tc)
+tc_va_check_derive_image(const struct vlc_gl_interop *interop)
{
- vlc_object_t *o = VLC_OBJECT(tc->gl);
- struct priv *priv = tc->priv;
+ vlc_object_t *o = VLC_OBJECT(interop->gl);
+ struct priv *priv = interop->priv;
VASurfaceID *va_surface_ids;
- picture_pool_t *pool = vlc_vaapi_PoolNew(o, tc->vctx, priv->vadpy, 1,
- &va_surface_ids, &tc->fmt);
+ picture_pool_t *pool = vlc_vaapi_PoolNew(o, interop->vctx, priv->vadpy, 1,
+ &va_surface_ids, &interop->fmt);
if (!pool)
return VLC_EGENERIC;
@@ -358,12 +358,13 @@ static int
Open(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *) obj;
+ struct vlc_gl_interop *interop = &tc->interop;
- if (tc->vctx == NULL)
+ if (interop->vctx == NULL)
return VLC_EGENERIC;
- vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(tc->vctx);
+ vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(interop->vctx);
if (dec_device->type != VLC_DECODER_DEVICE_VAAPI
- || !vlc_vaapi_IsChromaOpaque(tc->fmt.i_chroma)
+ || !vlc_vaapi_IsChromaOpaque(interop->fmt.i_chroma)
|| tc->gl->ext != VLC_GL_EXT_EGL
|| tc->gl->egl.createImageKHR == NULL
|| tc->gl->egl.destroyImageKHR == NULL)
@@ -372,7 +373,7 @@ Open(vlc_object_t *obj)
return VLC_EGENERIC;
}
- if (!vlc_gl_StrHasToken(tc->glexts, "GL_OES_EGL_image"))
+ if (!vlc_gl_StrHasToken(interop->glexts, "GL_OES_EGL_image"))
{
vlc_decoder_device_Release(dec_device);
return VLC_EGENERIC;
@@ -385,14 +386,14 @@ Open(vlc_object_t *obj)
return VLC_EGENERIC;
}
- struct priv *priv = tc->priv = calloc(1, sizeof(struct priv));
- if (unlikely(tc->priv == NULL))
+ struct priv *priv = interop->priv = calloc(1, sizeof(struct priv));
+ if (unlikely(priv == NULL))
goto error;
priv->fourcc = 0;
int va_fourcc;
int vlc_sw_chroma;
- switch (tc->fmt.i_chroma)
+ switch (interop->fmt.i_chroma)
{
case VLC_CODEC_VAAPI_420:
va_fourcc = VA_FOURCC_NV12;
@@ -420,16 +421,19 @@ Open(vlc_object_t *obj)
if (tc_va_check_interop_blacklist(tc, priv->vadpy))
goto error;
- if (tc_va_check_derive_image(tc))
+ if (tc_va_check_derive_image(interop))
goto error;
tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, vlc_sw_chroma,
- tc->fmt.space);
+ interop->fmt.space);
if (tc->fshader == 0)
goto error;
- tc->pf_update = tc_vaegl_update;
- tc->pf_get_pool = tc_vaegl_get_pool;
+ static const struct vlc_gl_interop_ops ops = {
+ .update_textures = tc_vaegl_update,
+ .get_pool = tc_vaegl_get_pool,
+ };
+ interop->ops = &ops;
vlc_decoder_device_Release(dec_device);
diff --git a/modules/video_output/opengl/converter_vdpau.c b/modules/video_output/opengl/converter_vdpau.c
index e5b3794e84..78441cb469 100644
--- a/modules/video_output/opengl/converter_vdpau.c
+++ b/modules/video_output/opengl/converter_vdpau.c
@@ -40,10 +40,10 @@
#define INTEROP_CALL(fct, ...) \
_##fct(__VA_ARGS__); \
{ \
- GLenum ret = tc->vt->GetError(); \
+ GLenum ret = interop->vt->GetError(); \
if (ret != GL_NO_ERROR) \
{ \
- msg_Err(tc->gl, #fct " failed: 0x%x", ret); \
+ msg_Err(interop->gl, #fct " failed: 0x%x", ret); \
return VLC_EGENERIC; \
} \
}
@@ -63,18 +63,18 @@ typedef struct {
} converter_sys_t;
static picture_pool_t *
-tc_vdpau_gl_get_pool(opengl_tex_converter_t const *tc,
+tc_vdpau_gl_get_pool(const struct vlc_gl_interop *interop,
unsigned int requested_count)
{
- converter_sys_t *sys = tc->priv;
+ converter_sys_t *sys = interop->priv;
vlc_decoder_device *dec_device = sys->dec_device;
return vlc_vdp_output_pool_create(GetVDPAUOpaqueDevice(dec_device),
VDP_RGBA_FORMAT_B8G8R8A8,
- &tc->fmt, requested_count);
+ &interop->fmt, requested_count);
}
static int
-tc_vdpau_gl_update(opengl_tex_converter_t const *tc, GLuint textures[],
+tc_vdpau_gl_update(const struct vlc_gl_interop *interop, GLuint textures[],
GLsizei const tex_widths[], GLsizei const tex_heights[],
picture_t *pic, size_t const plane_offsets[])
{
@@ -105,7 +105,7 @@ tc_vdpau_gl_update(opengl_tex_converter_t const *tc, GLuint textures[],
gl_nv_surface =
INTEROP_CALL(glVDPAURegisterOutputSurfaceNV,
(void *)(size_t)p_sys->surface,
- GL_TEXTURE_2D, tc->tex_count, textures);
+ GL_TEXTURE_2D, interop->tex_count, textures);
INTEROP_CALL(glVDPAUSurfaceAccessNV, gl_nv_surface, GL_READ_ONLY);
INTEROP_CALL(glVDPAUMapSurfacesNV, 1, &gl_nv_surface);
@@ -118,7 +118,7 @@ Close(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *)obj;
_glVDPAUFiniNV(); assert(tc->vt->GetError() == GL_NO_ERROR);
- converter_sys_t *sys = tc->priv;
+ converter_sys_t *sys = tc->interop.priv;
vlc_decoder_device *dec_device = sys->dec_device;
vlc_decoder_device_Release(dec_device);
}
@@ -127,14 +127,16 @@ static int
Open(vlc_object_t *obj)
{
opengl_tex_converter_t *tc = (void *) obj;
- if (tc->vctx == NULL)
+ struct vlc_gl_interop *interop = &tc->interop;
+
+ if (interop->vctx == NULL)
return VLC_EGENERIC;
- vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(tc->vctx);
+ vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(interop->vctx);
if (GetVDPAUOpaqueDevice(dec_device) == NULL
- || (tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_420
- && tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_422
- && tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_444)
- || !vlc_gl_StrHasToken(tc->glexts, "GL_NV_vdpau_interop")
+ || (interop->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_420
+ && interop->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_422
+ && interop->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_444)
+ || !vlc_gl_StrHasToken(interop->glexts, "GL_NV_vdpau_interop")
|| tc->gl->surface->type != VOUT_WINDOW_TYPE_XID)
{
vlc_decoder_device_Release(dec_device);
@@ -149,7 +151,7 @@ Open(vlc_object_t *obj)
}
sys->dec_device = dec_device;
- tc->fmt.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
+ interop->fmt.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
VdpDevice device;
vdpau_decoder_device_t *vdpau_dev = GetVDPAUOpaqueDevice(dec_device);
@@ -194,9 +196,12 @@ Open(vlc_object_t *obj)
return VLC_EGENERIC;
}
- tc->pf_get_pool = tc_vdpau_gl_get_pool;
- tc->pf_update = tc_vdpau_gl_update;
- tc->priv = sys;
+ static const struct vlc_gl_interop_ops ops = {
+ .get_pool = tc_vdpau_gl_get_pool,
+ .update_textures = tc_vdpau_gl_update,
+ };
+ interop->ops = &ops;
+ interop->priv = sys;
return VLC_SUCCESS;
}
diff --git a/modules/video_output/opengl/fragment_shaders.c b/modules/video_output/opengl/fragment_shaders.c
index bd9978fda4..340672620b 100644
--- a/modules/video_output/opengl/fragment_shaders.c
+++ b/modules/video_output/opengl/fragment_shaders.c
@@ -33,6 +33,7 @@
#include <vlc_common.h>
#include <vlc_memstream.h>
+#include "interop.h"
#include "internal.h"
#include "vout_helper.h"
@@ -102,10 +103,12 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
video_color_space_t yuv_space,
bool *swap_uv, const char *swizzle_per_tex[])
{
+ struct vlc_gl_interop *interop = &tc->interop;
+
GLint oneplane_texfmt, oneplane16_texfmt,
twoplanes_texfmt, twoplanes16_texfmt;
- if (vlc_gl_StrHasToken(tc->glexts, "GL_ARB_texture_rg"))
+ if (vlc_gl_StrHasToken(interop->glexts, "GL_ARB_texture_rg"))
{
oneplane_texfmt = GL_RED;
oneplane16_texfmt = GL_R16;
@@ -153,10 +156,10 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
assert(internal != 0 && type != 0);
- tc->tex_count = 3;
- for (unsigned i = 0; i < tc->tex_count; ++i )
+ interop->tex_count = 3;
+ for (unsigned i = 0; i < interop->tex_count; ++i )
{
- tc->texs[i] = (struct opengl_tex_cfg) {
+ interop->texs[i] = (struct vlc_gl_tex_cfg) {
{ desc->p[i].w.num, desc->p[i].w.den },
{ desc->p[i].h.num, desc->p[i].h.den },
internal, oneplane_texfmt, type
@@ -168,15 +171,15 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
}
else if (desc->plane_count == 2)
{
- tc->tex_count = 2;
+ interop->tex_count = 2;
if (desc->pixel_size == 1)
{
- tc->texs[0] = (struct opengl_tex_cfg) {
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ 1, 1 }, { 1, 1 }, oneplane_texfmt, oneplane_texfmt,
GL_UNSIGNED_BYTE
};
- tc->texs[1] = (struct opengl_tex_cfg) {
+ interop->texs[1] = (struct vlc_gl_tex_cfg) {
{ 1, 2 }, { 1, 2 }, twoplanes_texfmt, twoplanes_texfmt,
GL_UNSIGNED_BYTE
};
@@ -187,11 +190,11 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
|| GetTexFormatSize(tc, tex_target, twoplanes_texfmt,
twoplanes16_texfmt, GL_UNSIGNED_SHORT) != 16)
return VLC_EGENERIC;
- tc->texs[0] = (struct opengl_tex_cfg) {
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ 1, 1 }, { 1, 1 }, oneplane16_texfmt, oneplane_texfmt,
GL_UNSIGNED_SHORT
};
- tc->texs[1] = (struct opengl_tex_cfg) {
+ interop->texs[1] = (struct vlc_gl_tex_cfg) {
{ 1, 2 }, { 1, 2 }, twoplanes16_texfmt, twoplanes_texfmt,
GL_UNSIGNED_SHORT
};
@@ -213,8 +216,8 @@ tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
else if (desc->plane_count == 1)
{
/* Y1 U Y2 V fits in R G B A */
- tc->tex_count = 1;
- tc->texs[0] = (struct opengl_tex_cfg) {
+ interop->tex_count = 1;
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ 1, 2 }, { 1, 1 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE
};
@@ -302,12 +305,13 @@ tc_rgb_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
vlc_fourcc_t chroma)
{
(void) tex_target;
+ struct vlc_gl_interop *interop = &tc->interop;
switch (chroma)
{
case VLC_CODEC_RGB32:
case VLC_CODEC_RGBA:
- tc->texs[0] = (struct opengl_tex_cfg) {
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ 1, 1 }, { 1, 1 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE
};
break;
@@ -315,7 +319,7 @@ tc_rgb_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
if (GetTexFormatSize(tc, tex_target, GL_BGRA, GL_RGBA,
GL_UNSIGNED_BYTE) != 32)
return VLC_EGENERIC;
- tc->texs[0] = (struct opengl_tex_cfg) {
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ 1, 1 }, { 1, 1 }, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE
};
break;
@@ -323,13 +327,15 @@ tc_rgb_base_init(opengl_tex_converter_t *tc, GLenum tex_target,
default:
return VLC_EGENERIC;
}
- tc->tex_count = 1;
+ interop->tex_count = 1;
return VLC_SUCCESS;
}
static int
tc_base_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
{
+ struct vlc_gl_interop *interop = &tc->interop;
+
if (tc->yuv_color)
{
tc->uloc.Coefficients = tc->vt->GetUniformLocation(program,
@@ -338,14 +344,14 @@ tc_base_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
return VLC_EGENERIC;
}
- for (unsigned int i = 0; i < tc->tex_count; ++i)
+ for (unsigned int i = 0; i < interop->tex_count; ++i)
{
char name[sizeof("TextureX")];
snprintf(name, sizeof(name), "Texture%1u", i);
tc->uloc.Texture[i] = tc->vt->GetUniformLocation(program, name);
if (tc->uloc.Texture[i] == -1)
return VLC_EGENERIC;
- if (tc->tex_target == GL_TEXTURE_RECTANGLE)
+ if (interop->tex_target == GL_TEXTURE_RECTANGLE)
{
snprintf(name, sizeof(name), "TexSize%1u", i);
tc->uloc.TexSize[i] = tc->vt->GetUniformLocation(program, name);
@@ -375,18 +381,19 @@ tc_base_prepare_shader(const opengl_tex_converter_t *tc,
float alpha)
{
(void) tex_width; (void) tex_height;
+ const struct vlc_gl_interop *interop = &tc->interop;
if (tc->yuv_color)
tc->vt->Uniform4fv(tc->uloc.Coefficients, 4, tc->yuv_coefficients);
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
tc->vt->Uniform1i(tc->uloc.Texture[i], i);
tc->vt->Uniform4f(tc->uloc.FillColor, 1.0f, 1.0f, 1.0f, alpha);
- if (tc->tex_target == GL_TEXTURE_RECTANGLE)
+ if (interop->tex_target == GL_TEXTURE_RECTANGLE)
{
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
tc->vt->Uniform2f(tc->uloc.TexSize[i], tex_width[i],
tex_height[i]);
}
@@ -444,9 +451,11 @@ tc_xyz12_prepare_shader(const opengl_tex_converter_t *tc,
static GLuint
xyz12_shader_init(opengl_tex_converter_t *tc)
{
- tc->tex_count = 1;
- tc->tex_target = GL_TEXTURE_2D;
- tc->texs[0] = (struct opengl_tex_cfg) {
+ struct vlc_gl_interop *interop = &tc->interop;
+
+ interop->tex_count = 1;
+ interop->tex_target = GL_TEXTURE_2D;
+ interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ 1, 1 }, { 1, 1 }, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT
};
@@ -500,6 +509,8 @@ GLuint
opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
vlc_fourcc_t chroma, video_color_space_t yuv_space)
{
+ struct vlc_gl_interop *interop = &tc->interop;
+
const char *swizzle_per_tex[PICTURE_PLANE_MAX] = { NULL, };
const bool is_yuv = vlc_fourcc_IsYUV(chroma);
bool yuv_swap_uv = false;
@@ -557,7 +568,7 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
ADDF("%s", tc->glsl_precision_header);
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
ADDF("uniform %s Texture%u;\n"
"varying vec2 TexCoord%u;\n", sampler, i, i);
@@ -582,7 +593,7 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
dst_space.transfer = var_InheritInteger(tc->gl, "target-trc");
pl_shader_color_map(sh, &color_params,
- vlc_placebo_ColorSpace(&tc->fmt),
+ vlc_placebo_ColorSpace(&interop->fmt),
dst_space, NULL, false);
struct pl_shader_obj *dither_state = NULL;
@@ -632,8 +643,8 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
ADD(res->glsl);
}
#else
- if (tc->fmt.transfer == TRANSFER_FUNC_SMPTE_ST2084 ||
- tc->fmt.primaries == COLOR_PRIMARIES_BT2020)
+ if (interop->fmt.transfer == TRANSFER_FUNC_SMPTE_ST2084 ||
+ interop->fmt.primaries == COLOR_PRIMARIES_BT2020)
{
// no warning for HLG because it's more or less backwards-compatible
msg_Warn(tc->gl, "VLC needs to be built with support for libplacebo "
@@ -643,7 +654,7 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
if (tex_target == GL_TEXTURE_RECTANGLE)
{
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
ADDF("uniform vec2 TexSize%u;\n", i);
}
@@ -656,13 +667,13 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
if (tex_target == GL_TEXTURE_RECTANGLE)
{
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
ADDF(" vec2 TexCoordRect%u = vec2(TexCoord%u.x * TexSize%u.x, "
"TexCoord%u.y * TexSize%u.y);\n", i, i, i, i, i);
}
unsigned color_idx = 0;
- for (unsigned i = 0; i < tc->tex_count; ++i)
+ for (unsigned i = 0; i < interop->tex_count; ++i)
{
const char *swizzle = swizzle_per_tex[i];
if (swizzle)
@@ -743,7 +754,7 @@ opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target,
(const char *)&chroma, yuv_space, ms.ptr);
free(ms.ptr);
- tc->tex_target = tex_target;
+ interop->tex_target = tex_target;
tc->pf_fetch_locations = tc_base_fetch_locations;
tc->pf_prepare_shader = tc_base_prepare_shader;
diff --git a/modules/video_output/opengl/interop.h b/modules/video_output/opengl/interop.h
new file mode 100644
index 0000000000..b13b94a698
--- /dev/null
+++ b/modules/video_output/opengl/interop.h
@@ -0,0 +1,150 @@
+/*****************************************************************************
+ * interop.h
+ *****************************************************************************
+ * Copyright (C) 2019 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_GL_INTEROP_H
+#define VLC_GL_INTEROP_H
+
+#include <vlc_common.h>
+#include <vlc_opengl.h>
+#include <vlc_picture.h>
+#include <vlc_picture_pool.h>
+
+#include "gl_common.h"
+
+struct vlc_gl_interop;
+
+struct vlc_gl_interop_ops {
+ /**
+ * Callback to allocate data for bound textures
+ *
+ * This function pointer can be NULL. Software converters should call
+ * glTexImage2D() to allocate textures data (it will be deallocated by the
+ * caller when calling glDeleteTextures()). Won't be called if
+ * handle_texs_gen is true.
+ *
+ * \param interop the OpenGL interop
+ * \param textures array of textures to bind (one per plane)
+ * \param tex_width array of tex width (one per plane)
+ * \param tex_height array of tex height (one per plane)
+ * \return VLC_SUCCESS or a VLC error
+ */
+ int
+ (*allocate_textures)(const struct vlc_gl_interop *interoporter,
+ GLuint textures[], const GLsizei tex_width[],
+ const GLsizei tex_height[]);
+
+ /**
+ * Callback to update a picture
+ *
+ * This function pointer cannot be NULL. The implementation should upload
+ * every planes of the picture.
+ *
+ * \param interop the OpenGL interop
+ * \param textures array of textures to bind (one per plane)
+ * \param tex_width array of tex width (one per plane)
+ * \param tex_height array of tex height (one per plane)
+ * \param pic picture to update
+ * \param plane_offset offsets of each picture planes to read data from
+ * (one per plane, can be NULL)
+ * \return VLC_SUCCESS or a VLC error
+ */
+ int
+ (*update_textures)(const struct vlc_gl_interop *interoporter,
+ GLuint textures[], const GLsizei tex_width[],
+ const GLsizei tex_height[], picture_t *pic,
+ const size_t plane_offsets[]);
+
+ /**
+ * Callback to allocate a picture pool
+ *
+ * This function pointer *can* be NULL. If NULL, A generic pool with
+ * pictures allocated from the video_format_t will be used.
+ *
+ * \param interop the OpenGL interop
+ * \param requested_count number of pictures to allocate
+ * \return the picture pool or NULL in case of error
+ */
+ picture_pool_t *
+ (*get_pool)(const struct vlc_gl_interop *interoporter,
+ unsigned requested_count);
+
+ /**
+ * Callback to retrieve the transform matrix to apply to texture coordinates
+ *
+ * This function pointer can be NULL. If it is set, it may return NULL.
+ *
+ * Otherwise, it must return a 4x4 matrix, as an array of 16 floats in
+ * column-major order.
+ *
+ * This transform matrix maps 2D homogeneous texture coordinates of the
+ * form (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the
+ * texture coordinate that should be used to sample that location from the
+ * texture.
+ *
+ * The returned pointer is owned by the converter module, and must not be
+ * freed before the module is closed.
+ *
+ * \param interop the OpenGL interop
+ * \return a 4x4 transformatoin matrix (possibly NULL)
+ */
+ const float *
+ (*get_transform_matrix)(const struct vlc_gl_interop *interoporter);
+};
+
+struct vlc_gl_interop {
+ vlc_gl_t *gl;
+ const opengl_vtable_t *vt;
+ GLenum tex_target;
+
+ /* True if the current API is OpenGL ES, set by the caller */
+ bool is_gles;
+
+ /* Available gl extensions (from GL_EXTENSIONS) */
+ const char *glexts;
+
+ /* Can only be changed from the module open function */
+ video_format_t fmt;
+
+ /* Pointer to decoder video context, set by the caller (can be NULL) */
+ vlc_video_context *vctx;
+
+ /* Set to true if textures are generated from pf_update() */
+ bool handle_texs_gen;
+
+ /* Initialized by the interop */
+ struct vlc_gl_tex_cfg {
+ /*
+ * Texture scale factor, cannot be 0.
+ * In 4:2:0, 1/1 for the Y texture and 1/2 for the UV texture(s)
+ */
+ vlc_rational_t w;
+ vlc_rational_t h;
+
+ GLint internal;
+ GLenum format;
+ GLenum type;
+ } texs[PICTURE_PLANE_MAX];
+ unsigned tex_count;
+
+ void *priv;
+ const struct vlc_gl_interop_ops *ops;
+};
+
+#endif
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index d5d155006d..a14b0451b3 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -346,7 +346,7 @@ static GLuint BuildVertexShader(const opengl_tex_converter_t *tc,
tc->vt->ShaderSource(shader, 1, (const char **) &code, NULL);
if (tc->b_dump_shaders)
msg_Dbg(tc->gl, "\n=== Vertex shader for fourcc: %4.4s ===\n%s\n",
- (const char *)&tc->fmt.i_chroma, code);
+ (const char *)&tc->interop.fmt.i_chroma, code);
tc->vt->CompileShader(shader);
free(code);
return shader;
@@ -357,31 +357,33 @@ GenTextures(const opengl_tex_converter_t *tc,
const GLsizei *tex_width, const GLsizei *tex_height,
GLuint *textures)
{
- tc->vt->GenTextures(tc->tex_count, textures);
+ const struct vlc_gl_interop *interop = &tc->interop;
- for (unsigned i = 0; i < tc->tex_count; i++)
+ tc->vt->GenTextures(interop->tex_count, textures);
+
+ for (unsigned i = 0; i < interop->tex_count; i++)
{
- tc->vt->BindTexture(tc->tex_target, textures[i]);
+ tc->vt->BindTexture(interop->tex_target, textures[i]);
#if !defined(USE_OPENGL_ES2)
/* Set the texture parameters */
- tc->vt->TexParameterf(tc->tex_target, GL_TEXTURE_PRIORITY, 1.0);
+ tc->vt->TexParameterf(interop->tex_target, GL_TEXTURE_PRIORITY, 1.0);
tc->vt->TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
#endif
- tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ tc->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ tc->vt->TexParameteri(interop->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ tc->vt->TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ tc->vt->TexParameteri(interop->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
- if (tc->pf_allocate_textures != NULL)
+ if (interop->ops->allocate_textures != NULL)
{
- int ret = tc->pf_allocate_textures(tc, textures, tex_width, tex_height);
+ int ret = interop->ops->allocate_textures(&tc->interop, textures, tex_width, tex_height);
if (ret != VLC_SUCCESS)
{
- tc->vt->DeleteTextures(tc->tex_count, textures);
- memset(textures, 0, tc->tex_count * sizeof(GLuint));
+ tc->vt->DeleteTextures(interop->tex_count, textures);
+ memset(textures, 0, interop->tex_count * sizeof(GLuint));
return ret;
}
}
@@ -391,16 +393,18 @@ GenTextures(const opengl_tex_converter_t *tc,
static void
DelTextures(const opengl_tex_converter_t *tc, GLuint *textures)
{
- tc->vt->DeleteTextures(tc->tex_count, textures);
- memset(textures, 0, tc->tex_count * sizeof(GLuint));
+ const struct vlc_gl_interop *interop = &tc->interop;
+ tc->vt->DeleteTextures(interop->tex_count, textures);
+ memset(textures, 0, interop->tex_count * sizeof(GLuint));
}
static int
opengl_link_program(struct prgm *prgm)
{
opengl_tex_converter_t *tc = prgm->tc;
+ struct vlc_gl_interop *interop = &tc->interop;
- GLuint vertex_shader = BuildVertexShader(tc, tc->tex_count);
+ GLuint vertex_shader = BuildVertexShader(tc, interop->tex_count);
GLuint shaders[] = { tc->fshader, vertex_shader };
/* Check shaders messages */
@@ -474,11 +478,11 @@ opengl_link_program(struct prgm *prgm)
GET_ALOC(VertexPosition, "VertexPosition");
GET_ALOC(MultiTexCoord[0], "MultiTexCoord0");
/* MultiTexCoord 1 and 2 can be optimized out if not used */
- if (prgm->tc->tex_count > 1)
+ if (interop->tex_count > 1)
GET_ALOC(MultiTexCoord[1], "MultiTexCoord1");
else
prgm->aloc.MultiTexCoord[1] = -1;
- if (prgm->tc->tex_count > 2)
+ if (interop->tex_count > 2)
GET_ALOC(MultiTexCoord[2], "MultiTexCoord2");
else
prgm->aloc.MultiTexCoord[2] = -1;
@@ -505,9 +509,10 @@ static void
opengl_deinit_program(vout_display_opengl_t *vgl, struct prgm *prgm)
{
opengl_tex_converter_t *tc = prgm->tc;
+ struct vlc_gl_interop *interop = &tc->interop;
if (tc->p_module != NULL)
module_unneed(tc, tc->p_module);
- else if (tc->priv != NULL)
+ else if (interop->priv != NULL)
opengl_tex_converter_generic_deinit(tc);
if (prgm->id != 0)
vgl->vt.DeleteProgram(prgm->id);
@@ -532,22 +537,28 @@ opengl_init_program(vout_display_opengl_t *vgl, vlc_video_context *context,
if (tc == NULL)
return VLC_ENOMEM;
+ struct vlc_gl_interop *interop = &tc->interop;
+
tc->gl = vgl->gl;
tc->vt = &vgl->vt;
tc->b_dump_shaders = b_dump_shaders;
tc->pf_fragment_shader_init = opengl_fragment_shader_init_impl;
- tc->pf_get_transform_matrix = NULL;
- tc->glexts = glexts;
#if defined(USE_OPENGL_ES2)
- tc->is_gles = true;
+ interop->is_gles = true;
tc->glsl_version = 100;
tc->glsl_precision_header = "precision highp float;\n";
#else
- tc->is_gles = false;
+ interop->is_gles = false;
tc->glsl_version = 120;
tc->glsl_precision_header = "";
#endif
- tc->fmt = *fmt;
+
+ interop->ops = NULL;
+ interop->glexts = glexts;
+ interop->fmt = *fmt;
+
+ interop->gl = tc->gl;
+ interop->vt = tc->vt;
#ifdef HAVE_LIBPLACEBO
// Create the main libplacebo context
@@ -569,13 +580,13 @@ opengl_init_program(vout_display_opengl_t *vgl, vlc_video_context *context,
int ret;
if (subpics)
{
- tc->fmt.i_chroma = VLC_CODEC_RGB32;
+ interop->fmt.i_chroma = VLC_CODEC_RGB32;
/* Normal orientation and no projection for subtitles */
- tc->fmt.orientation = ORIENT_NORMAL;
- tc->fmt.projection_mode = PROJECTION_MODE_RECTANGULAR;
- tc->fmt.primaries = COLOR_PRIMARIES_UNDEF;
- tc->fmt.transfer = TRANSFER_FUNC_UNDEF;
- tc->fmt.space = COLOR_SPACE_UNDEF;
+ interop->fmt.orientation = ORIENT_NORMAL;
+ interop->fmt.projection_mode = PROJECTION_MODE_RECTANGULAR;
+ interop->fmt.primaries = COLOR_PRIMARIES_UNDEF;
+ interop->fmt.transfer = TRANSFER_FUNC_UNDEF;
+ interop->fmt.space = COLOR_SPACE_UNDEF;
ret = opengl_tex_converter_generic_init(tc, false);
}
@@ -592,7 +603,7 @@ opengl_init_program(vout_display_opengl_t *vgl, vlc_video_context *context,
if (desc->plane_count == 0)
{
/* Opaque chroma: load a module to handle it */
- tc->vctx = context;
+ interop->vctx = context;
tc->p_module = module_need_var(tc, "glconv", "glconv");
}
@@ -612,8 +623,11 @@ opengl_init_program(vout_display_opengl_t *vgl, vlc_video_context *context,
return VLC_EGENERIC;
}
- assert(tc->fshader != 0 && tc->tex_target != 0 && tc->tex_count > 0 &&
- tc->pf_update != NULL && tc->pf_fetch_locations != NULL &&
+ assert(tc->fshader != 0 &&
+ interop->tex_target != 0 &&
+ interop->tex_count > 0 &&
+ interop->ops->update_textures != NULL &&
+ tc->pf_fetch_locations != NULL &&
tc->pf_prepare_shader != NULL);
prgm->tc = tc;
@@ -625,9 +639,9 @@ opengl_init_program(vout_display_opengl_t *vgl, vlc_video_context *context,
return VLC_EGENERIC;
}
- getOrientationTransformMatrix(tc->fmt.orientation,
+ getOrientationTransformMatrix(interop->fmt.orientation,
prgm->var.OrientationMatrix);
- getViewpointMatrixes(vgl, tc->fmt.projection_mode, prgm);
+ getViewpointMatrixes(vgl, interop->fmt.projection_mode, prgm);
return VLC_SUCCESS;
}
@@ -838,18 +852,19 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
return NULL;
}
GL_ASSERT_NOERROR();
+
+ const struct vlc_gl_interop *interop = &vgl->prgm->tc->interop;
/* Update the fmt to main program one */
- vgl->fmt = vgl->prgm->tc->fmt;
+ vgl->fmt = interop->fmt;
/* The orientation is handled by the orientation matrix */
vgl->fmt.orientation = fmt->orientation;
/* Texture size */
- const opengl_tex_converter_t *tc = vgl->prgm->tc;
- for (unsigned j = 0; j < tc->tex_count; j++) {
- const GLsizei w = vgl->fmt.i_visible_width * tc->texs[j].w.num
- / tc->texs[j].w.den;
- const GLsizei h = vgl->fmt.i_visible_height * tc->texs[j].h.num
- / tc->texs[j].h.den;
+ for (unsigned j = 0; j < interop->tex_count; j++) {
+ const GLsizei w = vgl->fmt.i_visible_width * interop->texs[j].w.num
+ / interop->texs[j].w.den;
+ const GLsizei h = vgl->fmt.i_visible_height * interop->texs[j].h.num
+ / interop->texs[j].h.den;
if (vgl->supports_npot) {
vgl->tex_width[j] = w;
vgl->tex_height[j] = h;
@@ -860,9 +875,9 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
}
/* Allocates our textures */
- assert(!vgl->sub_prgm->tc->handle_texs_gen);
+ assert(!vgl->sub_prgm->tc->interop.handle_texs_gen);
- if (!vgl->prgm->tc->handle_texs_gen)
+ if (!interop->handle_texs_gen)
{
ret = GenTextures(vgl->prgm->tc, vgl->tex_width, vgl->tex_height,
vgl->texture);
@@ -883,7 +898,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
vgl->vt.GenBuffers(1, &vgl->vertex_buffer_object);
vgl->vt.GenBuffers(1, &vgl->index_buffer_object);
- vgl->vt.GenBuffers(vgl->prgm->tc->tex_count, vgl->texture_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;
@@ -924,8 +939,9 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
vgl->vt.Finish();
vgl->vt.Flush();
- const size_t main_tex_count = vgl->prgm->tc->tex_count;
- const bool main_del_texs = !vgl->prgm->tc->handle_texs_gen;
+ 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;
if (vgl->pool)
picture_pool_Release(vgl->pool);
@@ -1031,7 +1047,8 @@ void vout_display_opengl_Viewport(vout_display_opengl_t *vgl, int x, int y,
bool vout_display_opengl_HasPool(const vout_display_opengl_t *vgl)
{
opengl_tex_converter_t *tc = vgl->prgm->tc;
- return tc->pf_get_pool != NULL;
+ struct vlc_gl_interop *interop = &tc->interop;
+ return interop->ops->get_pool != NULL;
}
picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
@@ -1042,10 +1059,11 @@ picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned
return vgl->pool;
opengl_tex_converter_t *tc = vgl->prgm->tc;
+ const struct vlc_gl_interop *interop = &tc->interop;
requested_count = __MIN(VLCGL_PICTURE_MAX, requested_count);
/* Allocate with tex converter pool callback if it exists */
- assert(tc->pf_get_pool != NULL);
- vgl->pool = tc->pf_get_pool(tc, requested_count);
+ assert(interop->ops->get_pool != NULL);
+ vgl->pool = interop->ops->get_pool(interop, requested_count);
if (!vgl->pool)
goto error;
return vgl->pool;
@@ -1061,10 +1079,11 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
GL_ASSERT_NOERROR();
opengl_tex_converter_t *tc = vgl->prgm->tc;
+ struct vlc_gl_interop *interop = &tc->interop;
/* Update the texture */
- int ret = tc->pf_update(tc, vgl->texture, vgl->tex_width, vgl->tex_height,
- picture, NULL);
+ int ret = interop->ops->update_textures(interop, vgl->texture, vgl->tex_width, vgl->tex_height,
+ picture, NULL);
if (ret != VLC_SUCCESS)
return ret;
@@ -1075,6 +1094,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
vgl->region = NULL;
tc = vgl->sub_prgm->tc;
+ interop = &tc->interop;
if (subpicture) {
int count = 0;
@@ -1132,8 +1152,9 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
/* 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;
- ret = tc->pf_update(tc, &glr->texture, &glr->width, &glr->height,
- r->p_picture, &pixels_offset);
+ ret = interop->ops->update_textures(interop, &glr->texture,
+ &glr->width, &glr->height,
+ r->p_picture, &pixels_offset);
}
}
for (int i = 0; i < last_count; i++) {
@@ -1420,6 +1441,8 @@ 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;
+
GLfloat *vertexCoord, *textureCoord;
GLushort *indices;
unsigned nbVertices, nbIndices;
@@ -1428,19 +1451,19 @@ static int SetupCoords(vout_display_opengl_t *vgl,
switch (vgl->fmt.projection_mode)
{
case PROJECTION_MODE_RECTANGULAR:
- i_ret = BuildRectangle(vgl->prgm->tc->tex_count,
+ i_ret = BuildRectangle(interop->tex_count,
&vertexCoord, &textureCoord, &nbVertices,
&indices, &nbIndices,
left, top, right, bottom);
break;
case PROJECTION_MODE_EQUIRECTANGULAR:
- i_ret = BuildSphere(vgl->prgm->tc->tex_count,
+ i_ret = BuildSphere(interop->tex_count,
&vertexCoord, &textureCoord, &nbVertices,
&indices, &nbIndices,
left, top, right, bottom);
break;
case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:
- i_ret = BuildCube(vgl->prgm->tc->tex_count,
+ i_ret = BuildCube(interop->tex_count,
(float)vgl->fmt.i_cubemap_padding / vgl->fmt.i_width,
(float)vgl->fmt.i_cubemap_padding / vgl->fmt.i_height,
&vertexCoord, &textureCoord, &nbVertices,
@@ -1455,7 +1478,7 @@ static int SetupCoords(vout_display_opengl_t *vgl,
if (i_ret != VLC_SUCCESS)
return i_ret;
- for (unsigned j = 0; j < vgl->prgm->tc->tex_count; j++)
+ for (unsigned j = 0; j < interop->tex_count; j++)
{
vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->texture_buffer_object[j]);
vgl->vt.BufferData(GL_ARRAY_BUFFER, nbVertices * 2 * sizeof(GLfloat),
@@ -1482,12 +1505,13 @@ static int SetupCoords(vout_display_opengl_t *vgl,
static void DrawWithShaders(vout_display_opengl_t *vgl, struct prgm *prgm)
{
opengl_tex_converter_t *tc = prgm->tc;
+ const struct vlc_gl_interop *interop = &tc->interop;
tc->pf_prepare_shader(tc, vgl->tex_width, vgl->tex_height, 1.0f);
- for (unsigned j = 0; j < vgl->prgm->tc->tex_count; j++) {
+ for (unsigned j = 0; j < interop->tex_count; j++) {
assert(vgl->texture[j] != 0);
vgl->vt.ActiveTexture(GL_TEXTURE0+j);
- vgl->vt.BindTexture(tc->tex_target, vgl->texture[j]);
+ vgl->vt.BindTexture(interop->tex_target, vgl->texture[j]);
vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->texture_buffer_object[j]);
@@ -1502,8 +1526,9 @@ static void DrawWithShaders(vout_display_opengl_t *vgl, struct prgm *prgm)
vgl->vt.EnableVertexAttribArray(prgm->aloc.VertexPosition);
vgl->vt.VertexAttribPointer(prgm->aloc.VertexPosition, 3, GL_FLOAT, 0, 0, 0);
- const GLfloat *tm = tc->pf_get_transform_matrix
- ? tc->pf_get_transform_matrix(tc) : NULL;
+ const GLfloat *tm = NULL;
+ if (interop->ops && interop->ops->get_transform_matrix)
+ tm = interop->ops->get_transform_matrix(interop);
if (!tm)
tm = identity;
@@ -1544,6 +1569,8 @@ 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;
+
float stereoCoefs[2];
float stereoOffsets[2];
@@ -1553,7 +1580,7 @@ static void TextureCropForStereo(vout_display_opengl_t *vgl,
// Display only the left eye.
stereoCoefs[0] = 1; stereoCoefs[1] = 0.5;
stereoOffsets[0] = 0; stereoOffsets[1] = 0;
- GetTextureCropParamsForStereo(vgl->prgm->tc->tex_count,
+ GetTextureCropParamsForStereo(interop->tex_count,
stereoCoefs, stereoOffsets,
left, top, right, bottom);
break;
@@ -1561,7 +1588,7 @@ static void TextureCropForStereo(vout_display_opengl_t *vgl,
// Display only the left eye.
stereoCoefs[0] = 0.5; stereoCoefs[1] = 1;
stereoOffsets[0] = 0; stereoOffsets[1] = 0;
- GetTextureCropParamsForStereo(vgl->prgm->tc->tex_count,
+ GetTextureCropParamsForStereo(interop->tex_count,
stereoCoefs, stereoOffsets,
left, top, right, bottom);
break;
@@ -1592,11 +1619,12 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
float right[PICTURE_PLANE_MAX];
float bottom[PICTURE_PLANE_MAX];
const opengl_tex_converter_t *tc = vgl->prgm->tc;
- for (unsigned j = 0; j < tc->tex_count; j++)
+ const struct vlc_gl_interop *interop = &tc->interop;
+ for (unsigned j = 0; j < tc->interop.tex_count; j++)
{
- float scale_w = (float)tc->texs[j].w.num / tc->texs[j].w.den
+ float scale_w = (float)interop->texs[j].w.num / interop->texs[j].w.den
/ vgl->tex_width[j];
- float scale_h = (float)tc->texs[j].h.num / tc->texs[j].h.den
+ float scale_h = (float)interop->texs[j].h.num / interop->texs[j].h.den
/ vgl->tex_height[j];
/* Warning: if NPOT is not supported a larger texture is
@@ -1633,6 +1661,7 @@ int vout_display_opengl_Display(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);
@@ -1672,7 +1701,7 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
};
assert(glr->texture != 0);
- vgl->vt.BindTexture(tc->tex_target, glr->texture);
+ vgl->vt.BindTexture(interop->tex_target, glr->texture);
tc->pf_prepare_shader(tc, &glr->width, &glr->height, glr->alpha);
--
2.25.0.rc0
More information about the vlc-devel
mailing list