diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST index 9509eba71dd2a5a4ca9bed2a9a15e7f870452ce1..2f1656d930745cc9622757c055b1a928dd3860da 100644 --- a/modules/MODULES_LIST +++ b/modules/MODULES_LIST @@ -162,6 +162,11 @@ $Id$ * gaussianblur: gaussian blur video filter * gestures: mouse gestures control plugin * gl: OpenGL video output using the generic OpenGL provider + * glconv_android: Android SurfaceTexture OpenGL hardware converter + * glconv_cvpx: Apple CVPX OpenGL hardware converter (for iOS and macOS) + * glconv_vaapi_drm: VA-API OpenGL hardware converter for DRM + * glconv_vaapi_wl: VA-API OpenGL hardware converter for Wayland + * glconv_vaapi_x11: VA-API OpenGL hardware converter for X11 * gles2: OpenGL ES2 video output using the generic OpenGL provider * glspectrum: 3D OpenGL spectrum visualization * glwin32: a opengl provider using DirectX OpenGL diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am index 695cd680b4525e0b1a134ce38dfb552075407c7f..004bc51952502db212b026b70615ce3fc2f04bbb 100644 --- a/modules/video_output/Makefile.am +++ b/modules/video_output/Makefile.am @@ -3,53 +3,10 @@ vout_LTLIBRARIES = EXTRA_DIST += video_output/README -OPENGL_COMMONCFLAGS = -OPENGL_COMMONLDFLAGS = -OPENGL_COMMONLIBS = OPENGL_COMMONSOURCES = video_output/opengl/vout_helper.c \ video_output/opengl/vout_helper.h video_output/opengl/converter.h \ - video_output/opengl/converters.c -if HAVE_ANDROID -OPENGL_COMMONSOURCES += video_output/opengl/converter_android.c -endif -if HAVE_OSX -OPENGL_COMMONSOURCES += video_output/opengl/converter_cvpx.c \ - codec/vt_utils.c codec/vt_utils.h -OPENGL_COMMONCFLAGS += -DVLCGL_CONV_CVPX -OPENGL_COMMONLDFLAGS += -Wl,-framework,IOSurface -Wl,-framework,CoreVideo -endif -if HAVE_IOS -OPENGL_COMMONSOURCES += video_output/opengl/converter_cvpx.c -OPENGL_COMMONCFLAGS += -DVLCGL_CONV_CVPX -endif -if HAVE_TVOS -OPENGL_COMMONSOURCES += video_output/opengl/converter_cvpx.c -OPENGL_COMMONCFLAGS += -DVLCGL_CONV_CVPX -endif -if HAVE_EGL -if HAVE_VAAPI -OPENGL_COMMONLIBS += $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) -OPENGL_COMMONSOURCES += video_output/opengl/converter_vaapi.c \ - hw/vaapi/vlc_vaapi.c hw/vaapi/vlc_vaapi.h -OPENGL_COMMONCFLAGS += -DVLCGL_CONV_VA -if HAVE_WAYLAND_EGL -if HAVE_VAAPI_WL -OPENGL_COMMONLIBS += $(LIBVA_WL_LIBS) -OPENGL_COMMONCFLAGS += -DHAVE_VA_WL $(LIBVA_WL_CFLAGS) -endif -endif -if HAVE_VAAPI_X11 -if HAVE_XCB -OPENGL_COMMONLIBS += $(LIBVA_X11_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lX11 -OPENGL_COMMONCFLAGS += -DHAVE_VA_X11 -endif -endif -if HAVE_VAAPI_DRM -OPENGL_COMMONLIBS += $(LIBVA_DRM_LIBS) -OPENGL_COMMONCFLAGS += -DHAVE_VA_DRM -endif -endif -endif + video_output/opengl/internal.h video_output/opengl/fragment_shaders.c \ + video_output/opengl/converter_sw.c if HAVE_DECKLINK libdecklinkoutput_plugin_la_SOURCES = video_output/decklink.cpp @@ -58,27 +15,32 @@ libdecklinkoutput_plugin_la_LIBADD = $(LIBS_decklink) $(LIBDL) -lpthread vout_LTLIBRARIES += libdecklinkoutput_plugin.la endif +libglconv_cvpx_plugin_la_SOURCES = video_output/opengl/converter_cvpx.c \ + video_output/opengl/converter.h + if HAVE_OSX libvout_macosx_plugin_la_SOURCES = video_output/macosx.m $(OPENGL_COMMONSOURCES) -libvout_macosx_plugin_la_CFLAGS = $(AM_CFLAGS) $(OPENGL_COMMONCFLAGS) libvout_macosx_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \ - -Wl,-framework,OpenGL,-framework,Cocoa $(OPENGL_COMMONLDFLAGS) + -Wl,-framework,OpenGL,-framework,Cocoa libcaopengllayer_plugin_la_SOURCES = video_output/caopengllayer.m $(OPENGL_COMMONSOURCES) -libcaopengllayer_plugin_la_CFLAGS = $(AM_CFLAGS) $(OPENGL_COMMONCFLAGS) libcaopengllayer_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \ - -Wl,-framework,OpenGL,-framework,Cocoa,-framework,QuartzCore \ - $(OPENGL_COMMONLDFLAGS) -vout_LTLIBRARIES += libvout_macosx_plugin.la libcaopengllayer_plugin.la + -Wl,-framework,OpenGL,-framework,Cocoa,-framework,QuartzCore + +libglconv_cvpx_plugin_la_SOURCES += codec/vt_utils.c codec/vt_utils.h +libglconv_cvpx_plugin_la_LDFLAGS = -Wl,-framework,IOSurface -Wl,-framework,CoreVideo +vout_LTLIBRARIES += libvout_macosx_plugin.la libcaopengllayer_plugin.la \ + libglconv_cvpx_plugin.la +endif +if HAVE_IOS +libglconv_cvpx_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_OPENGL_ES2 endif libvout_ios_plugin_la_SOURCES = video_output/ios.m $(OPENGL_COMMONSOURCES) -libvout_ios_plugin_la_CFLAGS = $(AM_CFLAGS) $(OPENGL_COMMONCFLAGS) libvout_ios_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' \ - -Wl,-framework,OpenGLES,-framework,QuartzCore,-framework,UIKit \ - $(OPENGL_COMMONLDFLAGS) + -Wl,-framework,OpenGLES,-framework,QuartzCore,-framework,UIKit if HAVE_IOS -vout_LTLIBRARIES += libvout_ios_plugin.la +vout_LTLIBRARIES += libvout_ios_plugin.la libglconv_cvpx_plugin.la endif if HAVE_TVOS vout_LTLIBRARIES += libvout_ios_plugin.la @@ -86,22 +48,54 @@ endif ### OpenGL ### libgles2_plugin_la_SOURCES = $(OPENGL_COMMONSOURCES) video_output/opengl/display.c -libgles2_plugin_la_CFLAGS = $(AM_CFLAGS) $(GLES2_CFLAGS) -DUSE_OPENGL_ES2 \ - $(OPENGL_COMMONCFLAGS) -libgles2_plugin_la_LIBADD = $(GLES2_LIBS) $(LIBM) $(OPENGL_COMMONLIBS) -libgles2_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' $(OPENGL_COMMONLDFLAGS) +libgles2_plugin_la_CFLAGS = $(AM_CFLAGS) $(GLES2_CFLAGS) -DUSE_OPENGL_ES2 +libgles2_plugin_la_LIBADD = $(GLES2_LIBS) $(LIBM) +libgles2_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' EXTRA_LTLIBRARIES += libgles2_plugin.la vout_LTLIBRARIES += $(LTLIBgles2) libgl_plugin_la_SOURCES = $(OPENGL_COMMONSOURCES) video_output/opengl/display.c -libgl_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS) $(OPENGL_COMMONCFLAGS) -libgl_plugin_la_LIBADD = $(GL_LIBS) $(LIBM) $(OPENGL_COMMONLIBS) -libgl_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(OPENGL_COMMONLDFLAGS) +libgl_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS) +libgl_plugin_la_LIBADD = $(GL_LIBS) $(LIBM) + +libglconv_vaapi_wl_plugin_la_SOURCES = video_output/opengl/converter_vaapi.c \ + video_output/opengl/converter.h \ + hw/vaapi/vlc_vaapi.c hw/vaapi/vlc_vaapi.h +libglconv_vaapi_wl_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS) -DHAVE_VA_WL $(LIBVA_WL_CFLAGS) +libglconv_vaapi_wl_plugin_la_LIBADD = $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) \ + $(LIBVA_WL_LIBS) + +libglconv_vaapi_x11_plugin_la_SOURCES = $(libglconv_vaapi_wl_plugin_la_SOURCES) +libglconv_vaapi_x11_plugin_la_CFLAGS = $(AM_CFLAGS) -DHAVE_VA_X11 +libglconv_vaapi_x11_plugin_la_LIBADD = $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) \ + $(LIBVA_X11_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lX11 + +libglconv_vaapi_drm_plugin_la_SOURCES = $(libglconv_vaapi_wl_plugin_la_SOURCES) +libglconv_vaapi_drm_plugin_la_CFLAGS = $(AM_CFLAGS) -DHAVE_VA_DRM +libglconv_vaapi_drm_plugin_la_LIBADD = $(LIBVA_LIBS) $(LIBVA_EGL_LIBS) \ + $(LIBVA_DRM_LIBS) + if HAVE_GL vout_LTLIBRARIES += libgl_plugin.la +if HAVE_EGL +if HAVE_VAAPI +if HAVE_WAYLAND_EGL +if HAVE_VAAPI_WL +vout_LTLIBRARIES += libglconv_vaapi_wl_plugin.la endif - +endif +if HAVE_XCB +if HAVE_VAAPI_X11 +vout_LTLIBRARIES += libglconv_vaapi_x11_plugin.la +endif +endif +if HAVE_VAAPI_DRM +vout_LTLIBRARIES += libglconv_vaapi_drm_plugin.la +endif +endif +endif # HAVE_EGL +endif # HAVE_GL ### XCB ### libvlc_xcb_events_la_SOURCES = \ @@ -318,14 +312,12 @@ libglwin32_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \ -DMODULE_NAME_IS_glwin32 libwgl_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \ -DMODULE_NAME_IS_wgl -libglwin32_plugin_la_CFLAGS = $(AM_CFLAGS) $(OPENGL_COMMONCFLAGS) -libwgl_plugin_la_CFLAGS = $(AM_CFLAGS) $(OPENGL_COMMONCFLAGS) -libglwin32_plugin_la_LIBADD = -lopengl32 -lgdi32 $(LIBCOM) -luuid $(OPENGL_COMMONLIBS) -libwgl_plugin_la_LIBADD = -lopengl32 -lgdi32 $(OPENGL_COMMONLIBS) +libglwin32_plugin_la_LIBADD = -lopengl32 -lgdi32 $(LIBCOM) -luuid +libwgl_plugin_la_LIBADD = -lopengl32 -lgdi32 -libglwin32_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' $(OPENGL_COMMONLDFLAGS) -libwgl_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' $(OPENGL_COMMONLDFLAGS) +libglwin32_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' +libwgl_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' if HAVE_WIN32_DESKTOP vout_LTLIBRARIES += $(LTLIBglwin32) $(LTLIBwgl) @@ -389,10 +381,14 @@ libandroid_display_plugin_la_SOURCES = video_output/android/display.c \ libandroid_display_plugin_la_CFLAGS = $(AM_CFLAGS) libandroid_display_plugin_la_LIBADD = $(LIBDL) +libglconv_android_plugin_la_SOURCES = video_output/opengl/converter_android.c \ + video_output/opengl/converter.h +libglconv_android_plugin_la_CFLAGS = $(AM_CFLAGS) -DUSE_OPENGL_ES2 + if HAVE_ANDROID vout_LTLIBRARIES += libandroid_window_plugin.la libandroid_display_plugin.la if HAVE_EGL -vout_LTLIBRARIES += libegl_android_plugin.la +vout_LTLIBRARIES += libegl_android_plugin.la libglconv_android_plugin.la endif endif diff --git a/modules/video_output/macosx.m b/modules/video_output/macosx.m index dd132fef20993044366c87d9d302c36098d9b5ff..a04e12c7df11f30a00f6d87c1555b0e625fa64f7 100644 --- a/modules/video_output/macosx.m +++ b/modules/video_output/macosx.m @@ -49,6 +49,10 @@ #include <vlc_dialog.h> #include "opengl/vout_helper.h" +#define GLHW_TEXT N_("GL/GLES hw converter") +#define GLHW_LONGTEXT N_( \ + "Force an \"gl hw converter\" module.") + /** * Forward declarations */ @@ -77,6 +81,8 @@ vlc_module_begin () set_subcategory (SUBCAT_VIDEO_VOUT) set_capability ("vout display", 300) set_callbacks (Open, Close) + add_module ("glhw", NULL, NULL, + GLHW_TEXT, GLHW_LONGTEXT, true) add_shortcut ("macosx", "vout_macosx") vlc_module_end () diff --git a/modules/video_output/opengl/converter.h b/modules/video_output/opengl/converter.h index 6e1d10497bbcb9e304f47fece0bf71528a75c061..7ca1a2e26299a38b63e15e0be7d5af3c273da2e9 100644 --- a/modules/video_output/opengl/converter.h +++ b/modules/video_output/opengl/converter.h @@ -22,6 +22,7 @@ #define VLC_OPENGL_CONVERTER_H #include "vout_helper.h" +#include <vlc_plugin.h> #define VLCGL_PICTURE_MAX 128 @@ -163,32 +164,29 @@ typedef struct { PFNGLCLIENTWAITSYNCPROC ClientWaitSync; /* can be NULL */ } opengl_vtable_t; -typedef struct opengl_tex_converter_t opengl_tex_converter_t; - -/* - * Callback to initialize an opengl_tex_converter_t struct - * - * The implementation should initialize every members of the struct in regards - * of the video format. - * - * \param fmt video format, fmt->i_chroma can be modified in order to match a - * shader - * \param fc OpenGL tex converter that needs to be filled on success - * \return VLC_SUCCESS or a VLC error - */ -typedef int (*opengl_tex_converter_init_cb)(opengl_tex_converter_t *fc); - /* - * Structure that is filled by an opengl_tex_converter_init_cb function + * Structure that is filled by "glhw converter" module probe function + * The implementation should initialize every members of the struct that are + * not set by the caller */ +typedef struct opengl_tex_converter_t opengl_tex_converter_t; struct opengl_tex_converter_t { - /* Pointer to object gl, set by the caller of the init cb */ + VLC_COMMON_MEMBERS + + module_t *p_module; + + /* Pointer to object gl, set by the caller */ vlc_gl_t *gl; /* Function pointers to OpenGL functions, set by the caller */ const opengl_vtable_t *vt; + /* Function pointer to the shader init command, set by the caller, see + * opengl_fragment_shader_init() documentation. */ + 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; @@ -317,14 +315,6 @@ struct opengl_tex_converter_t void (*pf_prepare_shader)(const opengl_tex_converter_t *fc, const GLsizei *tex_width, const GLsizei *tex_height, float alpha); - - /* - * Callback to release the private context - * - * This function pointer can be NULL. - * \param fc OpenGL tex converter - */ - void (*pf_release)(const opengl_tex_converter_t *fc); }; /* @@ -334,38 +324,20 @@ struct opengl_tex_converter_t * generic fragment shader. It will compile a fragment shader generated from * the chroma and the tex target. This will initialize all elements of the * opengl_tex_converter_t struct except for priv, pf_allocate_texture, - * pf_get_pool, pf_update, and pf_release. + * pf_get_pool, pf_update * * \param tc OpenGL tex converter * \param tex_target GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE * \param chroma chroma used to generate the fragment shader - * \param yuv_space if not COLOR_SPACE_UNDEF, YUV planes will be converted to - * RGB according to the color space + * \param if not COLOR_SPACE_UNDEF, YUV planes will be converted to RGB + * according to the color space * \return the compiled fragment shader or 0 in case of error */ -GLuint +static inline GLuint opengl_fragment_shader_init(opengl_tex_converter_t *tc, GLenum tex_target, - vlc_fourcc_t chroma, video_color_space_t yuv_space); - -int -opengl_tex_converter_subpictures_init(opengl_tex_converter_t *); - -int -opengl_tex_converter_generic_init(opengl_tex_converter_t *); - -#ifdef __ANDROID__ -int -opengl_tex_converter_anop_init(opengl_tex_converter_t *); -#endif - -#ifdef VLCGL_CONV_CVPX -int -opengl_tex_converter_cvpx_init(opengl_tex_converter_t *tc); -#endif - -#ifdef VLCGL_CONV_VA -int -opengl_tex_converter_vaapi_init(opengl_tex_converter_t *tc); -#endif + vlc_fourcc_t chroma, video_color_space_t yuv_space) +{ + return tc->pf_fragment_shader_init(tc, tex_target, chroma, yuv_space); +} #endif /* include-guard */ diff --git a/modules/video_output/opengl/converter_android.c b/modules/video_output/opengl/converter_android.c index 6fce87955614431cd36a53cb81ff2a7f25434dcb..b028e47a2275e7921e15858cc1d23c682d47e126 100644 --- a/modules/video_output/opengl/converter_android.c +++ b/modules/video_output/opengl/converter_android.c @@ -181,8 +181,9 @@ tc_anop_prepare_shader(const opengl_tex_converter_t *tc, } static void -tc_anop_release(const opengl_tex_converter_t *tc) +Close(vlc_object_t *obj) { + opengl_tex_converter_t *tc = (void *)obj; struct priv *priv = tc->priv; if (priv->stex_attached) @@ -191,9 +192,11 @@ tc_anop_release(const opengl_tex_converter_t *tc) free(priv); } -int -opengl_tex_converter_anop_init(opengl_tex_converter_t *tc) +static int +Open(vlc_object_t *obj) { + opengl_tex_converter_t *tc = (void *) obj; + if (tc->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE || !tc->gl->surface->handle.anativewindow) return VLC_EGENERIC; @@ -212,10 +215,9 @@ opengl_tex_converter_anop_init(opengl_tex_converter_t *tc) tc->pf_update = tc_anop_update; tc->pf_fetch_locations = tc_anop_fetch_locations; tc->pf_prepare_shader = tc_anop_prepare_shader; - tc->pf_release = tc_anop_release; tc->tex_count = 1; - tc->texs[0] = (struct opengl_tex_cfg) { { 1, 1 }, { 1, 1 } }; + tc->texs[0] = (struct opengl_tex_cfg) { { 1, 1 }, { 1, 1 }, 0, 0, 0 }; tc->tex_target = GL_TEXTURE_EXTERNAL_OES; @@ -273,3 +275,11 @@ opengl_tex_converter_anop_init(opengl_tex_converter_t *tc) return VLC_SUCCESS; } + +vlc_module_begin () + set_description("Android OpenGL SurfaceTexture converter") + set_capability("glconv", 1) + set_callbacks(Open, Close) + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) +vlc_module_end () diff --git a/modules/video_output/opengl/converter_cvpx.c b/modules/video_output/opengl/converter_cvpx.c index 7ab31e0fd621796d6b5ee16b00c1c82f22830fca..c048a19dacf361f6565d92153102d05e148baa95 100644 --- a/modules/video_output/opengl/converter_cvpx.c +++ b/modules/video_output/opengl/converter_cvpx.c @@ -143,8 +143,9 @@ tc_cvpx_update(const opengl_tex_converter_t *tc, GLuint *textures, #endif static void -tc_cvpx_release(const opengl_tex_converter_t *tc) +Close(vlc_object_t *obj) { + opengl_tex_converter_t *tc = (void *)obj; struct priv *priv = tc->priv; if (priv->last_pic != NULL) @@ -155,9 +156,10 @@ tc_cvpx_release(const opengl_tex_converter_t *tc) free(tc->priv); } -int -opengl_tex_converter_cvpx_init(opengl_tex_converter_t *tc) +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 @@ -242,8 +244,15 @@ opengl_tex_converter_cvpx_init(opengl_tex_converter_t *tc) tc->priv = priv; tc->pf_update = tc_cvpx_update; - tc->pf_release = tc_cvpx_release; tc->fshader = fragment_shader; return VLC_SUCCESS; } + +vlc_module_begin () + set_description("Apple OpenGL CVPX converter") + set_capability("glconv", 1) + set_callbacks(Open, Close) + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) +vlc_module_end () diff --git a/modules/video_output/opengl/converters.c b/modules/video_output/opengl/converter_sw.c similarity index 55% rename from modules/video_output/opengl/converters.c rename to modules/video_output/opengl/converter_sw.c index 7f2e775c3d7a366eb006319553e741471ee890f7..e46d19ce07182146d7f87ddfee455224070f65b7 100644 --- a/modules/video_output/opengl/converters.c +++ b/modules/video_output/opengl/converter_sw.c @@ -1,7 +1,7 @@ /***************************************************************************** - * converters.c: OpenGL converters for common video formats + * converter_sw.c: OpenGL converters for software video formats ***************************************************************************** - * Copyright (C) 2016 VLC authors and VideoLAN + * Copyright (C) 2016,2017 VLC authors and VideoLAN * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by @@ -28,27 +28,7 @@ #include <vlc_common.h> #include <vlc_memory.h> -#include <vlc_memstream.h> -#include "converter.h" - -#ifndef GL_RED -# define GL_RED 0x1903 -#endif -#ifndef GL_RG -# define GL_RG 0x8227 -#endif -#ifndef GL_R16 -# define GL_R16 0x822A -#endif -#ifndef GL_LUMINANCE16 -# define GL_LUMINANCE16 0x8042 -#endif -#ifndef GL_TEXTURE_RED_SIZE -# define GL_TEXTURE_RED_SIZE 0x805C -#endif -#ifndef GL_TEXTURE_LUMINANCE_SIZE -# define GL_TEXTURE_LUMINANCE_SIZE 0x8060 -#endif +#include "internal.h" #ifndef GL_UNPACK_ROW_LENGTH # define GL_UNPACK_ROW_LENGTH 0x0CF2 @@ -113,493 +93,6 @@ struct priv } persistent; }; -static int GetTexFormatSize(opengl_tex_converter_t *tc, int target, - int tex_format, int tex_internal, int tex_type) -{ - GLint tex_param_size; - switch (tex_format) - { - case GL_RED: - tex_param_size = GL_TEXTURE_RED_SIZE; - break; - case GL_LUMINANCE: - tex_param_size = GL_TEXTURE_LUMINANCE_SIZE; - break; - default: - return -1; - } - GLuint texture; - - tc->vt->GenTextures(1, &texture); - tc->vt->BindTexture(target, texture); - tc->vt->TexImage2D(target, 0, tex_internal, 64, 64, 0, tex_format, tex_type, NULL); - GLint size = 0; - tc->vt->GetTexLevelParameteriv(target, 0, tex_param_size, &size); - - tc->vt->DeleteTextures(1, &texture); - return size; -} - -static int -tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target, - vlc_fourcc_t chroma, video_color_space_t yuv_space, - bool *swap_uv, const char *swizzle_per_tex[]) -{ - const vlc_chroma_description_t *desc = vlc_fourcc_GetChromaDescription(chroma); - if (desc == NULL) - return VLC_EGENERIC; - - GLint oneplane_texfmt, oneplane16_texfmt, twoplanes_texfmt; - - if (HasExtension(tc->glexts, "GL_ARB_texture_rg")) - { - oneplane_texfmt = GL_RED; - oneplane16_texfmt = GL_R16; - twoplanes_texfmt = GL_RG; - } - else - { - oneplane_texfmt = GL_LUMINANCE; - oneplane16_texfmt = GL_LUMINANCE16; - twoplanes_texfmt = GL_LUMINANCE_ALPHA; - } - - float yuv_range_correction = 1.0; - if (desc->plane_count == 3) - { - GLint internal = 0; - GLenum type = 0; - - if (desc->pixel_size == 1) - { - internal = oneplane_texfmt; - type = GL_UNSIGNED_BYTE; - } - else if (desc->pixel_size == 2) - { - if (oneplane16_texfmt == 0 - || GetTexFormatSize(tc, tex_target, oneplane_texfmt, - oneplane16_texfmt, GL_UNSIGNED_SHORT) != 16) - return VLC_EGENERIC; - - internal = oneplane16_texfmt; - type = GL_UNSIGNED_SHORT; - yuv_range_correction = (float)((1 << 16) - 1) - / ((1 << desc->pixel_bits) - 1); - } - else - return VLC_EGENERIC; - - assert(internal != 0 && type != 0); - - tc->tex_count = 3; - for (unsigned i = 0; i < tc->tex_count; ++i ) - { - tc->texs[i] = (struct opengl_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 - }; - } - - if (oneplane_texfmt == GL_RED) - swizzle_per_tex[0] = swizzle_per_tex[1] = swizzle_per_tex[2] = "r"; - } - else if (desc->plane_count == 2) - { - if (desc->pixel_size != 1) - return VLC_EGENERIC; - - tc->tex_count = 2; - tc->texs[0] = (struct opengl_tex_cfg) { - { 1, 1 }, { 1, 1 }, oneplane_texfmt, oneplane_texfmt, GL_UNSIGNED_BYTE - }; - tc->texs[1] = (struct opengl_tex_cfg) { - { 1, 2 }, { 1, 2 }, twoplanes_texfmt, twoplanes_texfmt, GL_UNSIGNED_BYTE - }; - - if (oneplane_texfmt == GL_RED) - { - swizzle_per_tex[0] = "r"; - swizzle_per_tex[1] = "rg"; - } - else - { - swizzle_per_tex[0] = NULL; - swizzle_per_tex[1] = "xa"; - } - } - 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) { - { 1, 2 }, { 1, 2 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE - }; - - /* - * Set swizzling in Y1 U V order - * R G B A - * U Y1 V Y2 => GRB - * Y1 U Y2 V => RGA - * V Y1 U Y2 => GBR - * Y1 V Y2 U => RAG - */ - switch (chroma) - { - case VLC_CODEC_UYVY: - swizzle_per_tex[0] = "grb"; - break; - case VLC_CODEC_YUYV: - swizzle_per_tex[0] = "rga"; - break; - case VLC_CODEC_VYUY: - swizzle_per_tex[0] = "gbr"; - break; - case VLC_CODEC_YVYU: - swizzle_per_tex[0] = "rag"; - break; - default: - assert(!"missing chroma"); - return VLC_EGENERIC; - } - } - else - return VLC_EGENERIC; - - /* [R/G/B][Y U V O] from TV range to full range - * XXX we could also do hue/brightness/constrast/gamma - * by simply changing the coefficients - */ - static const float matrix_bt601_tv2full[12] = { - 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 , - 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 , - 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 , - }; - static const float matrix_bt709_tv2full[12] = { - 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 , - 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 , - 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 , - }; - - const float *matrix; - switch (yuv_space) - { - case COLOR_SPACE_BT601: - matrix = matrix_bt601_tv2full; - break; - default: - matrix = matrix_bt709_tv2full; - }; - - for (int i = 0; i < 4; i++) { - float correction = i < 3 ? yuv_range_correction : 1.f; - /* We place coefficient values for coefficient[4] in one array from - * matrix values. Notice that we fill values from top down instead - * of left to right.*/ - for (int j = 0; j < 4; j++) - tc->yuv_coefficients[i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.f; - } - - tc->yuv_color = true; - - *swap_uv = chroma == VLC_CODEC_YV12 || chroma == VLC_CODEC_YV9 || - chroma == VLC_CODEC_NV21; - return VLC_SUCCESS; -} - -static int -tc_rgb_base_init(opengl_tex_converter_t *tc, GLenum tex_target, - vlc_fourcc_t chroma) -{ - (void) tex_target; - - if (chroma != VLC_CODEC_RGB32) - return VLC_EGENERIC; - - tc->tex_count = 1; - tc->texs[0] = (struct opengl_tex_cfg) { - { 1, 1 }, { 1, 1 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE - }; - return VLC_SUCCESS; -} - -static int -tc_base_fetch_locations(opengl_tex_converter_t *tc, GLuint program) -{ - if (tc->yuv_color) - { - tc->uloc.Coefficients = tc->vt->GetUniformLocation(program, - "Coefficients"); - if (tc->uloc.Coefficients == -1) - return VLC_EGENERIC; - } - - for (unsigned int i = 0; i < tc->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) - { - snprintf(name, sizeof(name), "TexSize%1u", i); - tc->uloc.TexSize[i] = tc->vt->GetUniformLocation(program, name); - if (tc->uloc.TexSize[i] == -1) - return VLC_EGENERIC; - } - } - - tc->uloc.FillColor = tc->vt->GetUniformLocation(program, "FillColor"); - if (tc->uloc.FillColor == -1) - return VLC_EGENERIC; - return VLC_SUCCESS; -} - -static void -tc_base_prepare_shader(const opengl_tex_converter_t *tc, - const GLsizei *tex_width, const GLsizei *tex_height, - float alpha) -{ - (void) tex_width; (void) tex_height; - - if (tc->yuv_color) - tc->vt->Uniform4fv(tc->uloc.Coefficients, 4, tc->yuv_coefficients); - - for (unsigned i = 0; i < tc->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) - { - for (unsigned i = 0; i < tc->tex_count; ++i) - tc->vt->Uniform2f(tc->uloc.TexSize[i], tex_width[i], - tex_height[i]); - } -} - -static int -tc_xyz12_fetch_locations(opengl_tex_converter_t *tc, GLuint program) -{ - tc->uloc.Texture[0] = tc->vt->GetUniformLocation(program, "Texture0"); - return tc->uloc.Texture[0] != -1 ? VLC_SUCCESS : VLC_EGENERIC; -} - -static void -tc_xyz12_prepare_shader(const opengl_tex_converter_t *tc, - const GLsizei *tex_width, const GLsizei *tex_height, - float alpha) -{ - (void) tex_width; (void) tex_height; (void) alpha; - tc->vt->Uniform1i(tc->uloc.Texture[0], 0); -} - -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) { - { 1, 1 }, { 1, 1 }, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT - }; - - tc->pf_fetch_locations = tc_xyz12_fetch_locations; - tc->pf_prepare_shader = tc_xyz12_prepare_shader; - - /* Shader for XYZ to RGB correction - * 3 steps : - * - XYZ gamma correction - * - XYZ to RGB matrix conversion - * - reverse RGB gamma correction - */ - static const char *template = - "#version %u\n" - "%s" - "uniform sampler2D Texture0;" - "uniform vec4 xyz_gamma = vec4(2.6);" - "uniform vec4 rgb_gamma = vec4(1.0/2.2);" - /* WARN: matrix Is filled column by column (not row !) */ - "uniform mat4 matrix_xyz_rgb = mat4(" - " 3.240454 , -0.9692660, 0.0556434, 0.0," - " -1.5371385, 1.8760108, -0.2040259, 0.0," - " -0.4985314, 0.0415560, 1.0572252, 0.0," - " 0.0, 0.0, 0.0, 1.0 " - " );" - - "varying vec2 TexCoord0;" - "void main()" - "{ " - " vec4 v_in, v_out;" - " v_in = texture2D(Texture0, TexCoord0);" - " v_in = pow(v_in, xyz_gamma);" - " v_out = matrix_xyz_rgb * v_in ;" - " v_out = pow(v_out, rgb_gamma) ;" - " v_out = clamp(v_out, 0.0, 1.0) ;" - " gl_FragColor = v_out;" - "}"; - - char *code; - if (asprintf(&code, template, tc->glsl_version, tc->glsl_precision_header) < 0) - return 0; - - GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER); - tc->vt->ShaderSource(fragment_shader, 1, (const char **) &code, NULL); - tc->vt->CompileShader(fragment_shader); - free(code); - return fragment_shader; -} - -GLuint -opengl_fragment_shader_init(opengl_tex_converter_t *tc, GLenum tex_target, - vlc_fourcc_t chroma, video_color_space_t yuv_space) -{ - const char *swizzle_per_tex[PICTURE_PLANE_MAX] = { NULL, }; - const bool is_yuv = vlc_fourcc_IsYUV(chroma); - bool yuv_swap_uv = false; - int ret; - - if (chroma == VLC_CODEC_XYZ12) - return xyz12_shader_init(tc); - - if (is_yuv) - ret = tc_yuv_base_init(tc, tex_target, chroma, yuv_space, - &yuv_swap_uv, swizzle_per_tex); - else - ret = tc_rgb_base_init(tc, tex_target, chroma); - - if (ret != VLC_SUCCESS) - return 0; - - const char *sampler, *lookup, *coord_name; - switch (tex_target) - { - case GL_TEXTURE_2D: - sampler = "sampler2D"; - lookup = "texture2D"; - coord_name = "TexCoord"; - break; - case GL_TEXTURE_RECTANGLE: - sampler = "sampler2DRect"; - lookup = "texture2DRect"; - coord_name = "TexCoordRect"; - break; - default: - vlc_assert_unreachable(); - } - - struct vlc_memstream ms; - if (vlc_memstream_open(&ms) != 0) - return 0; - -#define ADD(x) vlc_memstream_puts(&ms, x) -#define ADDF(x, ...) vlc_memstream_printf(&ms, x, ##__VA_ARGS__) - - ADDF("#version %u\n%s", tc->glsl_version, tc->glsl_precision_header); - - for (unsigned i = 0; i < tc->tex_count; ++i) - ADDF("uniform %s Texture%u;" - "varying vec2 TexCoord%u;", sampler, i, i); - - if (tex_target == GL_TEXTURE_RECTANGLE) - { - for (unsigned i = 0; i < tc->tex_count; ++i) - ADDF("uniform vec2 TexSize%u;", i); - } - - if (is_yuv) - ADD("uniform vec4 Coefficients[4];"); - - ADD("uniform vec4 FillColor;" - "void main(void) {" - "float val;vec4 colors;"); - - if (tex_target == GL_TEXTURE_RECTANGLE) - { - for (unsigned i = 0; i < tc->tex_count; ++i) - ADDF("vec2 TexCoordRect%u = vec2(TexCoord%u.x * TexSize%u.x, " - "TexCoord%u.y * TexSize%u.y);", i, i, i, i, i); - } - - unsigned color_idx = 0; - for (unsigned i = 0; i < tc->tex_count; ++i) - { - const char *swizzle = swizzle_per_tex[i]; - if (swizzle) - { - size_t swizzle_count = strlen(swizzle); - ADDF("colors = %s(Texture%u, %s%u);", lookup, i, coord_name, i); - for (unsigned j = 0; j < swizzle_count; ++j) - { - ADDF("val = colors.%c;" - "vec4 color%u = vec4(val, val, val, 1);", - swizzle[j], color_idx); - color_idx++; - assert(color_idx <= PICTURE_PLANE_MAX); - } - } - else - { - ADDF("vec4 color%u = %s(Texture%u, %s%u);", - color_idx, lookup, i, coord_name, i); - color_idx++; - assert(color_idx <= PICTURE_PLANE_MAX); - } - } - unsigned color_count = color_idx; - assert(yuv_space == COLOR_SPACE_UNDEF || color_count == 3); - - if (is_yuv) - ADD("vec4 result = (color0 * Coefficients[0]) + Coefficients[3];"); - else - ADD("vec4 result = color0;"); - - for (unsigned i = 1; i < color_count; ++i) - { - unsigned color_idx; - if (yuv_swap_uv) - { - assert(color_count == 3); - color_idx = (i % 2) + 1; - } - else - color_idx = i; - - if (is_yuv) - ADDF("result = (color%u * Coefficients[%u]) + result;", color_idx, i); - else - ADDF("result = color%u + result;", color_idx); - } - - ADD("gl_FragColor = result * FillColor;" - "}"); - -#undef ADD -#undef ADDF - - if (vlc_memstream_close(&ms) != 0) - return 0; - - GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER); - if (fragment_shader == 0) - { - free(ms.ptr); - return 0; - } - GLint length = ms.length; - tc->vt->ShaderSource(fragment_shader, 1, (const char **)&ms.ptr, &length); - tc->vt->CompileShader(fragment_shader); - free(ms.ptr); - - tc->tex_target = tex_target; - - tc->pf_fetch_locations = tc_base_fetch_locations; - tc->pf_prepare_shader = tc_base_prepare_shader; - - return fragment_shader; -} - static picture_t * pbo_picture_create(const opengl_tex_converter_t *tc, void (*pf_destroy)(picture_t *)) @@ -736,15 +229,6 @@ tc_pbo_update(const opengl_tex_converter_t *tc, GLuint *textures, return VLC_SUCCESS; } -static void -tc_pbo_release(const opengl_tex_converter_t *tc) -{ - struct priv *priv = tc->priv; - for (size_t i = 0; i < PBO_DISPLAY_COUNT && priv->pbo.display_pics[i]; ++i) - picture_Release(priv->pbo.display_pics[i]); - free(tc->priv); -} - static int persistent_map(const opengl_tex_converter_t *tc, picture_t *pic) { @@ -880,13 +364,6 @@ tc_persistent_update(const opengl_tex_converter_t *tc, GLuint *textures, return VLC_SUCCESS; } -static void -tc_persistent_release(const opengl_tex_converter_t *tc) -{ - persistent_release_gpupics(tc, true); - free(tc->priv); -} - static void picture_persistent_destroy_cb(picture_t *pic) { @@ -1051,23 +528,9 @@ tc_common_update(const opengl_tex_converter_t *tc, GLuint *textures, return ret; } -static void -tc_common_release(const opengl_tex_converter_t *tc) -{ - struct priv *priv = tc->priv; - free(priv->texture_temp_buf); - free(tc->priv); -} - -static int -generic_init(opengl_tex_converter_t *tc, bool allow_dr) +int +opengl_tex_converter_generic_init(opengl_tex_converter_t *tc, bool allow_dr) { - const vlc_chroma_description_t *desc = - vlc_fourcc_GetChromaDescription(tc->fmt.i_chroma); - assert(desc); - if (!desc) - return VLC_EGENERIC; - GLuint fragment_shader = 0; video_color_space_t space; const vlc_fourcc_t *list; @@ -1130,7 +593,6 @@ generic_init(opengl_tex_converter_t *tc, bool allow_dr) } tc->pf_update = tc_common_update; - tc->pf_release = tc_common_release; tc->pf_allocate_textures = tc_common_allocate_textures; if (allow_dr) @@ -1159,7 +621,6 @@ generic_init(opengl_tex_converter_t *tc, bool allow_dr) { tc->pf_get_pool = tc_persistent_get_pool; tc->pf_update = tc_persistent_update; - tc->pf_release = tc_persistent_release; msg_Dbg(tc->gl, "MAP_PERSISTENT support (direct rendering) enabled"); } if (!supports_map_persistent) @@ -1169,7 +630,6 @@ generic_init(opengl_tex_converter_t *tc, bool allow_dr) if (supports_pbo && pbo_pics_alloc(tc) == VLC_SUCCESS) { tc->pf_update = tc_pbo_update; - tc->pf_release = tc_pbo_release; msg_Dbg(tc->gl, "PBO support enabled"); } } @@ -1183,14 +643,13 @@ generic_init(opengl_tex_converter_t *tc, bool allow_dr) return VLC_SUCCESS; } -int -opengl_tex_converter_subpictures_init(opengl_tex_converter_t *tc) -{ - return generic_init(tc, false); -} - -int -opengl_tex_converter_generic_init(opengl_tex_converter_t *tc) +void +opengl_tex_converter_generic_deinit(opengl_tex_converter_t *tc) { - return generic_init(tc, true); + struct priv *priv = tc->priv; + for (size_t i = 0; i < PBO_DISPLAY_COUNT && priv->pbo.display_pics[i]; ++i) + picture_Release(priv->pbo.display_pics[i]); + persistent_release_gpupics(tc, true); + free(priv->texture_temp_buf); + free(tc->priv); } diff --git a/modules/video_output/opengl/converter_vaapi.c b/modules/video_output/opengl/converter_vaapi.c index 4979bfc31a56d37b40149692f95c4e566324e3c2..6ffee98fb59466b4ca83273ccf5410cbf4d7f441 100644 --- a/modules/video_output/opengl/converter_vaapi.c +++ b/modules/video_output/opengl/converter_vaapi.c @@ -249,8 +249,9 @@ tc_vaegl_get_pool(const opengl_tex_converter_t *tc, unsigned requested_count) } static void -tc_vaegl_release(const opengl_tex_converter_t *tc) +Close(vlc_object_t *obj) { + opengl_tex_converter_t *tc = (void *)obj; struct priv *priv = tc->priv; if (priv->last.pic != NULL) @@ -319,7 +320,6 @@ tc_vaegl_init(opengl_tex_converter_t *tc, VADisplay *vadpy, goto error; tc->pf_update = tc_vaegl_update; - tc->pf_release = tc_vaegl_release; tc->pf_get_pool = tc_vaegl_get_pool; priv->vainst = vlc_vaapi_InitializeInstance(VLC_OBJECT(tc->gl), priv->vadpy, @@ -371,9 +371,11 @@ drm_native_destroy_cb(VANativeDisplay native) } #endif -int -opengl_tex_converter_vaapi_init(opengl_tex_converter_t *tc) +static int +Open(vlc_object_t *obj) { + opengl_tex_converter_t *tc = (void *) obj; + if (tc->fmt.i_chroma != VLC_CODEC_VAAPI_420 || tc->gl->ext != VLC_GL_EXT_EGL || tc->gl->egl.createImageKHR == NULL || tc->gl->egl.destroyImageKHR == NULL) @@ -387,34 +389,23 @@ opengl_tex_converter_vaapi_init(opengl_tex_converter_t *tc) return VLC_EGENERIC; int ret = VLC_EGENERIC; - switch (tc->gl->surface->type) +#if defined (HAVE_VA_X11) + if (tc->gl->surface->type == VOUT_WINDOW_TYPE_XID) { -#ifdef HAVE_VA_X11 - case VOUT_WINDOW_TYPE_XID: - { - if (!vlc_xlib_init(VLC_OBJECT(tc->gl))) - break; - Display *x11dpy = XOpenDisplay(tc->gl->surface->display.x11); - if (x11dpy == NULL) - break; - - ret = tc_vaegl_init(tc, vaGetDisplay(x11dpy), x11dpy, - x11_native_destroy_cb); - break; - } -#endif -#ifdef HAVE_VA_WL - case VOUT_WINDOW_TYPE_WAYLAND: - ret = tc_vaegl_init(tc, vaGetDisplayWl(tc->gl->surface->display.wl), - NULL, NULL); - break; -#endif + if (!vlc_xlib_init(VLC_OBJECT(tc->gl))) + return VLC_EGENERIC; + Display *x11dpy = XOpenDisplay(tc->gl->surface->display.x11); + if (x11dpy == NULL) + return VLC_EGENERIC; + + ret = tc_vaegl_init(tc, vaGetDisplay(x11dpy), x11dpy, + x11_native_destroy_cb); } - - if (ret == VLC_SUCCESS) - return VLC_SUCCESS; - -#ifdef HAVE_VA_DRM +#elif defined(HAVE_VA_WL) + if (tc->gl->surface->type == VOUT_WINDOW_TYPE_WAYLAND) + ret = tc_vaegl_init(tc, vaGetDisplayWl(tc->gl->surface->display.wl), + NULL, NULL); +#elif defined (HAVE_VA_DRM) static const char *const drm_device_paths[] = { "/dev/dri/renderD128", "/dev/dri/card0" @@ -431,14 +422,34 @@ opengl_tex_converter_vaapi_init(opengl_tex_converter_t *tc) { ret = tc_vaegl_init(tc, dpy, (VANativeDisplay) (intptr_t) drm_fd, drm_native_destroy_cb); - if (ret == VLC_SUCCESS) - return ret; } else vlc_close(drm_fd); } - /* Fallback to X11 or WAYLAND */ #endif - return VLC_EGENERIC; + return ret; } + +#if defined (HAVE_VA_X11) +# define PRIORITY 2 +# define SHORTCUT "vaapi_x11" +# define DESCRIPTION_SUFFIX "X11" +#elif defined(HAVE_VA_WL) +# define PRIORITY 2 +# define SHORTCUT "vaapi_wl" +# define DESCRIPTION_SUFFIX "Wayland" +#elif defined (HAVE_VA_DRM) +# define PRIORITY 1 +# define SHORTCUT "vaapi_drm" +# define DESCRIPTION_SUFFIX "DRM" +#endif + +vlc_module_begin () + set_description("VA-API OpenGL surface converter for " DESCRIPTION_SUFFIX) + set_capability("glconv", PRIORITY) + set_callbacks(Open, Close) + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) + add_shortcut("vaapi", SHORTCUT) +vlc_module_end () diff --git a/modules/video_output/opengl/display.c b/modules/video_output/opengl/display.c index d12d6ca71a680e522999cbc6acd0b6364a6a0ec5..063873372b35277e174cb61fc6a18bf191bc58e8 100644 --- a/modules/video_output/opengl/display.c +++ b/modules/video_output/opengl/display.c @@ -42,6 +42,10 @@ static void Close (vlc_object_t *); #define PROVIDER_LONGTEXT N_( \ "Extension through which to use the Open Graphics Library (OpenGL).") +#define GLCONV_TEXT N_("Open GL/GLES hardware converter") +#define GLCONV_LONGTEXT N_( \ + "Force a \"glconv\" module.") + vlc_module_begin () #if defined (USE_OPENGL_ES2) # define API VLC_OPENGL_ES2 @@ -68,6 +72,8 @@ vlc_module_begin () add_module ("gl", "opengl", NULL, GL_TEXT, PROVIDER_LONGTEXT, true) #endif + add_module ("glconv", NULL, NULL, + GLCONV_TEXT, GLCONV_LONGTEXT, true) vlc_module_end () struct vout_display_sys_t diff --git a/modules/video_output/opengl/fragment_shaders.c b/modules/video_output/opengl/fragment_shaders.c new file mode 100644 index 0000000000000000000000000000000000000000..294330ca279293f2e0480f36c61d618104f10559 --- /dev/null +++ b/modules/video_output/opengl/fragment_shaders.c @@ -0,0 +1,536 @@ +/***************************************************************************** + * fragment_shaders.c: OpenGL fragment shaders + ***************************************************************************** + * Copyright (C) 2016,2017 VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <stdlib.h> + +#include <vlc_common.h> +#include <vlc_memstream.h> +#include "internal.h" + +#ifndef GL_RED +# define GL_RED 0x1903 +#endif +#ifndef GL_RG +# define GL_RG 0x8227 +#endif +#ifndef GL_R16 +# define GL_R16 0x822A +#endif +#ifndef GL_LUMINANCE16 +# define GL_LUMINANCE16 0x8042 +#endif +#ifndef GL_TEXTURE_RED_SIZE +# define GL_TEXTURE_RED_SIZE 0x805C +#endif +#ifndef GL_TEXTURE_LUMINANCE_SIZE +# define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#endif + +static int GetTexFormatSize(opengl_tex_converter_t *tc, int target, + int tex_format, int tex_internal, int tex_type) +{ + GLint tex_param_size; + switch (tex_format) + { + case GL_RED: + tex_param_size = GL_TEXTURE_RED_SIZE; + break; + case GL_LUMINANCE: + tex_param_size = GL_TEXTURE_LUMINANCE_SIZE; + break; + default: + return -1; + } + GLuint texture; + + tc->vt->GenTextures(1, &texture); + tc->vt->BindTexture(target, texture); + tc->vt->TexImage2D(target, 0, tex_internal, 64, 64, 0, tex_format, tex_type, NULL); + GLint size = 0; + tc->vt->GetTexLevelParameteriv(target, 0, tex_param_size, &size); + + tc->vt->DeleteTextures(1, &texture); + return size; +} + +static int +tc_yuv_base_init(opengl_tex_converter_t *tc, GLenum tex_target, + vlc_fourcc_t chroma, video_color_space_t yuv_space, + bool *swap_uv, const char *swizzle_per_tex[]) +{ + const vlc_chroma_description_t *desc = vlc_fourcc_GetChromaDescription(chroma); + if (desc == NULL) + return VLC_EGENERIC; + + GLint oneplane_texfmt, oneplane16_texfmt, twoplanes_texfmt; + + if (HasExtension(tc->glexts, "GL_ARB_texture_rg")) + { + oneplane_texfmt = GL_RED; + oneplane16_texfmt = GL_R16; + twoplanes_texfmt = GL_RG; + } + else + { + oneplane_texfmt = GL_LUMINANCE; + oneplane16_texfmt = GL_LUMINANCE16; + twoplanes_texfmt = GL_LUMINANCE_ALPHA; + } + + float yuv_range_correction = 1.0; + if (desc->plane_count == 3) + { + GLint internal = 0; + GLenum type = 0; + + if (desc->pixel_size == 1) + { + internal = oneplane_texfmt; + type = GL_UNSIGNED_BYTE; + } + else if (desc->pixel_size == 2) + { + if (oneplane16_texfmt == 0 + || GetTexFormatSize(tc, tex_target, oneplane_texfmt, + oneplane16_texfmt, GL_UNSIGNED_SHORT) != 16) + return VLC_EGENERIC; + + internal = oneplane16_texfmt; + type = GL_UNSIGNED_SHORT; + yuv_range_correction = (float)((1 << 16) - 1) + / ((1 << desc->pixel_bits) - 1); + } + else + return VLC_EGENERIC; + + assert(internal != 0 && type != 0); + + tc->tex_count = 3; + for (unsigned i = 0; i < tc->tex_count; ++i ) + { + tc->texs[i] = (struct opengl_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 + }; + } + + if (oneplane_texfmt == GL_RED) + swizzle_per_tex[0] = swizzle_per_tex[1] = swizzle_per_tex[2] = "r"; + } + else if (desc->plane_count == 2) + { + if (desc->pixel_size != 1) + return VLC_EGENERIC; + + tc->tex_count = 2; + tc->texs[0] = (struct opengl_tex_cfg) { + { 1, 1 }, { 1, 1 }, oneplane_texfmt, oneplane_texfmt, GL_UNSIGNED_BYTE + }; + tc->texs[1] = (struct opengl_tex_cfg) { + { 1, 2 }, { 1, 2 }, twoplanes_texfmt, twoplanes_texfmt, GL_UNSIGNED_BYTE + }; + + if (oneplane_texfmt == GL_RED) + { + swizzle_per_tex[0] = "r"; + swizzle_per_tex[1] = "rg"; + } + else + { + swizzle_per_tex[0] = NULL; + swizzle_per_tex[1] = "xa"; + } + } + 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) { + { 1, 2 }, { 1, 2 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE + }; + + /* + * Set swizzling in Y1 U V order + * R G B A + * U Y1 V Y2 => GRB + * Y1 U Y2 V => RGA + * V Y1 U Y2 => GBR + * Y1 V Y2 U => RAG + */ + switch (chroma) + { + case VLC_CODEC_UYVY: + swizzle_per_tex[0] = "grb"; + break; + case VLC_CODEC_YUYV: + swizzle_per_tex[0] = "rga"; + break; + case VLC_CODEC_VYUY: + swizzle_per_tex[0] = "gbr"; + break; + case VLC_CODEC_YVYU: + swizzle_per_tex[0] = "rag"; + break; + default: + assert(!"missing chroma"); + return VLC_EGENERIC; + } + } + else + return VLC_EGENERIC; + + /* [R/G/B][Y U V O] from TV range to full range + * XXX we could also do hue/brightness/constrast/gamma + * by simply changing the coefficients + */ + static const float matrix_bt601_tv2full[12] = { + 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 , + 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 , + 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 , + }; + static const float matrix_bt709_tv2full[12] = { + 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 , + 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 , + 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 , + }; + + const float *matrix; + switch (yuv_space) + { + case COLOR_SPACE_BT601: + matrix = matrix_bt601_tv2full; + break; + default: + matrix = matrix_bt709_tv2full; + }; + + for (int i = 0; i < 4; i++) { + float correction = i < 3 ? yuv_range_correction : 1.f; + /* We place coefficient values for coefficient[4] in one array from + * matrix values. Notice that we fill values from top down instead + * of left to right.*/ + for (int j = 0; j < 4; j++) + tc->yuv_coefficients[i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.f; + } + + tc->yuv_color = true; + + *swap_uv = chroma == VLC_CODEC_YV12 || chroma == VLC_CODEC_YV9 || + chroma == VLC_CODEC_NV21; + return VLC_SUCCESS; +} + +static int +tc_rgb_base_init(opengl_tex_converter_t *tc, GLenum tex_target, + vlc_fourcc_t chroma) +{ + (void) tex_target; + + if (chroma != VLC_CODEC_RGB32) + return VLC_EGENERIC; + + tc->tex_count = 1; + tc->texs[0] = (struct opengl_tex_cfg) { + { 1, 1 }, { 1, 1 }, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE + }; + return VLC_SUCCESS; +} + +static int +tc_base_fetch_locations(opengl_tex_converter_t *tc, GLuint program) +{ + if (tc->yuv_color) + { + tc->uloc.Coefficients = tc->vt->GetUniformLocation(program, + "Coefficients"); + if (tc->uloc.Coefficients == -1) + return VLC_EGENERIC; + } + + for (unsigned int i = 0; i < tc->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) + { + snprintf(name, sizeof(name), "TexSize%1u", i); + tc->uloc.TexSize[i] = tc->vt->GetUniformLocation(program, name); + if (tc->uloc.TexSize[i] == -1) + return VLC_EGENERIC; + } + } + + tc->uloc.FillColor = tc->vt->GetUniformLocation(program, "FillColor"); + if (tc->uloc.FillColor == -1) + return VLC_EGENERIC; + return VLC_SUCCESS; +} + +static void +tc_base_prepare_shader(const opengl_tex_converter_t *tc, + const GLsizei *tex_width, const GLsizei *tex_height, + float alpha) +{ + (void) tex_width; (void) tex_height; + + if (tc->yuv_color) + tc->vt->Uniform4fv(tc->uloc.Coefficients, 4, tc->yuv_coefficients); + + for (unsigned i = 0; i < tc->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) + { + for (unsigned i = 0; i < tc->tex_count; ++i) + tc->vt->Uniform2f(tc->uloc.TexSize[i], tex_width[i], + tex_height[i]); + } +} + +static int +tc_xyz12_fetch_locations(opengl_tex_converter_t *tc, GLuint program) +{ + tc->uloc.Texture[0] = tc->vt->GetUniformLocation(program, "Texture0"); + return tc->uloc.Texture[0] != -1 ? VLC_SUCCESS : VLC_EGENERIC; +} + +static void +tc_xyz12_prepare_shader(const opengl_tex_converter_t *tc, + const GLsizei *tex_width, const GLsizei *tex_height, + float alpha) +{ + (void) tex_width; (void) tex_height; (void) alpha; + tc->vt->Uniform1i(tc->uloc.Texture[0], 0); +} + +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) { + { 1, 1 }, { 1, 1 }, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT + }; + + tc->pf_fetch_locations = tc_xyz12_fetch_locations; + tc->pf_prepare_shader = tc_xyz12_prepare_shader; + + /* Shader for XYZ to RGB correction + * 3 steps : + * - XYZ gamma correction + * - XYZ to RGB matrix conversion + * - reverse RGB gamma correction + */ + static const char *template = + "#version %u\n" + "%s" + "uniform sampler2D Texture0;" + "uniform vec4 xyz_gamma = vec4(2.6);" + "uniform vec4 rgb_gamma = vec4(1.0/2.2);" + /* WARN: matrix Is filled column by column (not row !) */ + "uniform mat4 matrix_xyz_rgb = mat4(" + " 3.240454 , -0.9692660, 0.0556434, 0.0," + " -1.5371385, 1.8760108, -0.2040259, 0.0," + " -0.4985314, 0.0415560, 1.0572252, 0.0," + " 0.0, 0.0, 0.0, 1.0 " + " );" + + "varying vec2 TexCoord0;" + "void main()" + "{ " + " vec4 v_in, v_out;" + " v_in = texture2D(Texture0, TexCoord0);" + " v_in = pow(v_in, xyz_gamma);" + " v_out = matrix_xyz_rgb * v_in ;" + " v_out = pow(v_out, rgb_gamma) ;" + " v_out = clamp(v_out, 0.0, 1.0) ;" + " gl_FragColor = v_out;" + "}"; + + char *code; + if (asprintf(&code, template, tc->glsl_version, tc->glsl_precision_header) < 0) + return 0; + + GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER); + tc->vt->ShaderSource(fragment_shader, 1, (const char **) &code, NULL); + tc->vt->CompileShader(fragment_shader); + free(code); + return fragment_shader; +} + +GLuint +opengl_fragment_shader_init_impl(opengl_tex_converter_t *tc, GLenum tex_target, + vlc_fourcc_t chroma, video_color_space_t yuv_space) +{ + const char *swizzle_per_tex[PICTURE_PLANE_MAX] = { NULL, }; + const bool is_yuv = vlc_fourcc_IsYUV(chroma); + bool yuv_swap_uv = false; + int ret; + + if (chroma == VLC_CODEC_XYZ12) + return xyz12_shader_init(tc); + + if (is_yuv) + ret = tc_yuv_base_init(tc, tex_target, chroma, yuv_space, + &yuv_swap_uv, swizzle_per_tex); + else + ret = tc_rgb_base_init(tc, tex_target, chroma); + + if (ret != VLC_SUCCESS) + return 0; + + const char *sampler, *lookup, *coord_name; + switch (tex_target) + { + case GL_TEXTURE_2D: + sampler = "sampler2D"; + lookup = "texture2D"; + coord_name = "TexCoord"; + break; + case GL_TEXTURE_RECTANGLE: + sampler = "sampler2DRect"; + lookup = "texture2DRect"; + coord_name = "TexCoordRect"; + break; + default: + vlc_assert_unreachable(); + } + + struct vlc_memstream ms; + if (vlc_memstream_open(&ms) != 0) + return 0; + +#define ADD(x) vlc_memstream_puts(&ms, x) +#define ADDF(x, ...) vlc_memstream_printf(&ms, x, ##__VA_ARGS__) + + ADDF("#version %u\n%s", tc->glsl_version, tc->glsl_precision_header); + + for (unsigned i = 0; i < tc->tex_count; ++i) + ADDF("uniform %s Texture%u;" + "varying vec2 TexCoord%u;", sampler, i, i); + + if (tex_target == GL_TEXTURE_RECTANGLE) + { + for (unsigned i = 0; i < tc->tex_count; ++i) + ADDF("uniform vec2 TexSize%u;", i); + } + + if (is_yuv) + ADD("uniform vec4 Coefficients[4];"); + + ADD("uniform vec4 FillColor;" + "void main(void) {" + "float val;vec4 colors;"); + + if (tex_target == GL_TEXTURE_RECTANGLE) + { + for (unsigned i = 0; i < tc->tex_count; ++i) + ADDF("vec2 TexCoordRect%u = vec2(TexCoord%u.x * TexSize%u.x, " + "TexCoord%u.y * TexSize%u.y);", i, i, i, i, i); + } + + unsigned color_idx = 0; + for (unsigned i = 0; i < tc->tex_count; ++i) + { + const char *swizzle = swizzle_per_tex[i]; + if (swizzle) + { + size_t swizzle_count = strlen(swizzle); + ADDF("colors = %s(Texture%u, %s%u);", lookup, i, coord_name, i); + for (unsigned j = 0; j < swizzle_count; ++j) + { + ADDF("val = colors.%c;" + "vec4 color%u = vec4(val, val, val, 1);", + swizzle[j], color_idx); + color_idx++; + assert(color_idx <= PICTURE_PLANE_MAX); + } + } + else + { + ADDF("vec4 color%u = %s(Texture%u, %s%u);", + color_idx, lookup, i, coord_name, i); + color_idx++; + assert(color_idx <= PICTURE_PLANE_MAX); + } + } + unsigned color_count = color_idx; + assert(yuv_space == COLOR_SPACE_UNDEF || color_count == 3); + + if (is_yuv) + ADD("vec4 result = (color0 * Coefficients[0]) + Coefficients[3];"); + else + ADD("vec4 result = color0;"); + + for (unsigned i = 1; i < color_count; ++i) + { + unsigned color_idx; + if (yuv_swap_uv) + { + assert(color_count == 3); + color_idx = (i % 2) + 1; + } + else + color_idx = i; + + if (is_yuv) + ADDF("result = (color%u * Coefficients[%u]) + result;", color_idx, i); + else + ADDF("result = color%u + result;", color_idx); + } + + ADD("gl_FragColor = result * FillColor;" + "}"); + +#undef ADD +#undef ADDF + + if (vlc_memstream_close(&ms) != 0) + return 0; + + GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER); + if (fragment_shader == 0) + { + free(ms.ptr); + return 0; + } + GLint length = ms.length; + tc->vt->ShaderSource(fragment_shader, 1, (const char **)&ms.ptr, &length); + tc->vt->CompileShader(fragment_shader); + free(ms.ptr); + + tc->tex_target = tex_target; + + tc->pf_fetch_locations = tc_base_fetch_locations; + tc->pf_prepare_shader = tc_base_prepare_shader; + + return fragment_shader; +} diff --git a/modules/video_output/opengl/internal.h b/modules/video_output/opengl/internal.h new file mode 100644 index 0000000000000000000000000000000000000000..9cac74bf9a11865bb6966b8d39a5826f6b09b9c1 --- /dev/null +++ b/modules/video_output/opengl/internal.h @@ -0,0 +1,35 @@ +/***************************************************************************** + * internal.h: OpenGL internal header + ***************************************************************************** + * Copyright (C) 2017 VLC authors and VideoLAN + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef VLC_OPENGL_INTERNAL_H +#define VLC_OPENGL_INTERNAL_H + +#include "converter.h" + +GLuint +opengl_fragment_shader_init_impl(opengl_tex_converter_t *, + GLenum, vlc_fourcc_t, video_color_space_t); +int +opengl_tex_converter_generic_init(opengl_tex_converter_t *, bool); + +void +opengl_tex_converter_generic_deinit(opengl_tex_converter_t *tc); + +#endif /* include-guard */ diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c index 372bdd7c96372bedf12bb2623e5551d93130706a..9ae57c3457a73064024b82914f2ed7b75d0b3097 100644 --- a/modules/video_output/opengl/vout_helper.c +++ b/modules/video_output/opengl/vout_helper.c @@ -37,11 +37,11 @@ #include <vlc_subpicture.h> #include <vlc_opengl.h> #include <vlc_memory.h> +#include <vlc_modules.h> #include <vlc_vout.h> #include <vlc_viewpoint.h> -#include "vout_helper.h" -#include "converter.h" +#include "internal.h" #ifndef GL_CLAMP_TO_EDGE # define GL_CLAMP_TO_EDGE 0x812F @@ -49,20 +49,6 @@ #define SPHERE_RADIUS 1.f -static opengl_tex_converter_init_cb opengl_tex_converter_init_cbs[] = -{ -#ifdef VLCGL_CONV_VA - opengl_tex_converter_vaapi_init, -#endif -#ifdef __ANDROID__ - opengl_tex_converter_anop_init, -#endif -#ifdef VLCGL_CONV_CVPX - opengl_tex_converter_cvpx_init, -#endif - opengl_tex_converter_generic_init, -}; - typedef struct { GLuint texture; GLsizei width; @@ -82,7 +68,7 @@ typedef struct { struct prgm { GLuint id; - opengl_tex_converter_t tc; + opengl_tex_converter_t *tc; struct { GLfloat OrientationMatrix[16]; @@ -435,7 +421,7 @@ DelTextures(const opengl_tex_converter_t *tc, GLuint *textures) static int opengl_link_program(struct prgm *prgm) { - opengl_tex_converter_t *tc = &prgm->tc; + opengl_tex_converter_t *tc = prgm->tc; GLuint vertex_shader = BuildVertexShader(tc, tc->tex_count); GLuint shaders[] = { tc->fshader, vertex_shader }; @@ -512,18 +498,18 @@ 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 (prgm->tc->tex_count > 1) GET_ALOC(MultiTexCoord[1], "MultiTexCoord1"); else prgm->aloc.MultiTexCoord[1] = -1; - if (prgm->tc.tex_count > 2) + if (prgm->tc->tex_count > 2) GET_ALOC(MultiTexCoord[2], "MultiTexCoord2"); else prgm->aloc.MultiTexCoord[2] = -1; #undef GET_LOC #undef GET_ULOC #undef GET_ALOC - int ret = prgm->tc.pf_fetch_locations(&prgm->tc, prgm->id); + int ret = prgm->tc->pf_fetch_locations(prgm->tc, prgm->id); assert(ret == VLC_SUCCESS); if (ret != VLC_SUCCESS) { @@ -542,8 +528,12 @@ error: static void opengl_deinit_program(vout_display_opengl_t *vgl, struct prgm *prgm) { - if (prgm->tc.pf_release != NULL) - prgm->tc.pf_release(&prgm->tc); + opengl_tex_converter_t *tc = prgm->tc; + if (tc->p_module != NULL) + module_unneed(tc, tc->p_module); + else if (tc->priv != NULL) + opengl_tex_converter_generic_deinit(tc); + vlc_object_release(tc); if (prgm->id != 0) vgl->vt.DeleteProgram(prgm->id); } @@ -552,61 +542,81 @@ static int opengl_init_program(vout_display_opengl_t *vgl, struct prgm *prgm, const char *glexts, const video_format_t *fmt, bool subpics) { - int ret; - prgm->tc = (opengl_tex_converter_t) { - .gl = vgl->gl, - .vt = &vgl->vt, - .glexts = glexts, + opengl_tex_converter_t *tc = + vlc_object_create(vgl->gl, sizeof(opengl_tex_converter_t)); + if (tc == NULL) + return VLC_ENOMEM; + + tc->gl = vgl->gl; + tc->vt = &vgl->vt; + tc->pf_fragment_shader_init = opengl_fragment_shader_init_impl; + tc->glexts = glexts; #if defined(USE_OPENGL_ES2) - .is_gles = true, - .glsl_version = 100, - .glsl_precision_header = "precision highp float;\n", + tc->is_gles = true; + tc->glsl_version = 100; + tc->glsl_precision_header = "precision highp float;\n"; #else - .is_gles = false, - .glsl_version = 120, - .glsl_precision_header = "", + tc->is_gles = false; + tc->glsl_version = 120; + tc->glsl_precision_header = ""; #endif - .fmt = *fmt, - }; + tc->fmt = *fmt; + int ret; if (subpics) { - prgm->tc.fmt.i_chroma = VLC_CODEC_RGB32; + tc->fmt.i_chroma = VLC_CODEC_RGB32; /* Normal orientation and no projection for subtitles */ - prgm->tc.fmt.orientation = ORIENT_NORMAL; - prgm->tc.fmt.projection_mode = PROJECTION_MODE_RECTANGULAR; + tc->fmt.orientation = ORIENT_NORMAL; + tc->fmt.projection_mode = PROJECTION_MODE_RECTANGULAR; - ret = opengl_tex_converter_subpictures_init(&prgm->tc); + ret = opengl_tex_converter_generic_init(tc, false); } else { - for (size_t i = 0; i < ARRAY_SIZE(opengl_tex_converter_init_cbs); ++i) + const vlc_chroma_description_t *desc = + vlc_fourcc_GetChromaDescription(fmt->i_chroma); + + if (desc == NULL) + return VLC_EGENERIC; + if (desc->plane_count == 0) + { + /* Opaque chroma: load a module to handle it */ + tc->p_module = module_need(tc, "glconv", "$glconv", true); + } + + if (tc->p_module != NULL) + ret = VLC_SUCCESS; + else { - ret = opengl_tex_converter_init_cbs[i](&prgm->tc); - if (ret == VLC_SUCCESS) - break; + /* Software chroma or gl hw converter failed: use a generic + * converter */ + ret = opengl_tex_converter_generic_init(tc, true); } } if (ret != VLC_SUCCESS) - return ret; + { + vlc_object_release(tc); + return VLC_EGENERIC; + } + + assert(tc->fshader != 0 && tc->tex_target != 0 && tc->tex_count > 0 && + tc->pf_update != NULL && tc->pf_fetch_locations != NULL && + tc->pf_prepare_shader != NULL); - assert(prgm->tc.fshader != 0 && prgm->tc.tex_target != 0 && - prgm->tc.tex_count > 0 && prgm->tc.pf_update != NULL && - prgm->tc.pf_fetch_locations != NULL && - prgm->tc.pf_prepare_shader != NULL); + prgm->tc = tc; ret = opengl_link_program(prgm); if (ret != VLC_SUCCESS) { - if (prgm->tc.pf_release != NULL) - prgm->tc.pf_release(&prgm->tc); + opengl_deinit_program(vgl, prgm); return VLC_EGENERIC; } - getOrientationTransformMatrix(prgm->tc.fmt.orientation, + getOrientationTransformMatrix(tc->fmt.orientation, prgm->var.OrientationMatrix); - getViewpointMatrixes(vgl, prgm->tc.fmt.projection_mode, prgm); + getViewpointMatrixes(vgl, tc->fmt.projection_mode, prgm); return VLC_SUCCESS; } @@ -783,12 +793,12 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt, return NULL; } /* Update the fmt to main program one */ - vgl->fmt = vgl->prgm->tc.fmt; + vgl->fmt = vgl->prgm->tc->fmt; /* The orientation is handled by the orientation matrix */ vgl->fmt.orientation = ORIENT_NORMAL; /* Texture size */ - const opengl_tex_converter_t *tc = &vgl->prgm->tc; + 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; @@ -804,11 +814,11 @@ 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->handle_texs_gen); - if (!vgl->prgm->tc.handle_texs_gen) + if (!vgl->prgm->tc->handle_texs_gen) { - ret = GenTextures(&vgl->prgm->tc, vgl->tex_width, vgl->tex_height, + ret = GenTextures(vgl->prgm->tc, vgl->tex_width, vgl->tex_height, vgl->texture); if (ret != VLC_SUCCESS) { @@ -827,7 +837,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(vgl->prgm->tc->tex_count, vgl->texture_buffer_object); /* Initial number of allocated buffer objects for subpictures, will grow dynamically. */ int subpicture_buffer_object_count = 8; @@ -864,12 +874,12 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl) glFinish(); glFlush(); - opengl_tex_converter_t *tc = &vgl->prgm->tc; + opengl_tex_converter_t *tc = vgl->prgm->tc; if (!tc->handle_texs_gen) DelTextures(tc, vgl->texture); opengl_deinit_program(vgl, vgl->prgm); - tc = &vgl->sub_prgm->tc; + tc = vgl->sub_prgm->tc; for (int i = 0; i < vgl->region_count; i++) { if (vgl->region[i].texture) @@ -881,7 +891,7 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl) vgl->vt.DeleteBuffers(1, &vgl->vertex_buffer_object); vgl->vt.DeleteBuffers(1, &vgl->index_buffer_object); - vgl->vt.DeleteBuffers(vgl->prgm->tc.tex_count, vgl->texture_buffer_object); + vgl->vt.DeleteBuffers(vgl->prgm->tc->tex_count, vgl->texture_buffer_object); if (vgl->subpicture_buffer_object_count > 0) vgl->vt.DeleteBuffers(vgl->subpicture_buffer_object_count, vgl->subpicture_buffer_object); free(vgl->subpicture_buffer_object); @@ -965,7 +975,7 @@ picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned if (vgl->pool) return vgl->pool; - opengl_tex_converter_t *tc = &vgl->prgm->tc; + opengl_tex_converter_t *tc = vgl->prgm->tc; requested_count = __MIN(VLCGL_PICTURE_MAX, requested_count); /* Allocate with tex converter pool callback if it exists */ if (tc->pf_get_pool != NULL) @@ -1007,7 +1017,7 @@ error: int vout_display_opengl_Prepare(vout_display_opengl_t *vgl, picture_t *picture, subpicture_t *subpicture) { - opengl_tex_converter_t *tc = &vgl->prgm->tc; + opengl_tex_converter_t *tc = vgl->prgm->tc; /* Update the texture */ int ret = tc->pf_update(tc, vgl->texture, vgl->tex_width, vgl->tex_height, @@ -1021,7 +1031,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl, vgl->region_count = 0; vgl->region = NULL; - tc = &vgl->sub_prgm->tc; + tc = vgl->sub_prgm->tc; if (subpicture) { int count = 0; @@ -1370,19 +1380,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(vgl->prgm->tc->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(vgl->prgm->tc->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(vgl->prgm->tc->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, @@ -1397,7 +1407,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 < vgl->prgm->tc->tex_count; j++) { vgl->vt.BindBuffer(GL_ARRAY_BUFFER, vgl->texture_buffer_object[j]); vgl->vt.BufferData(GL_ARRAY_BUFFER, nbVertices * 2 * sizeof(GLfloat), @@ -1423,10 +1433,10 @@ 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; + opengl_tex_converter_t *tc = prgm->tc; 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 < vgl->prgm->tc->tex_count; j++) { assert(vgl->texture[j] != 0); vgl->vt.ActiveTexture(GL_TEXTURE0+j); vgl->vt.BindTexture(tc->tex_target, vgl->texture[j]); @@ -1479,7 +1489,7 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl, float top[PICTURE_PLANE_MAX]; float right[PICTURE_PLANE_MAX]; float bottom[PICTURE_PLANE_MAX]; - const opengl_tex_converter_t *tc = &vgl->prgm->tc; + const opengl_tex_converter_t *tc = vgl->prgm->tc; for (unsigned j = 0; j < tc->tex_count; j++) { float scale_w = (float)tc->texs[j].w.num / tc->texs[j].w.den @@ -1519,7 +1529,7 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl, // Change the program for overlays struct prgm *prgm = vgl->sub_prgm; GLuint program = prgm->id; - opengl_tex_converter_t *tc = &prgm->tc; + opengl_tex_converter_t *tc = prgm->tc; vgl->vt.UseProgram(program); glEnable(GL_BLEND); diff --git a/po/POTFILES.in b/po/POTFILES.in index 01388cb32451fa27ed2f59e8bab39eabc69db3d8..57ef6ba7b56a75d2669854c53d989122c044bce4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1132,6 +1132,9 @@ modules/video_output/glx.c modules/video_output/ios.m modules/video_output/kva.c modules/video_output/macosx.m +modules/video_output/opengl/converter_android.c +modules/video_output/opengl/converter_cvpx.c +modules/video_output/opengl/converter_vaapi.c modules/video_output/opengl/display.c modules/video_output/opengl/egl.c modules/video_output/win32/direct3d9.c