vlc | branch: master | Romain Vimont <[email protected]> | Wed Nov 27 16:27:51 2019 +0100| [32aeaaff919d4ae28ad661a1e30e5b6d166af816] | committer: Thomas Guillem
opengl: extract interop from converter Extract fields specific to texture interop into a separate structure. For now, it is still embedded in opengl_tex_converter_t. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=32aeaaff919d4ae28ad661a1e30e5b6d166af816 --- modules/hw/nvdec/nvdec_gl.c | 52 ++++---- modules/video_output/opengl/converter.h | 92 +------------- modules/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 | 76 ++++++------ modules/video_output/opengl/converter_vdpau.c | 33 ++--- modules/video_output/opengl/fragment_shaders.c | 71 ++++++----- modules/video_output/opengl/interop.h | 136 ++++++++++++++++++++ modules/video_output/opengl/vout_helper.c | 157 ++++++++++++++---------- modules/video_output/win32/direct3d9.c | 52 ++++---- 11 files changed, 554 insertions(+), 430 deletions(-) diff --git a/modules/hw/nvdec/nvdec_gl.c b/modules/hw/nvdec/nvdec_gl.c index 5c5773a5c2..a6ff6ccf69 100644 --- a/modules/hw/nvdec/nvdec_gl.c +++ b/modules/hw/nvdec/nvdec_gl.c @@ -60,12 +60,12 @@ typedef struct { CUarray mappedArray[PICTURE_PLANE_MAX]; } converter_sys_t; -#define CALL_CUDA(func, ...) CudaCheckErr((vlc_object_t*)&tc->obj, devsys->cudaFunctions, devsys->cudaFunctions->func(__VA_ARGS__), #func) +#define CALL_CUDA(func, ...) CudaCheckErr(VLC_OBJECT(interop->gl), devsys->cudaFunctions, devsys->cudaFunctions->func(__VA_ARGS__), #func) -static int tc_nvdec_gl_allocate_texture(const opengl_tex_converter_t *tc, GLuint *textures, +static int tc_nvdec_gl_allocate_texture(const struct vlc_gl_interop *interop, GLuint *textures, const GLsizei *tex_width, const GLsizei *tex_height) { - converter_sys_t *p_sys = tc->priv; + converter_sys_t *p_sys = interop->priv; vlc_decoder_device *device = p_sys->device; decoder_device_nvdec_t *devsys = GetNVDECOpaqueDevice(device); @@ -74,25 +74,25 @@ static int tc_nvdec_gl_allocate_texture(const opengl_tex_converter_t *tc, GLuint if (result != VLC_SUCCESS) return result; - 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); - if (tc->vt->GetError() != GL_NO_ERROR) + 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); + if (interop->vt->GetError() != GL_NO_ERROR) { - msg_Err(tc->gl, "could not alloc PBO buffers"); + msg_Err(interop->gl, "could not alloc PBO buffers"); return VLC_EGENERIC; } - result = CALL_CUDA(cuGraphicsGLRegisterImage, &p_sys->cu_res[i], textures[i], tc->tex_target, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD); + result = CALL_CUDA(cuGraphicsGLRegisterImage, &p_sys->cu_res[i], textures[i], interop->tex_target, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD); result = CALL_CUDA(cuGraphicsMapResources, 1, &p_sys->cu_res[i], 0); result = CALL_CUDA(cuGraphicsSubResourceGetMappedArray, &p_sys->mappedArray[i], p_sys->cu_res[i], 0, 0); result = CALL_CUDA(cuGraphicsUnmapResources, 1, &p_sys->cu_res[i], 0); - tc->vt->BindTexture(tc->tex_target, 0); + interop->vt->BindTexture(interop->tex_target, 0); } CALL_CUDA(cuCtxPopCurrent, NULL); @@ -100,14 +100,14 @@ static int tc_nvdec_gl_allocate_texture(const opengl_tex_converter_t *tc, GLuint } static int -tc_nvdec_gl_update(opengl_tex_converter_t const *tc, GLuint textures[], +tc_nvdec_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[]) { VLC_UNUSED(plane_offsets); VLC_UNUSED(textures); - converter_sys_t *p_sys = tc->priv; + converter_sys_t *p_sys = interop->priv; vlc_decoder_device *device = p_sys->device; decoder_device_nvdec_t *devsys = GetNVDECOpaqueDevice(device); pic_context_nvdec_t *srcpic = container_of(pic->context, pic_context_nvdec_t, ctx); @@ -119,7 +119,7 @@ tc_nvdec_gl_update(opengl_tex_converter_t const *tc, GLuint textures[], // copy the planes from the pic context to mappedArray size_t srcY = 0; - for (unsigned i = 0; i < tc->tex_count; i++) + for (unsigned i = 0; i < interop->tex_count; i++) { CUDA_MEMCPY2D cu_cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, @@ -131,7 +131,7 @@ tc_nvdec_gl_update(opengl_tex_converter_t const *tc, GLuint textures[], .WidthInBytes = tex_widths[0], .Height = tex_heights[i], }; - if (tc->fmt.i_chroma != VLC_CODEC_NVDEC_OPAQUE && tc->fmt.i_chroma != VLC_CODEC_NVDEC_OPAQUE_444) + if (interop->fmt.i_chroma != VLC_CODEC_NVDEC_OPAQUE && interop->fmt.i_chroma != VLC_CODEC_NVDEC_OPAQUE_444) cu_cpy.WidthInBytes *= 2; result = CALL_CUDA(cuMemcpy2DAsync, &cu_cpy, 0); if (result != VLC_SUCCESS) @@ -147,17 +147,18 @@ error: static void Close(vlc_object_t *obj) { opengl_tex_converter_t *tc = (void *)obj; - converter_sys_t *p_sys = tc->priv; + converter_sys_t *p_sys = tc->interop.priv; vlc_decoder_device_Release(p_sys->device); } static int Open(vlc_object_t *obj) { opengl_tex_converter_t *tc = (void *) obj; - if (!is_nvdec_opaque(tc->fmt.i_chroma)) + struct vlc_gl_interop *interop = &tc->interop; + if (!is_nvdec_opaque(interop->fmt.i_chroma)) return VLC_EGENERIC; - vlc_decoder_device *device = vlc_video_context_HoldDevice(tc->vctx); + vlc_decoder_device *device = vlc_video_context_HoldDevice(interop->vctx); if (device == NULL || device->type != VLC_DECODER_DEVICE_NVDEC) return VLC_EGENERIC; @@ -197,7 +198,7 @@ static int Open(vlc_object_t *obj) } vlc_fourcc_t render_chroma; - switch (tc->fmt.i_chroma) + switch (interop->fmt.i_chroma) { case VLC_CODEC_NVDEC_OPAQUE_10B: render_chroma = VLC_CODEC_P010; break; case VLC_CODEC_NVDEC_OPAQUE_16B: render_chroma = VLC_CODEC_P016; break; @@ -207,16 +208,19 @@ static int Open(vlc_object_t *obj) default: render_chroma = VLC_CODEC_NV12; break; } - tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, render_chroma, tc->fmt.space); + tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, render_chroma, interop->fmt.space); if (!tc->fshader) { Close(obj); return VLC_EGENERIC; } - tc->pf_allocate_textures = tc_nvdec_gl_allocate_texture; - tc->pf_update = tc_nvdec_gl_update; - tc->priv = p_sys; + static const struct vlc_gl_interop_ops ops = { + .allocate_textures = tc_nvdec_gl_allocate_texture, + .update_textures = tc_nvdec_gl_update, + }; + interop->ops = &ops; + interop->priv = p_sys; return VLC_SUCCESS; } diff --git a/modules/video_output/opengl/converter.h b/modules/video_output/opengl/converter.h index dc053aca5f..7692f269c6 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,44 +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 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 @@ -183,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 9574036e68..ab07b4a73d 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); } @@ -231,12 +231,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) @@ -274,14 +274,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; @@ -313,7 +313,7 @@ tc_va_check_derive_image(opengl_tex_converter_t *tc) EGLint w = (va_image.width * w_num) / image_desc->p[i].w.den; EGLint h = (va_image.height * image_desc->p[i].h.num) / image_desc->p[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) { @@ -321,7 +321,7 @@ tc_va_check_derive_image(opengl_tex_converter_t *tc) ret = VLC_EGENERIC; goto done; } - vaegl_image_destroy(tc, egl_image); + vaegl_image_destroy(interop, egl_image); } done: @@ -341,12 +341,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) @@ -355,7 +356,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; @@ -368,14 +369,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; @@ -403,15 +404,18 @@ 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; + static const struct vlc_gl_interop_ops ops = { + .update_textures = tc_vaegl_update, + }; + 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 837df39568..bf5461ddd4 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,7 +63,7 @@ typedef struct { } converter_sys_t; 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[]) { @@ -94,7 +94,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); @@ -107,7 +107,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); } @@ -116,14 +116,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); @@ -138,7 +140,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); @@ -183,8 +185,11 @@ Open(vlc_object_t *obj) return VLC_EGENERIC; } - tc->pf_update = tc_vdpau_gl_update; - tc->priv = sys; + static const struct vlc_gl_interop_ops ops = { + .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..46aee2a3f4 --- /dev/null +++ b/modules/video_output/opengl/interop.h @@ -0,0 +1,136 @@ +/***************************************************************************** + * 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 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 c19d95f4f7..875dfa58fe 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); @@ -1034,10 +1050,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; @@ -1048,6 +1065,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; @@ -1105,8 +1123,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++) { @@ -1393,6 +1412,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; @@ -1401,19 +1422,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, @@ -1428,7 +1449,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), @@ -1455,12 +1476,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]); @@ -1475,8 +1497,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; @@ -1517,6 +1540,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]; @@ -1526,7 +1551,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; @@ -1534,7 +1559,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; @@ -1565,11 +1590,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 @@ -1606,6 +1632,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); @@ -1645,7 +1672,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); diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c index 709f6de24c..3d8fca052b 100644 --- a/modules/video_output/win32/direct3d9.c +++ b/modules/video_output/win32/direct3d9.c @@ -1687,12 +1687,12 @@ struct glpriv }; static int -GLConvUpdate(const opengl_tex_converter_t *tc, GLuint *textures, +GLConvUpdate(const struct vlc_gl_interop *interop, GLuint *textures, const GLsizei *tex_width, const GLsizei *tex_height, picture_t *pic, const size_t *plane_offset) { VLC_UNUSED(textures); VLC_UNUSED(tex_width); VLC_UNUSED(tex_height); VLC_UNUSED(plane_offset); - struct glpriv *priv = tc->priv; + struct glpriv *priv = interop->priv; HRESULT hr; picture_sys_d3d9_t *picsys = ActiveD3D9PictureSys(pic); @@ -1701,11 +1701,11 @@ GLConvUpdate(const opengl_tex_converter_t *tc, GLuint *textures, if (!priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render)) { - msg_Warn(tc->gl, "DXUnlockObjectsNV failed"); + msg_Warn(interop->gl, "DXUnlockObjectsNV failed"); return VLC_EGENERIC; } - d3d9_decoder_device_t *d3d9_decoder = GetD3D9OpaqueContext(tc->vctx); + d3d9_decoder_device_t *d3d9_decoder = GetD3D9OpaqueContext(interop->vctx); const RECT rect = { .left = 0, @@ -1717,13 +1717,13 @@ GLConvUpdate(const opengl_tex_converter_t *tc, GLuint *textures, &rect, priv->dx_render, NULL, D3DTEXF_NONE); if (FAILED(hr)) { - msg_Warn(tc->gl, "IDirect3DDevice9Ex_StretchRect failed. (0x%lX)", hr); + msg_Warn(interop->gl, "IDirect3DDevice9Ex_StretchRect failed. (0x%lX)", hr); return VLC_EGENERIC; } if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render)) { - msg_Warn(tc->gl, "DXLockObjectsNV failed"); + msg_Warn(interop->gl, "DXLockObjectsNV failed"); priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render); priv->gl_render = NULL; return VLC_EGENERIC; @@ -1733,24 +1733,24 @@ GLConvUpdate(const opengl_tex_converter_t *tc, GLuint *textures, } static int -GLConvAllocateTextures(const opengl_tex_converter_t *tc, GLuint *textures, +GLConvAllocateTextures(const struct vlc_gl_interop *interop, GLuint *textures, const GLsizei *tex_width, const GLsizei *tex_height) { VLC_UNUSED(tex_width); VLC_UNUSED(tex_height); - struct glpriv *priv = tc->priv; + struct glpriv *priv = interop->priv; priv->gl_render = priv->vt.DXRegisterObjectNV(priv->gl_handle_d3d, priv->dx_render, textures[0], GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV); if (!priv->gl_render) { - msg_Warn(tc->gl, "DXRegisterObjectNV failed: %lu", GetLastError()); + msg_Warn(interop->gl, "DXRegisterObjectNV failed: %lu", GetLastError()); return VLC_EGENERIC; } if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render)) { - msg_Warn(tc->gl, "DXLockObjectsNV failed"); + msg_Warn(interop->gl, "DXLockObjectsNV failed"); priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render); priv->gl_render = NULL; return VLC_EGENERIC; @@ -1763,7 +1763,7 @@ static void GLConvClose(vlc_object_t *obj) { opengl_tex_converter_t *tc = (void *)obj; - struct glpriv *priv = tc->priv; + struct glpriv *priv = tc->interop.priv; if (priv->gl_handle_d3d) { @@ -1779,34 +1779,35 @@ GLConvClose(vlc_object_t *obj) if (priv->dx_render) IDirect3DSurface9_Release(priv->dx_render); - free(tc->priv); + free(priv); } static int GLConvOpen(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_D3D9_OPAQUE - && tc->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B) + if (interop->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE + && interop->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B) return VLC_EGENERIC; - d3d9_video_context_t *vctx_sys = GetD3D9ContextPrivate( tc->vctx ); - d3d9_decoder_device_t *d3d9_decoder = GetD3D9OpaqueContext(tc->vctx); + d3d9_video_context_t *vctx_sys = GetD3D9ContextPrivate( interop->vctx ); + d3d9_decoder_device_t *d3d9_decoder = GetD3D9OpaqueContext(interop->vctx); if ( vctx_sys == NULL || d3d9_decoder == NULL ) return VLC_EGENERIC; - if (tc->gl->ext != VLC_GL_EXT_WGL || !tc->gl->wgl.getExtensionsString) + if (interop->gl->ext != VLC_GL_EXT_WGL || !interop->gl->wgl.getExtensionsString) return VLC_EGENERIC; - const char *wglExt = tc->gl->wgl.getExtensionsString(tc->gl); + const char *wglExt = interop->gl->wgl.getExtensionsString(interop->gl); if (wglExt == NULL || !vlc_gl_StrHasToken(wglExt, "WGL_NV_DX_interop")) return VLC_EGENERIC; struct wgl_vt vt; #define LOAD_EXT(name, type) do { \ - vt.name = (type) vlc_gl_GetProcAddress(tc->gl, "wgl" #name); \ + vt.name = (type) vlc_gl_GetProcAddress(interop->gl, "wgl" #name); \ if (!vt.name) { \ msg_Warn(obj, "'wgl " #name "' could not be loaded"); \ return VLC_EGENERIC; \ @@ -1824,7 +1825,7 @@ GLConvOpen(vlc_object_t *obj) struct glpriv *priv = calloc(1, sizeof(struct glpriv)); if (!priv) return VLC_ENOMEM; - tc->priv = priv; + interop->priv = priv; priv->vt = vt; if (!d3d9_decoder->hd3d.use_ex) @@ -1836,8 +1837,8 @@ GLConvOpen(vlc_object_t *obj) HRESULT hr; HANDLE shared_handle = NULL; hr = IDirect3DDevice9Ex_CreateRenderTarget(d3d9_decoder->d3ddev.devex, - tc->fmt.i_visible_width, - tc->fmt.i_visible_height, + interop->fmt.i_visible_width, + interop->fmt.i_visible_height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &priv->dx_render, &shared_handle); @@ -1857,8 +1858,11 @@ GLConvOpen(vlc_object_t *obj) goto error; } - tc->pf_update = GLConvUpdate; - tc->pf_allocate_textures = GLConvAllocateTextures; + static const struct vlc_gl_interop_ops ops = { + .allocate_textures = GLConvAllocateTextures, + .update_textures = GLConvUpdate, + }; + interop->ops = &ops; tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, VLC_CODEC_RGB32, COLOR_SPACE_UNDEF); _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
