diff options
-rw-r--r-- | options/options.c | 2 | ||||
-rw-r--r-- | video/out/opengl/hwdec.c | 144 | ||||
-rw-r--r-- | video/out/opengl/hwdec.h | 122 | ||||
-rw-r--r-- | video/out/opengl/hwdec_cuda.c | 168 | ||||
-rw-r--r-- | video/out/opengl/hwdec_d3d11egl.c | 185 | ||||
-rw-r--r-- | video/out/opengl/hwdec_d3d11eglrgb.c | 142 | ||||
-rw-r--r-- | video/out/opengl/hwdec_dxva2egl.c | 226 | ||||
-rw-r--r-- | video/out/opengl/hwdec_dxva2gldx.c | 187 | ||||
-rw-r--r-- | video/out/opengl/hwdec_ios.m | 209 | ||||
-rw-r--r-- | video/out/opengl/hwdec_osx.c | 154 | ||||
-rw-r--r-- | video/out/opengl/hwdec_rpi.c | 58 | ||||
-rw-r--r-- | video/out/opengl/hwdec_vaegl.c | 291 | ||||
-rw-r--r-- | video/out/opengl/hwdec_vaglx.c | 163 | ||||
-rw-r--r-- | video/out/opengl/hwdec_vdpau.c | 264 | ||||
-rw-r--r-- | video/out/opengl/ra_gl.c | 147 | ||||
-rw-r--r-- | video/out/opengl/ra_gl.h | 12 | ||||
-rw-r--r-- | video/out/opengl/video.c | 73 | ||||
-rw-r--r-- | video/out/opengl/video.h | 4 | ||||
-rw-r--r-- | video/out/vo_opengl.c | 8 | ||||
-rw-r--r-- | video/out/vo_opengl_cb.c | 6 | ||||
-rw-r--r-- | video/vdpau.c | 3 |
21 files changed, 1429 insertions, 1139 deletions
diff --git a/options/options.c b/options/options.c index b07c576d4f..b13d9e5803 100644 --- a/options/options.c +++ b/options/options.c @@ -179,7 +179,7 @@ static const m_option_t mp_vo_opt_list[] = { #endif #if HAVE_GL OPT_STRING_VALIDATE("opengl-hwdec-interop", gl_hwdec_interop, 0, - gl_hwdec_validate_opt), + ra_hwdec_validate_opt), OPT_REPLACED("hwdec-preload", "opengl-hwdec-interop"), #endif {0} diff --git a/video/out/opengl/hwdec.c b/video/out/opengl/hwdec.c index c9256c9c5b..5fbc1aa4a9 100644 --- a/video/out/opengl/hwdec.c +++ b/video/out/opengl/hwdec.c @@ -25,84 +25,85 @@ #include "options/m_config.h" #include "hwdec.h" -extern const struct gl_hwdec_driver gl_hwdec_vaegl; -extern const struct gl_hwdec_driver gl_hwdec_vaglx; -extern const struct gl_hwdec_driver gl_hwdec_videotoolbox; -extern const struct gl_hwdec_driver gl_hwdec_vdpau; -extern const struct gl_hwdec_driver gl_hwdec_dxva2egl; -extern const struct gl_hwdec_driver gl_hwdec_d3d11egl; -extern const struct gl_hwdec_driver gl_hwdec_d3d11eglrgb; -extern const struct gl_hwdec_driver gl_hwdec_dxva2gldx; -extern const struct gl_hwdec_driver gl_hwdec_dxva2; -extern const struct gl_hwdec_driver gl_hwdec_cuda; -extern const struct gl_hwdec_driver gl_hwdec_rpi_overlay; - -static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = { +extern const struct ra_hwdec_driver ra_hwdec_vaegl; +extern const struct ra_hwdec_driver ra_hwdec_vaglx; +extern const struct ra_hwdec_driver ra_hwdec_videotoolbox; +extern const struct ra_hwdec_driver ra_hwdec_vdpau; +extern const struct ra_hwdec_driver ra_hwdec_dxva2egl; +extern const struct ra_hwdec_driver ra_hwdec_d3d11egl; +extern const struct ra_hwdec_driver ra_hwdec_d3d11eglrgb; +extern const struct ra_hwdec_driver ra_hwdec_dxva2gldx; +extern const struct ra_hwdec_driver ra_hwdec_dxva2; +extern const struct ra_hwdec_driver ra_hwdec_cuda; +extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay; + +static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = { #if HAVE_VAAPI_EGL - &gl_hwdec_vaegl, + &ra_hwdec_vaegl, #endif #if HAVE_VAAPI_GLX - &gl_hwdec_vaglx, + &ra_hwdec_vaglx, #endif #if HAVE_VDPAU_GL_X11 - &gl_hwdec_vdpau, + &ra_hwdec_vdpau, #endif #if HAVE_VIDEOTOOLBOX_GL || HAVE_IOS_GL - &gl_hwdec_videotoolbox, + &ra_hwdec_videotoolbox, #endif #if HAVE_D3D_HWACCEL - &gl_hwdec_d3d11egl, - &gl_hwdec_d3d11eglrgb, + &ra_hwdec_d3d11egl, + &ra_hwdec_d3d11eglrgb, #if HAVE_D3D9_HWACCEL - &gl_hwdec_dxva2egl, + &ra_hwdec_dxva2egl, #endif #endif #if HAVE_GL_DXINTEROP_D3D9 - &gl_hwdec_dxva2gldx, + &ra_hwdec_dxva2gldx, #endif #if HAVE_CUDA_HWACCEL - &gl_hwdec_cuda, + &ra_hwdec_cuda, #endif #if HAVE_RPI - &gl_hwdec_rpi_overlay, + &ra_hwdec_rpi_overlay, #endif NULL }; -static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl, +static struct ra_hwdec *load_hwdec_driver(struct mp_log *log, struct ra *ra, struct mpv_global *global, struct mp_hwdec_devices *devs, - const struct gl_hwdec_driver *drv, + const struct ra_hwdec_driver *drv, bool is_auto) { - struct gl_hwdec *hwdec = talloc(NULL, struct gl_hwdec); - *hwdec = (struct gl_hwdec) { + struct ra_hwdec *hwdec = talloc(NULL, struct ra_hwdec); + *hwdec = (struct ra_hwdec) { .driver = drv, .log = mp_log_new(hwdec, log, drv->name), .global = global, - .gl = gl, + .ra = ra, .devs = devs, .probing = is_auto, + .priv = talloc_zero_size(hwdec, drv->priv_size), }; mp_verbose(log, "Loading hwdec driver '%s'\n", drv->name); - if (hwdec->driver->create(hwdec) < 0) { - talloc_free(hwdec); + if (hwdec->driver->init(hwdec) < 0) { + ra_hwdec_uninit(hwdec); mp_verbose(log, "Loading failed.\n"); return NULL; } return hwdec; } -struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, +struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra, struct mpv_global *g, struct mp_hwdec_devices *devs, enum hwdec_type api) { bool is_auto = HWDEC_IS_AUTO(api); for (int n = 0; mpgl_hwdec_drivers[n]; n++) { - const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n]; if ((is_auto || api == drv->api) && !drv->testing_only) { - struct gl_hwdec *r = load_hwdec_driver(log, gl, g, devs, drv, is_auto); + struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, is_auto); if (r) return r; } @@ -111,7 +112,7 @@ struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, } // Load by option name. -struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl, +struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra, struct mpv_global *g, struct mp_hwdec_devices *devs, const char *name) @@ -128,25 +129,25 @@ struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl, } for (int n = 0; mpgl_hwdec_drivers[n]; n++) { - const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n]; if (name && strcmp(drv->name, name) == 0) { - struct gl_hwdec *r = load_hwdec_driver(log, gl, g, devs, drv, false); + struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, false); if (r) return r; } } - return gl_hwdec_load_api(log, gl, g, devs, api_id); + return ra_hwdec_load_api(log, ra, g, devs, api_id); } -int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, +int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param) { bool help = bstr_equals0(param, "help"); if (help) mp_info(log, "Available hwdecs:\n"); for (int n = 0; mpgl_hwdec_drivers[n]; n++) { - const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n]; const char *api_name = m_opt_choice_str(mp_hwdec_names, drv->api); if (help) { mp_info(log, " %s [%s]\n", drv->name, api_name); @@ -172,18 +173,67 @@ int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, return M_OPT_INVALID; } -void gl_hwdec_uninit(struct gl_hwdec *hwdec) +void ra_hwdec_uninit(struct ra_hwdec *hwdec) { if (hwdec) - hwdec->driver->destroy(hwdec); + hwdec->driver->uninit(hwdec); talloc_free(hwdec); } -bool gl_hwdec_test_format(struct gl_hwdec *hwdec, int imgfmt) +bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt) +{ + for (int n = 0; hwdec->driver->imgfmts[n]; n++) { + if (hwdec->driver->imgfmts[n] == imgfmt) + return true; + } + return false; +} + +struct ra_hwdec_mapper *ra_hwdec_mapper_create(struct ra_hwdec *hwdec, + struct mp_image_params *params) +{ + assert(ra_hwdec_test_format(hwdec, params->imgfmt)); + + struct ra_hwdec_mapper *mapper = talloc_ptrtype(NULL, mapper); + *mapper = (struct ra_hwdec_mapper){ + .owner = hwdec, + .driver = hwdec->driver->mapper, + .log = hwdec->log, + .ra = hwdec->ra, + .priv = talloc_zero_size(mapper, hwdec->driver->mapper->priv_size), + .src_params = *params, + .dst_params = *params, + }; + if (mapper->driver->init(mapper) < 0) + ra_hwdec_mapper_free(&mapper); + return mapper; +} + +void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper) +{ + struct ra_hwdec_mapper *p = *mapper; + if (p) { + ra_hwdec_mapper_unmap(p); + p->driver->uninit(p); + talloc_free(p); + } + *mapper = NULL; +} + +void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper) { - if (!imgfmt) - return false; - if (hwdec->driver->test_format) - return hwdec->driver->test_format(hwdec, imgfmt); - return hwdec->driver->imgfmt == imgfmt; + if (mapper->driver->unmap) + mapper->driver->unmap(mapper); + mp_image_unrefp(&mapper->src); +} + +int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img) +{ + ra_hwdec_mapper_unmap(mapper); + mp_image_setrefp(&mapper->src, img); + if (mapper->driver->map(mapper) < 0) { + ra_hwdec_mapper_unmap(mapper); + return -1; + } + return 0; } diff --git a/video/out/opengl/hwdec.h b/video/out/opengl/hwdec.h index 6d4dc5d591..f978b70018 100644 --- a/video/out/opengl/hwdec.h +++ b/video/out/opengl/hwdec.h @@ -2,13 +2,14 @@ #define MPGL_HWDEC_H_ #include "common.h" +#include "ra.h" #include "video/hwdec.h" -struct gl_hwdec { - const struct gl_hwdec_driver *driver; +struct ra_hwdec { + const struct ra_hwdec_driver *driver; struct mp_log *log; struct mpv_global *global; - GL *gl; + struct ra *ra; struct mp_hwdec_devices *devs; // GLSL extensions required to sample textures from this. const char **glsl_extensions; @@ -20,79 +21,110 @@ struct gl_hwdec { float overlay_colorkey[4]; }; -struct gl_hwdec_plane { - GLuint gl_texture; - GLenum gl_target; - // Like struct gl_format.format (GL_RED etc.). Currently to detect - // GL_LUMINANCE_ALPHA and integer formats - can be left to 0 otherwise. - GLenum gl_format; - int tex_w, tex_h; // allocated texture size -}; +struct ra_hwdec_mapper { + const struct ra_hwdec_mapper_driver *driver; + struct mp_log *log; + struct ra *ra; + void *priv; + struct ra_hwdec *owner; + // Input frame parameters. (Set before init(), immutable.) + struct mp_image_params src_params; + // Output frame parameters (represents the format the textures return). Must + // be set by init(), immutable afterwards, + struct mp_image_params dst_params; + + // The currently mapped source image (or the image about to be mapped in + // ->map()). NULL if unmapped. The mapper can also clear this reference if + // the mapped textures contain a full copy. + struct mp_image *src; -struct gl_hwdec_frame { - struct gl_hwdec_plane planes[4]; + // The mapped textures and metadata about them. These fields change if a + // new frame is mapped (or unmapped), but otherwise remain constant. + // The common code won't mess with these, so you can e.g. set them in the + // .init() callback. + struct ra_tex *tex[4]; bool vdpau_fields; }; -struct gl_hwdec_driver { +// This can be used to map frames of a specific hw format as GL textures. +struct ra_hwdec_mapper_driver { + // Used to create ra_hwdec_mapper.priv. + size_t priv_size; + + // Init the mapper implementation. At this point, the field src_params, + // fns, devs, priv are initialized. + int (*init)(struct ra_hwdec_mapper *mapper); + // Destroy the mapper. unmap is called before this. + void (*uninit)(struct ra_hwdec_mapper *mapper); + + // Map mapper->src as texture, and set mapper->frame to textures using it. + // It is expected that that the textures remain valid until the next unmap + // or uninit call. + // The function is allowed to unref mapper->src if it's not needed (i.e. + // this function creates a copy). + // The underlying format can change, so you might need to do some form + // of change detection. You also must reject unsupported formats with an + // error. + // On error, returns negative value on error and remains unmapped. + int (*map)(struct ra_hwdec_mapper *mapper); + // Unmap the frame. Does nothing if already unmapped. Optional. + void (*unmap)(struct ra_hwdec_mapper *mapper); +}; + +struct ra_hwdec_driver { // Name of the interop backend. This is used for informational purposes only. const char *name; + // Used to create ra_hwdec.priv. + size_t priv_size; // Used to explicitly request a specific API. enum hwdec_type api; - // The hardware surface IMGFMT_ that must be passed to map_image later. - // If the test_format callback is set, this field is ignored! - int imgfmt; + // One of the hardware surface IMGFMT_ that must be passed to map_image later. + // Terminated with a 0 entry. (Extend the array size as needed.) + const int imgfmts[3]; // Dosn't load this unless requested by name. bool testing_only; + // Create the hwdec device. It must add it to hw->devs, if applicable. - int (*create)(struct gl_hwdec *hw); - // Prepare for rendering video. (E.g. create textures.) - // Called on initialization, and every time the video size changes. - // *params must be set to the format the hw textures return. - int (*reinit)(struct gl_hwdec *hw, struct mp_image_params *params); - // Return textures that contain a copy or reference of the given hw_image. - // The textures mirror the format returned by the reinit params argument. - // The textures must remain valid until unmap is called. - // hw_image remains referenced by the caller until unmap is called. - int (*map_frame)(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame); - // Must be idempotent. - void (*unmap)(struct gl_hwdec *hw); - - void (*destroy)(struct gl_hwdec *hw); - - // Optional callback for checking input format support. - bool (*test_format)(struct gl_hwdec *hw, int imgfmt); - - // The following functions provide an alternative API. Each gl_hwdec_driver - // must have either map_frame or overlay_frame set (not both or none), and + int (*init)(struct ra_hwdec *hw); + void (*uninit)(struct ra_hwdec *hw); + + // This will be used to create a ra_hwdec_mapper from ra_hwdec. + const struct ra_hwdec_mapper_driver *mapper; + + // The following function provides an alternative API. Each ra_hwdec_driver + // must have either provide a mapper or overlay_frame (not both or none), and // if overlay_frame is set, it operates in overlay mode. In this mode, // OSD etc. is rendered via OpenGL, but the video is rendered as a separate // layer below it. // Non-overlay mode is strictly preferred, so try not to use overlay mode. - // Set the given frame as overlay, replacing the previous one. This can also // just change the position of the overlay. // hw_image==src==dst==NULL is passed to clear the overlay. - int (*overlay_frame)(struct gl_hwdec *hw, struct mp_image *hw_image, + int (*overlay_frame)(struct ra_hwdec *hw, struct mp_image *hw_image, struct mp_rect *src, struct mp_rect *dst, bool newframe); }; -struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, +struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra, struct mpv_global *g, struct mp_hwdec_devices *devs, enum hwdec_type api); -struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl, +struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra, struct mpv_global *g, struct mp_hwdec_devices *devs, const char *name); -int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, +int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param); -void gl_hwdec_uninit(struct gl_hwdec *hwdec); +void ra_hwdec_uninit(struct ra_hwdec *hwdec); + +bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt); -bool gl_hwdec_test_format(struct gl_hwdec *hwdec, int imgfmt); +struct ra_hwdec_mapper *ra_hwdec_mapper_create(struct ra_hwdec *hwdec, + struct mp_image_params *params); +void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper); +void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper); +int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img); #endif diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c index fd432ee7f8..d40bafee24 100644 --- a/video/out/opengl/hwdec_cuda.c +++ b/video/out/opengl/hwdec_cuda.c @@ -35,21 +35,24 @@ #include "formats.h" #include "hwdec.h" #include "options/m_config.h" +#include "ra_gl.h" #include "video.h" -struct priv { +struct priv_owner { struct mp_hwdec_ctx hwctx; + CUcontext display_ctx; + CUcontext decode_ctx; +}; + +struct priv { struct mp_image layout; - GLuint gl_textures[4]; CUgraphicsResource cu_res[4]; CUarray cu_array[4]; - int plane_bytes[4]; CUcontext display_ctx; - CUcontext decode_ctx; }; -static int check_cu(struct gl_hwdec *hw, CUresult err, const char *func) +static int check_cu(struct ra_hwdec *hw, CUresult err, const char *func) { const char *err_name; const char *err_string; @@ -72,22 +75,24 @@ static int check_cu(struct gl_hwdec *hw, CUresult err, const char *func) #define CHECK_CU(x) check_cu(hw, (x), #x) -static int cuda_create(struct gl_hwdec *hw) +static int cuda_init(struct ra_hwdec *hw) { CUdevice display_dev; AVBufferRef *hw_device_ctx = NULL; CUcontext dummy; unsigned int device_count; int ret = 0; + struct priv_owner *p = hw->priv; - if (hw->gl->version < 210 && hw->gl->es < 300) { + if (!ra_is_gl(hw->ra)) + return -1; + + GL *gl = ra_gl_get(hw->ra); + if (gl->version < 210 && gl->es < 300) { MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n"); return -1; } - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - bool loaded = cuda_load(); if (!loaded) { MP_VERBOSE(hw, "Failed to load CUDA symbols\n"); @@ -171,22 +176,43 @@ static int cuda_create(struct gl_hwdec *hw) return -1; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void cuda_uninit(struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); + av_buffer_unref(&p->hwctx.av_device_ref); + + if (p->decode_ctx && p->decode_ctx != p->display_ctx) + CHECK_CU(cuCtxDestroy(p->decode_ctx)); + + if (p->display_ctx) + CHECK_CU(cuCtxDestroy(p->display_ctx)); +} + +#undef CHECK_CU +#define CHECK_CU(x) check_cu((mapper)->owner, (x), #x) + +static int mapper_init(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; CUcontext dummy; int ret = 0, eret = 0; - assert(params->imgfmt == hw->driver->imgfmt); - params->imgfmt = params->hw_subfmt; - params->hw_subfmt = 0; + p->display_ctx = p_owner->display_ctx; - mp_image_set_params(&p->layout, params); + int imgfmt = mapper->src_params.hw_subfmt; + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = imgfmt; + mapper->dst_params.hw_subfmt = 0; - struct gl_imgfmt_desc desc; - if (!gl_get_imgfmt_desc(gl, params->imgfmt, &desc)) { - MP_ERR(hw, "Unsupported format: %s\n", mp_imgfmt_to_name(params->imgfmt)); + mp_image_set_params(&p->layout, &mapper->dst_params); + + struct ra_imgfmt_desc desc; + if (!ra_get_imgfmt_desc(mapper->ra, imgfmt, &desc)) { + MP_ERR(mapper, "Unsupported format: %s\n", mp_imgfmt_to_name(imgfmt)); return -1; } @@ -194,26 +220,30 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) if (ret < 0) return ret; - gl->GenTextures(4, p->gl_textures); for (int n = 0; n < desc.num_planes; n++) { - const struct gl_format *fmt = desc.planes[n]; - - p->plane_bytes[n] = gl_bytes_per_pixel(fmt->format, fmt->type); - - gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); - GLenum filter = GL_LINEAR; - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl->TexImage2D(GL_TEXTURE_2D, 0, fmt->internal_format, - mp_image_plane_w(&p->layout, n), - mp_image_plane_h(&p->layout, n), - 0, fmt->format, fmt->type, NULL); - gl->BindTexture(GL_TEXTURE_2D, 0); - - ret = CHECK_CU(cuGraphicsGLRegisterImage(&p->cu_res[n], p->gl_textures[n], - GL_TEXTURE_2D, + const struct ra_format *format = desc.planes[n]; + + struct ra_tex_params params = { + .dimensions = 2, + .w = mp_image_plane_w(&p->layout, n), + .h = mp_image_plane_h(&p->layout, n), + .d = 1, + .format = format, + .render_src = true, + .src_linear = format->linear_filter, + }; + + mapper->tex[n] = ra_tex_create(mapper->ra, ¶ms); + if (!mapper->tex[n]) { + ret = -1; + goto error; + } + + GLuint texture; + GLenum target; + ra_gl_get_raw_tex(mapper->ra, mapper->tex[n], &texture, &target); + + ret = CHECK_CU(cuGraphicsGLRegisterImage(&p->cu_res[n], texture, target, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD)); if (ret < 0) goto error; @@ -240,10 +270,9 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) return ret; } -static void destroy(struct gl_hwdec *hw) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; CUcontext dummy; // Don't bail if any CUDA calls fail. This is all best effort. @@ -252,25 +281,18 @@ static void destroy(struct gl_hwdec *hw) if (p->cu_res[n] > 0) CHECK_CU(cuGraphicsUnregisterResource(p->cu_res[n])); p->cu_res[n] = 0; + ra_tex_free(mapper->ra, &mapper->tex[n]); } CHECK_CU(cuCtxPopCurrent(&dummy)); +} - if (p->decode_ctx != p->display_ctx) { - CHECK_CU(cuCtxDestroy(p->decode_ctx)); - } - - CHECK_CU(cuCtxDestroy(p->display_ctx)); - - gl->DeleteTextures(4, p->gl_textures); - - hwdec_devices_remove(hw->devs, &p->hwctx); - av_buffer_unref(&p->hwctx.av_device_ref); +static void mapper_unmap(struct ra_hwdec_mapper *mapper) +{ } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; + struct priv *p = mapper->priv; CUcontext dummy; int ret = 0, eret = 0; @@ -278,31 +300,21 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, if (ret < 0) return ret; - *out_frame = (struct gl_hwdec_frame) { 0, }; - for (int n = 0; n < p->layout.num_planes; n++) { - // widthInBytes must account for the chroma plane - // elements being two samples wide. CUDA_MEMCPY2D cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, .dstMemoryType = CU_MEMORYTYPE_ARRAY, - .srcDevice = (CUdeviceptr)hw_image->planes[n], - .srcPitch = hw_image->stride[n], + .srcDevice = (CUdeviceptr)mapper->src->planes[n], + .srcPitch = mapper->src->stride[n], .srcY = 0, .dstArray = p->cu_array[n], - .WidthInBytes = mp_image_plane_w(&p->layout, n) * p->plane_bytes[n], + .WidthInBytes = mp_image_plane_w(&p->layout, n) * + mapper->tex[n]->params.format->pixel_size, .Height = mp_image_plane_h(&p->layout, n), }; ret = CHECK_CU(cuMemcpy2D(&cpy)); if (ret < 0) goto error; - - out_frame->planes[n] = (struct gl_hwdec_plane){ - .gl_texture = p->gl_textures[n], - .gl_target = GL_TEXTURE_2D, - .tex_w = mp_image_plane_w(&p->layout, n), - .tex_h = mp_image_plane_h(&p->layout, n), - }; } @@ -314,12 +326,18 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, return ret; } -const struct gl_hwdec_driver gl_hwdec_cuda = { +const struct ra_hwdec_driver ra_hwdec_cuda = { .name = "cuda", .api = HWDEC_CUDA, - .imgfmt = IMGFMT_CUDA, - .create = cuda_create, - .reinit = reinit, - .map_frame = map_frame, - .destroy = destroy, + .imgfmts = {IMGFMT_CUDA, 0}, + .priv_size = sizeof(struct priv_owner), + .init = cuda_init, + .uninit = cuda_uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/hwdec_d3d11egl.c b/video/out/opengl/hwdec_d3d11egl.c index 686bb99d1a..3988f8310e 100644 --- a/video/out/opengl/hwdec_d3d11egl.c +++ b/video/out/opengl/hwdec_d3d11egl.c @@ -28,6 +28,7 @@ #include "osdep/timer.h" #include "osdep/windows_utils.h" #include "hwdec.h" +#include "ra_gl.h" #include "video/hwdec.h" #include "video/decode/d3d.h" @@ -35,15 +36,12 @@ #define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB #endif -struct priv { +struct priv_owner { struct mp_hwdec_ctx hwctx; ID3D11Device *d3d11_device; EGLDisplay egl_display; - EGLStreamKHR egl_stream; - GLuint gl_textures[3]; - // EGL_KHR_stream EGLStreamKHR (EGLAPIENTRY *CreateStreamKHR)(EGLDisplay dpy, const EGLint *attrib_list); @@ -68,36 +66,29 @@ struct priv { const EGLAttrib *attrib_list); }; -static void destroy_objects(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - GL *gl = hw->gl; - - if (p->egl_stream) - p->DestroyStreamKHR(p->egl_display, p->egl_stream); - p->egl_stream = 0; - - for (int n = 0; n < 3; n++) { - gl->DeleteTextures(1, &p->gl_textures[n]); - p->gl_textures[n] = 0; - } -} +struct priv { + EGLStreamKHR egl_stream; + GLuint gl_textures[2]; +}; -static void destroy(struct gl_hwdec *hw) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; + struct priv_owner *p = hw->priv; - destroy_objects(hw); - - hwdec_devices_remove(hw->devs, &p->hwctx); + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); if (p->d3d11_device) ID3D11Device_Release(p->d3d11_device); - p->d3d11_device = NULL; } -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { + struct priv_owner *p = hw->priv; + HRESULT hr; + + if (!ra_is_gl(hw->ra)) + return -1; if (!angle_load()) return -1; @@ -108,19 +99,17 @@ static int create(struct gl_hwdec *hw) if (!eglGetCurrentContext()) return -1; + GL *gl = ra_gl_get(hw->ra); + const char *exts = eglQueryString(egl_display, EGL_EXTENSIONS); if (!exts || !strstr(exts, "EGL_ANGLE_d3d_share_handle_client_buffer") || !strstr(exts, "EGL_ANGLE_stream_producer_d3d_texture_nv12") || - !(strstr(hw->gl->extensions, "GL_OES_EGL_image_external_essl3") || - hw->gl->es == 200) || + !(strstr(gl->extensions, "GL_OES_EGL_image_external_essl3") || + gl->es == 200) || !strstr(exts, "EGL_EXT_device_query") || - !(hw->gl->mpgl_caps & MPGL_CAP_TEX_RG)) + !(gl->mpgl_caps & MPGL_CAP_TEX_RG)) return -1; - HRESULT hr; - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - p->egl_display = egl_display; p->CreateStreamKHR = (void *)eglGetProcAddress("eglCreateStreamKHR"); @@ -149,7 +138,7 @@ static int create(struct gl_hwdec *hw) static const char *es2_exts[] = {"GL_NV_EGL_stream_consumer_external", 0}; static const char *es3_exts[] = {"GL_NV_EGL_stream_consumer_external", "GL_OES_EGL_image_external_essl3", 0}; - hw->glsl_extensions = hw->gl->es == 200 ? es2_exts : es3_exts; + hw->glsl_extensions = gl->es == 200 ? es2_exts : es3_exts; PFNEGLQUERYDISPLAYATTRIBEXTPROC p_eglQueryDisplayAttribEXT = (void *)eglGetProcAddress("eglQueryDisplayAttribEXT"); @@ -201,30 +190,44 @@ static int create(struct gl_hwdec *hw) return 0; fail: - destroy(hw); return -1; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *o = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); - destroy_objects(hw); + if (p->egl_stream) + o->DestroyStreamKHR(o->egl_display, p->egl_stream); + p->egl_stream = 0; + + gl->DeleteTextures(2, p->gl_textures); +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *o = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); - if (params->hw_subfmt != IMGFMT_NV12) { - MP_FATAL(hw, "Format not supported.\n"); + if (mapper->src_params.hw_subfmt != IMGFMT_NV12) { + MP_FATAL(mapper, "Format not supported.\n"); return -1; } - // Hope that the given texture unit range is not "in use" by anything. + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = mapper->src_params.hw_subfmt; + mapper->dst_params.hw_subfmt = 0; + // The texture units need to be bound during init only, and are free for // use again after the initialization here is done. int texunits = 0; // [texunits, texunits + num_planes) int num_planes = 2; int gl_target = GL_TEXTURE_EXTERNAL_OES; - p->egl_stream = p->CreateStreamKHR(p->egl_display, (EGLint[]){EGL_NONE}); + p->egl_stream = o->CreateStreamKHR(o->egl_display, (EGLint[]){EGL_NONE}); if (!p->egl_stream) goto fail; @@ -246,17 +249,14 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) EGL_NONE, }; - if (!p->StreamConsumerGLTextureExternalAttribsNV(p->egl_display, p->egl_stream, + if (!o->StreamConsumerGLTextureExternalAttribsNV(o->egl_display, p->egl_stream, attrs)) goto fail; - if (!p->CreateStreamProducerD3DTextureNV12ANGLE(p->egl_display, p->egl_stream, + if (!o->CreateStreamProducerD3DTextureNV12ANGLE(o->egl_display, p->egl_stream, (EGLAttrib[]){EGL_NONE})) goto fail; - params->imgfmt = params->hw_subfmt; - params->hw_subfmt = 0; - for (int n = 0; n < num_planes; n++) { gl->ActiveTexture(GL_TEXTURE0 + texunits + n); gl->BindTexture(gl_target, 0); @@ -264,24 +264,18 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) gl->ActiveTexture(GL_TEXTURE0); return 0; fail: - MP_ERR(hw, "Failed to create EGLStream\n"); - if (p->egl_stream) - p->DestroyStreamKHR(p->egl_display, p->egl_stream); - p->egl_stream = 0; gl->ActiveTexture(GL_TEXTURE0); + MP_ERR(mapper, "Failed to create EGLStream\n"); return -1; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; + struct priv_owner *o = mapper->owner->priv; + struct priv *p = mapper->priv; - if (!p->gl_textures[0]) - return -1; - - ID3D11Texture2D *d3d_tex = (void *)hw_image->planes[0]; - int d3d_subindex = (intptr_t)hw_image->planes[1]; + ID3D11Texture2D *d3d_tex = (void *)mapper->src->planes[0]; + int d3d_subindex = (intptr_t)mapper->src->planes[1]; if (!d3d_tex) return -1; @@ -289,55 +283,68 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, d3d_subindex, EGL_NONE, }; - if (!p->StreamPostD3DTextureNV12ANGLE(p->egl_display, p->egl_stream, + if (!o->StreamPostD3DTextureNV12ANGLE(o->egl_display, p->egl_stream, (void *)d3d_tex, attrs)) { // ANGLE changed the enum ID of this without warning at one point. attrs[0] = attrs[0] == 0x33AB ? 0x3AAB : 0x33AB; - if (!p->StreamPostD3DTextureNV12ANGLE(p->egl_display, p->egl_stream, - (void *)d3d_tex, attrs)) + if (!o->StreamPostD3DTextureNV12ANGLE(o->egl_display, p->egl_stream, + (void *)d3d_tex, attrs)) return -1; } - if (!p->StreamConsumerAcquireKHR(p->egl_display, p->egl_stream)) + if (!o->StreamConsumerAcquireKHR(o->egl_display, p->egl_stream)) return -1; D3D11_TEXTURE2D_DESC texdesc; ID3D11Texture2D_GetDesc(d3d_tex, &texdesc); - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->gl_textures[0], - .gl_target = GL_TEXTURE_EXTERNAL_OES, - .tex_w = texdesc.Width, - .tex_h = texdesc.Height, - }, - { - .gl_texture = p->gl_textures[1], - .gl_target = GL_TEXTURE_EXTERNAL_OES, - .tex_w = texdesc.Width / 2, - .tex_h = texdesc.Height / 2, - }, - }, - }; + for (int n = 0; n < 2; n++) { + struct ra_tex_params params = { + .dimensions = 2, + .w = texdesc.Width / (n ? 2 : 1), + .h = texdesc.Height / (n ? 2 : 1), + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, n ? 2 : 1), + .render_src = true, + .src_linear = true, + .external_oes = true, + }; + if (!params.format) + return -1; + + mapper->tex[n] = ra_create_wrapped_tex(mapper->ra, ¶ms, + p->gl_textures[n]); + if (!mapper->tex[n]) + return -1; + } + return 0; } -static void unmap(struct gl_hwdec *hw) +static void mapper_unmap(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; + struct priv_owner *o = mapper->owner->priv; + struct priv *p = mapper->priv; + + for (int n = 0; n < 2; n++) + ra_tex_free(mapper->ra, &mapper->tex[n]); if (p->egl_stream) - p->StreamConsumerReleaseKHR(p->egl_display, p->egl_stream); + o->StreamConsumerReleaseKHR(o->egl_display, p->egl_stream); } -const struct gl_hwdec_driver gl_hwdec_d3d11egl = { +const struct ra_hwdec_driver ra_hwdec_d3d11egl = { .name = "d3d11-egl", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_D3D11VA, - .imgfmt = IMGFMT_D3D11NV12, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .unmap = unmap, - .destroy = destroy, + .imgfmts = {IMGFMT_D3D11NV12, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/hwdec_d3d11eglrgb.c b/video/out/opengl/hwdec_d3d11eglrgb.c index d1e96cf295..fa3976fec6 100644 --- a/video/out/opengl/hwdec_d3d11eglrgb.c +++ b/video/out/opengl/hwdec_d3d11eglrgb.c @@ -28,6 +28,7 @@ #include "osdep/timer.h" #include "osdep/windows_utils.h" #include "hwdec.h" +#include "ra_gl.h" #include "video/hwdec.h" #include "video/decode/d3d.h" @@ -35,54 +36,38 @@ #define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x3AAB #endif -struct priv { +struct priv_owner { struct mp_hwdec_ctx hwctx; ID3D11Device *d3d11_device; EGLDisplay egl_display; EGLConfig egl_config; - EGLSurface egl_surface; +}; +struct priv { + EGLSurface egl_surface; GLuint gl_texture; }; -static void unmap(struct gl_hwdec *hw) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; - if (p->egl_surface) { - eglReleaseTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER); - eglDestroySurface(p->egl_display, p->egl_surface); - } - p->egl_surface = NULL; -} + struct priv_owner *p = hw->priv; -static void destroy_objects(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - GL *gl = hw->gl; - - unmap(hw); - - gl->DeleteTextures(1, &p->gl_texture); - p->gl_texture = 0; -} - -static void destroy(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - - destroy_objects(hw); - - hwdec_devices_remove(hw->devs, &p->hwctx); + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); if (p->d3d11_device) ID3D11Device_Release(p->d3d11_device); - p->d3d11_device = NULL; } -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { + struct priv_owner *p = hw->priv; + HRESULT hr; + + if (!ra_is_gl(hw->ra)) + return -1; if (!angle_load()) return -1; @@ -99,10 +84,6 @@ static int create(struct gl_hwdec *hw) if (!exts || !strstr(exts, "EGL_ANGLE_d3d_share_handle_client_buffer")) return -1; - HRESULT hr; - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - p->egl_display = egl_display; if (!d3d11_D3D11CreateDevice) { @@ -165,16 +146,21 @@ static int create(struct gl_hwdec *hw) return 0; fail: - destroy(hw); return -1; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); - destroy_objects(hw); + gl->DeleteTextures(1, &p->gl_texture); +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); gl->GenTextures(1, &p->gl_texture); gl->BindTexture(GL_TEXTURE_2D, p->gl_texture); @@ -184,22 +170,35 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl->BindTexture(GL_TEXTURE_2D, 0); - params->imgfmt = IMGFMT_RGB0; - params->hw_subfmt = 0; + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = IMGFMT_RGB0; + mapper->dst_params.hw_subfmt = 0; return 0; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static void mapper_unmap(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *o = mapper->owner->priv; + struct priv *p = mapper->priv; + ra_tex_free(mapper->ra, &mapper->tex[0]); + if (p->egl_surface) { + eglReleaseTexImage(o->egl_display, p->egl_surface, EGL_BACK_BUFFER); + eglDestroySurface(o->egl_display, p->egl_surface); + } + p->egl_surface = NULL; +} + +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *o = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); HRESULT hr; if (!p->gl_texture) return -1; - ID3D11Texture2D *d3d_tex = (void *)hw_image->planes[0]; + ID3D11Texture2D *d3d_tex = (void *)mapper->src->planes[0]; if (!d3d_tex) return -1; @@ -229,37 +228,48 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, EGL_NONE }; p->egl_surface = eglCreatePbufferFromClientBuffer( - p->egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - share_handle, p->egl_config, attrib_list); + o->egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + share_handle, o->egl_config, attrib_list); if (p->egl_surface == EGL_NO_SURFACE) { - MP_ERR(hw, "Failed to create EGL surface\n"); + MP_ERR(mapper, "Failed to create EGL surface\n"); return -1; } gl->BindTexture(GL_TEXTURE_2D, p->gl_texture); - eglBindTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER); + eglBindTexImage(o->egl_display, p->egl_surface, EGL_BACK_BUFFER); gl->BindTexture(GL_TEXTURE_2D, 0); - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->gl_texture, - .gl_target = GL_TEXTURE_2D, - .tex_w = texdesc.Width, - .tex_h = texdesc.Height, - }, - }, + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w, + .h = mapper->src_params.h, + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, 4), + .render_src = true, + .src_linear = true, }; + if (!params.format) + return -1; + + mapper->tex[0] = ra_create_wrapped_tex(mapper->ra, ¶ms, p->gl_texture); + if (!mapper->tex[0]) + return -1; + return 0; } -const struct gl_hwdec_driver gl_hwdec_d3d11eglrgb = { +const struct ra_hwdec_driver ra_hwdec_d3d11eglrgb = { .name = "d3d11-egl-rgb", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_D3D11VA, - .imgfmt = IMGFMT_D3D11RGB, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .unmap = unmap, - .destroy = destroy, + .imgfmts = {IMGFMT_D3D11RGB, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/hwdec_dxva2egl.c b/video/out/opengl/hwdec_dxva2egl.c index c52d7a2166..01fb482325 100644 --- a/video/out/opengl/hwdec_dxva2egl.c +++ b/video/out/opengl/hwdec_dxva2egl.c @@ -28,61 +28,38 @@ #include "osdep/timer.h" #include "osdep/windows_utils.h" #include "hwdec.h" +#include "ra_gl.h" #include "video/hwdec.h" #include "video/decode/d3d.h" -struct priv { +struct priv_owner { struct mp_hwdec_ctx hwctx; - IDirect3D9Ex *d3d9ex; IDirect3DDevice9Ex *device9ex; + + EGLDisplay egl_display; + EGLConfig egl_config; + EGLint alpha; +}; + +struct priv { + IDirect3DDevice9Ex *device9ex; // (no own reference) IDirect3DQuery9 *query9; IDirect3DTexture9 *texture9; IDirect3DSurface9 *surface9; EGLDisplay egl_display; - EGLConfig egl_config; - EGLint alpha; EGLSurface egl_surface; GLuint gl_texture; }; -static void destroy_textures(struct gl_hwdec *hw) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p = hw->priv; - gl->DeleteTextures(1, &p->gl_texture); - p->gl_texture = 0; - - if (p->egl_display && p->egl_surface) { - eglReleaseTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER); - eglDestroySurface(p->egl_display, p->egl_surface); - p->egl_surface = NULL; - } - - if (p->surface9) { - IDirect3DSurface9_Release(p->surface9); - p->surface9 = NULL; - } - - if (p->texture9) { - IDirect3DTexture9_Release(p->texture9); - p->texture9 = NULL; - } -} - -static void destroy(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - - destroy_textures(hw); - - hwdec_devices_remove(hw->devs, &p->hwctx); - - if (p->query9) - IDirect3DQuery9_Release(p->query9); + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); if (p->device9ex) IDirect3DDevice9Ex_Release(p->device9ex); @@ -91,10 +68,13 @@ static void destroy(struct gl_hwdec *hw) IDirect3D9Ex_Release(p->d3d9ex); } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params); - -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { + struct priv_owner *p = hw->priv; + HRESULT hr; + + if (!ra_is_gl(hw->ra)) + return -1; if (!angle_load()) return -1; @@ -113,10 +93,6 @@ static int create(struct gl_hwdec *hw) return -1; } - HRESULT hr; - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - p->egl_display = egl_display; if (!d3d9_dll) { @@ -171,22 +147,6 @@ static int create(struct gl_hwdec *hw) goto fail; } - hr = IDirect3DDevice9_CreateQuery(p->device9ex, D3DQUERYTYPE_EVENT, - &p->query9); - if (FAILED(hr)) { - MP_FATAL(hw, "Failed to create Direct3D query interface: %s\n", - mp_HRESULT_to_str(hr)); - goto fail; - } - - // Test the query API - hr = IDirect3DQuery9_Issue(p->query9, D3DISSUE_END); - if (FAILED(hr)) { - MP_FATAL(hw, "Failed to issue Direct3D END test query: %s\n", - mp_HRESULT_to_str(hr)); - goto fail; - } - EGLint attrs[] = { EGL_BUFFER_SIZE, 32, EGL_RED_SIZE, 8, @@ -209,15 +169,15 @@ static int create(struct gl_hwdec *hw) goto fail; } - struct mp_image_params dummy_params = { .imgfmt = IMGFMT_DXVA2, .w = 256, .h = 256, }; - if (reinit(hw, &dummy_params) < 0) + struct ra_hwdec_mapper *mapper = ra_hwdec_mapper_create(hw, &dummy_params); + if (!mapper) goto fail; - destroy_textures(hw); + ra_hwdec_mapper_free(&mapper); p->hwctx = (struct mp_hwdec_ctx){ .type = HWDEC_DXVA2, @@ -229,51 +189,93 @@ static int create(struct gl_hwdec *hw) return 0; fail: - destroy(hw); return -1; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + + ra_tex_free(mapper->ra, &mapper->tex[0]); + gl->DeleteTextures(1, &p->gl_texture); + + if (p->egl_display && p->egl_surface) { + eglReleaseTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER); + eglDestroySurface(p->egl_display, p->egl_surface); + } + + if (p->surface9) + IDirect3DSurface9_Release(p->surface9); + + if (p->texture9) + IDirect3DTexture9_Release(p->texture9); + + if (p->query9) + IDirect3DQuery9_Release(p->query9); +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); HRESULT hr; - destroy_textures(hw); + p->device9ex = p_owner->device9ex; + p->egl_display = p_owner->egl_display; + + hr = IDirect3DDevice9_CreateQuery(p->device9ex, D3DQUERYTYPE_EVENT, + &p->query9); + if (FAILED(hr)) { + MP_FATAL(mapper, "Failed to create Direct3D query interface: %s\n", + mp_HRESULT_to_str(hr)); + goto fail; + } + + // Test the query API + hr = IDirect3DQuery9_Issue(p->query9, D3DISSUE_END); + if (FAILED(hr)) { + MP_FATAL(mapper, "Failed to issue Direct3D END test query: %s\n", + mp_HRESULT_to_str(hr)); + goto fail; + } HANDLE share_handle = NULL; hr = IDirect3DDevice9Ex_CreateTexture(p->device9ex, - params->w, params->h, + mapper->src_params.w, + mapper->src_params.h, 1, D3DUSAGE_RENDERTARGET, - p->alpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8, + p_owner->alpha ? + D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &p->texture9, &share_handle); if (FAILED(hr)) { - MP_ERR(hw, "Failed to create Direct3D9 texture: %s\n", + MP_ERR(mapper, "Failed to create Direct3D9 texture: %s\n", mp_HRESULT_to_str(hr)); goto fail; } hr = IDirect3DTexture9_GetSurfaceLevel(p->texture9, 0, &p->surface9); if (FAILED(hr)) { - MP_ERR(hw, "Failed to get Direct3D9 surface from texture: %s\n", + MP_ERR(mapper, "Failed to get Direct3D9 surface from texture: %s\n", mp_HRESULT_to_str(hr)); goto fail; } EGLint attrib_list[] = { - EGL_WIDTH, params->w, - EGL_HEIGHT, params->h, - EGL_TEXTURE_FORMAT, p->alpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, + EGL_WIDTH, mapper->src_params.w, + EGL_HEIGHT, mapper->src_params.h, + EGL_TEXTURE_FORMAT, p_owner->alpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_NONE }; p->egl_surface = eglCreatePbufferFromClientBuffer( p->egl_display, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - share_handle, p->egl_config, attrib_list); + share_handle, p_owner->egl_config, attrib_list); if (p->egl_surface == EGL_NO_SURFACE) { - MP_ERR(hw, "Failed to create EGL surface\n"); + MP_ERR(mapper, "Failed to create EGL surface\n"); goto fail; } @@ -285,38 +287,51 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl->BindTexture(GL_TEXTURE_2D, 0); - params->imgfmt = IMGFMT_RGB0; - params->hw_subfmt = 0; + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w, + .h = mapper->src_params.h, + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, p_owner->alpha ? 4 : 3), + .render_src = true, + .src_linear = true, + }; + if (!params.format) + goto fail; + + mapper->tex[0] = ra_create_wrapped_tex(mapper->ra, ¶ms, p->gl_texture); + if (!mapper->tex[0]) + goto fail; + + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = IMGFMT_RGB0; + mapper->dst_params.hw_subfmt = 0; return 0; fail: - destroy_textures(hw); return -1; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; - if (!p->surface9 || !p->egl_surface || !p->gl_texture) - return -1; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); HRESULT hr; - RECT rc = {0, 0, hw_image->w, hw_image->h}; - IDirect3DSurface9* hw_surface = (IDirect3DSurface9 *)hw_image->planes[3]; + RECT rc = {0, 0, mapper->src->w, mapper->src->h}; + IDirect3DSurface9* hw_surface = (IDirect3DSurface9 *)mapper->src->planes[3]; hr = IDirect3DDevice9Ex_StretchRect(p->device9ex, hw_surface, &rc, p->surface9, &rc, D3DTEXF_NONE); if (FAILED(hr)) { - MP_ERR(hw, "Direct3D RGB conversion failed: %s\n", + MP_ERR(mapper, "Direct3D RGB conversion failed: %s\n", mp_HRESULT_to_str(hr)); return -1; } hr = IDirect3DQuery9_Issue(p->query9, D3DISSUE_END); if (FAILED(hr)) { - MP_ERR(hw, "Failed to issue Direct3D END query\n"); + MP_ERR(mapper, "Failed to issue Direct3D END query\n"); return -1; } @@ -329,11 +344,11 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, while (true) { hr = IDirect3DQuery9_GetData(p->query9, NULL, 0, D3DGETDATA_FLUSH); if (FAILED(hr)) { - MP_ERR(hw, "Failed to query Direct3D flush state\n"); + MP_ERR(mapper, "Failed to query Direct3D flush state\n"); return -1; } else if (hr == S_FALSE) { if (++retries > max_retries) { - MP_VERBOSE(hw, "Failed to flush frame after %lld ms\n", + MP_VERBOSE(mapper, "Failed to flush frame after %lld ms\n", (long long)(wait_us * max_retries) / 1000); break; } @@ -347,25 +362,20 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, eglBindTexImage(p->egl_display, p->egl_surface, EGL_BACK_BUFFER); gl->BindTexture(GL_TEXTURE_2D, 0); - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->gl_texture, - .gl_target = GL_TEXTURE_2D, - .tex_w = hw_image->w, - .tex_h = hw_image->h, - }, - }, - }; return 0; } -const struct gl_hwdec_driver gl_hwdec_dxva2egl = { +const struct ra_hwdec_driver ra_hwdec_dxva2egl = { .name = "dxva2-egl", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_DXVA2, - .imgfmt = IMGFMT_DXVA2, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .destroy = destroy, + .imgfmts = {IMGFMT_DXVA2, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + }, }; diff --git a/video/out/opengl/hwdec_dxva2gldx.c b/video/out/opengl/hwdec_dxva2gldx.c index 7e0ea88b51..fd9c80b7a2 100644 --- a/video/out/opengl/hwdec_dxva2gldx.c +++ b/video/out/opengl/hwdec_dxva2gldx.c @@ -21,6 +21,7 @@ #include "common/common.h" #include "osdep/windows_utils.h" #include "hwdec.h" +#include "ra_gl.h" #include "video/hwdec.h" #include "video/decode/d3d.h" @@ -28,67 +29,42 @@ #include <GL/wglext.h> #define SHARED_SURFACE_D3DFMT D3DFMT_X8R8G8B8 -#define SHARED_SURFACE_MPFMT IMGFMT_RGB0 -struct priv { + +struct priv_owner { struct mp_hwdec_ctx hwctx; IDirect3DDevice9Ex *device; HANDLE device_h; +}; +struct priv { + IDirect3DDevice9Ex *device; + HANDLE device_h; IDirect3DSurface9 *rtarget; HANDLE rtarget_h; GLuint texture; }; -static void destroy_objects(struct gl_hwdec *hw) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p = hw->priv; - if (p->rtarget_h && p->device_h) { - if (!gl->DXUnlockObjectsNV(p->device_h, 1, &p->rtarget_h)) { - MP_ERR(hw, "Failed unlocking texture for access by OpenGL: %s\n", - mp_LastError_to_str()); - } - } - - if (p->rtarget_h) { - if (!gl->DXUnregisterObjectNV(p->device_h, p->rtarget_h)) { - MP_ERR(hw, "Failed to unregister Direct3D surface with OpenGL: %s\n", - mp_LastError_to_str()); - } else { - p->rtarget_h = 0; - } - } - - gl->DeleteTextures(1, &p->texture); - p->texture = 0; - - if (p->rtarget) { - IDirect3DSurface9_Release(p->rtarget); - p->rtarget = NULL; - } -} - -static void destroy(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - destroy_objects(hw); - - hwdec_devices_remove(hw->devs, &p->hwctx); + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); if (p->device) IDirect3DDevice9Ex_Release(p->device); } -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { - GL *gl = hw->gl; + struct priv_owner *p = hw->priv; + + if (!ra_is_gl(hw->ra)) + return -1; + GL *gl = ra_gl_get(hw->ra); if (!(gl->mpgl_caps & MPGL_CAP_DXINTEROP)) return -1; - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - // AMD drivers won't open multiple dxinterop HANDLES on the same D3D device, // so we request the one already in use by context_dxinterop p->device_h = mpgl_get_native_display(gl, "dxinterop_device_HANDLE"); @@ -111,31 +87,65 @@ static int create(struct gl_hwdec *hw) return 0; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + + if (p->rtarget_h && p->device_h) { + if (!gl->DXUnlockObjectsNV(p->device_h, 1, &p->rtarget_h)) { + MP_ERR(mapper, "Failed unlocking texture for access by OpenGL: %s\n", + mp_LastError_to_str()); + } + } + + if (p->rtarget_h) { + if (!gl->DXUnregisterObjectNV(p->device_h, p->rtarget_h)) { + MP_ERR(mapper, "Failed to unregister Direct3D surface with OpenGL: %s\n", + mp_LastError_to_str()); + } else { + p->rtarget_h = 0; + } + } + + gl->DeleteTextures(1, &p->texture); + p->texture = 0; + + if (p->rtarget) { + IDirect3DSurface9_Release(p->rtarget); + p->rtarget = NULL; + } + + ra_tex_free(mapper->ra, &mapper->tex[0]); +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); HRESULT hr; - destroy_objects(hw); + p->device = p_owner->device; + p->device_h = p_owner->device_h; HANDLE share_handle = NULL; hr = IDirect3DDevice9Ex_CreateRenderTarget( p->device, - params->w, params->h, + mapper->src_params.w, mapper->src_params.h, SHARED_SURFACE_D3DFMT, D3DMULTISAMPLE_NONE, 0, FALSE, &p->rtarget, &share_handle); if (FAILED(hr)) { - MP_ERR(hw, "Failed creating offscreen Direct3D surface: %s\n", + MP_ERR(mapper, "Failed creating offscreen Direct3D surface: %s\n", mp_HRESULT_to_str(hr)); - goto fail; + return -1; } if (share_handle && !gl->DXSetResourceShareHandleNV(p->rtarget, share_handle)) { - MP_ERR(hw, "Failed setting Direct3D/OpenGL share handle for surface: %s\n", + MP_ERR(mapper, "Failed setting Direct3D/OpenGL share handle for surface: %s\n", mp_LastError_to_str()); - goto fail; + return -1; } gl->GenTextures(1, &p->texture); @@ -150,76 +160,83 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) GL_TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV); if (!p->rtarget_h) { - MP_ERR(hw, "Failed to register Direct3D surface with OpenGL: %s\n", + MP_ERR(mapper, "Failed to register Direct3D surface with OpenGL: %s\n", mp_LastError_to_str()); - goto fail; + return -1; } if (!gl->DXLockObjectsNV(p->device_h, 1, &p->rtarget_h)) { - MP_ERR(hw, "Failed locking texture for access by OpenGL %s\n", + MP_ERR(mapper, "Failed locking texture for access by OpenGL %s\n", mp_LastError_to_str()); - goto fail; + return -1; } - params->imgfmt = SHARED_SURFACE_MPFMT; - params->hw_subfmt = 0; + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w, + .h = mapper->src_params.h, + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, 4), + .render_src = true, + .src_linear = true, + }; + if (!params.format) + return -1; + + mapper->tex[0] = ra_create_wrapped_tex(mapper->ra, ¶ms, p->texture); + if (!mapper->tex[0]) + return -1; + + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = IMGFMT_RGB0; + mapper->dst_params.hw_subfmt = 0; return 0; -fail: - destroy_objects(hw); - return -1; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - assert(hw_image && hw_image->imgfmt == hw->driver->imgfmt); - GL *gl = hw->gl; - struct priv *p = hw->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); HRESULT hr; if (!gl->DXUnlockObjectsNV(p->device_h, 1, &p->rtarget_h)) { - MP_ERR(hw, "Failed unlocking texture for access by OpenGL: %s\n", + MP_ERR(mapper, "Failed unlocking texture for access by OpenGL: %s\n", mp_LastError_to_str()); return -1; } - IDirect3DSurface9* hw_surface = (IDirect3DSurface9 *)hw_image->planes[3]; - RECT rc = {0, 0, hw_image->w, hw_image->h}; + IDirect3DSurface9* hw_surface = (IDirect3DSurface9 *)mapper->src->planes[3]; + RECT rc = {0, 0, mapper->src->w, mapper->src->h}; hr = IDirect3DDevice9Ex_StretchRect(p->device, hw_surface, &rc, p->rtarget, &rc, D3DTEXF_NONE); if (FAILED(hr)) { - MP_ERR(hw, "Direct3D RGB conversion failed: %s", mp_HRESULT_to_str(hr)); + MP_ERR(mapper, "Direct3D RGB conversion failed: %s", mp_HRESULT_to_str(hr)); return -1; } if (!gl->DXLockObjectsNV(p->device_h, 1, &p->rtarget_h)) { - MP_ERR(hw, "Failed locking texture for access by OpenGL: %s\n", + MP_ERR(mapper, "Failed locking texture for access by OpenGL: %s\n", mp_LastError_to_str()); return -1; } - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->texture, - .gl_target = GL_TEXTURE_2D, - .tex_w = hw_image->w, - .tex_h = hw_image->h, - }, - }, - }; return 0; } -const struct gl_hwdec_driver gl_hwdec_dxva2gldx = { +const struct ra_hwdec_driver ra_hwdec_dxva2gldx = { .name = "dxva2-dxinterop", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_DXVA2, - .imgfmt = IMGFMT_DXVA2, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .destroy = destroy, + .imgfmts = {IMGFMT_DXVA2, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + }, }; diff --git a/video/out/opengl/hwdec_ios.m b/video/out/opengl/hwdec_ios.m index 9461f3d980..ec6eb422d6 100644 --- a/video/out/opengl/hwdec_ios.m +++ b/video/out/opengl/hwdec_ios.m @@ -29,21 +29,27 @@ #include "video/mp_image_pool.h" #include "video/vt.h" -#include "formats.h" +#include "ra_gl.h" #include "hwdec.h" -struct priv { +struct priv_owner { struct mp_hwdec_ctx hwctx; +}; +struct priv { CVPixelBufferRef pbuf; CVOpenGLESTextureCacheRef gl_texture_cache; CVOpenGLESTextureRef gl_planes[MP_MAX_PLANES]; - struct gl_imgfmt_desc desc; + struct ra_imgfmt_desc desc; }; -static bool check_hwdec(struct gl_hwdec *hw) +static bool check_hwdec(struct ra_hwdec *hw) { - if (hw->gl->es < 200) { + if (!ra_is_gl(hw->ra)) + return false; + + GL *gl = ra_gl_get(hw->ra); + if (gl->es < 200) { MP_ERR(hw, "need OpenGLES 2.0 for CVOpenGLESTextureCacheCreateTextureFromImage()\n"); return false; } @@ -56,25 +62,12 @@ static bool check_hwdec(struct gl_hwdec *hw) return true; } -static int create_hwdec(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { - if (!check_hwdec(hw)) - return -1; - - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - - CVReturn err = CVOpenGLESTextureCacheCreate( - kCFAllocatorDefault, - NULL, - [EAGLContext currentContext], - NULL, - &p->gl_texture_cache); + struct priv_owner *p = hw->priv; - if (err != noErr) { - MP_ERR(hw, "Failure in CVOpenGLESTextureCacheCreate: %d\n", err); + if (!check_hwdec(hw)) return -1; - } p->hwctx = (struct mp_hwdec_ctx){ .type = HWDEC_VIDEOTOOLBOX, @@ -92,32 +85,98 @@ static int create_hwdec(struct gl_hwdec *hw) return 0; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void uninit(struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); + av_buffer_unref(&p->hwctx.av_device_ref); +} + +// In GLES3 mode, CVOpenGLESTextureCacheCreateTextureFromImage() +// will return error -6683 unless invoked with GL_LUMINANCE and +// GL_LUMINANCE_ALPHA (http://stackoverflow.com/q/36213994/332798) +// If a format trues to use GL_RED/GL_RG instead, try to find a format +// that uses GL_LUMINANCE[_ALPHA] instead. +static const struct ra_format *find_la_variant(struct ra *ra, + const struct ra_format *fmt) +{ + GLint internal_format; + GLenum format; + GLenum type; + ra_gl_get_format(fmt, &internal_format, &format, &type); + + if (format == GL_RED) { + format = internal_format = GL_LUMINANCE; + } else if (format == GL_RG) { + format = internal_format = GL_LUMINANCE_ALPHA; + } else { + return fmt; + } + + for (int n = 0; n < ra->num_formats; n++) { + const struct ra_format *fmt2 = ra->formats[n]; + GLint internal_format2; + GLenum format2; + GLenum type2; + ra_gl_get_format(fmt2, &internal_format2, &format2, &type2); + if (internal_format2 == internal_format && + format2 == format && type2 == type) + return fmt2; + } + + return NULL; +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - assert(params->imgfmt == hw->driver->imgfmt); + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); - if (!params->hw_subfmt) { - MP_ERR(hw, "Unsupported CVPixelBuffer format.\n"); + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = mapper->src_params.hw_subfmt; + mapper->dst_params.hw_subfmt = 0; + + if (!mapper->dst_params.imgfmt) { + MP_ERR(mapper, "Unsupported CVPixelBuffer format.\n"); return -1; } - if (!gl_get_imgfmt_desc(hw->gl, params->hw_subfmt, &p->desc)) { - MP_ERR(hw, "Unsupported texture format.\n"); + if (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &p->desc)) { + MP_ERR(mapper, "Unsupported texture format.\n"); + return -1; + } + + for (int n = 0; n < p->desc.num_planes; n++) { + p->desc.planes[n] = find_la_variant(mapper->ra, p->desc.planes[n]); + if (!p->desc.planes[n] || p->desc.planes[n]->ctype != RA_CTYPE_UNORM) { + MP_ERR(mapper, "Format unsupported.\n"); + return -1; + } + } + + CVReturn err = CVOpenGLESTextureCacheCreate( + kCFAllocatorDefault, + NULL, + [EAGLContext currentContext], + NULL, + &p->gl_texture_cache); + + if (err != noErr) { + MP_ERR(mapper, "Failure in CVOpenGLESTextureCacheCreate: %d\n", err); return -1; } - params->imgfmt = params->hw_subfmt; - params->hw_subfmt = 0; return 0; } -static void cleanup_textures(struct gl_hwdec *hw) +static void mapper_unmap(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - int i; + struct priv *p = mapper->priv; - for (i = 0; i < MP_MAX_PLANES; i++) { + for (int i = 0; i < p->desc.num_planes; i++) { + ra_tex_free(mapper->ra, &mapper->tex[i]); if (p->gl_planes[i]) { CFRelease(p->gl_planes[i]); p->gl_planes[i] = NULL; @@ -127,37 +186,26 @@ static void cleanup_textures(struct gl_hwdec *hw) CVOpenGLESTextureCacheFlush(p->gl_texture_cache, 0); } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(hw->ra); CVPixelBufferRelease(p->pbuf); - p->pbuf = (CVPixelBufferRef)hw_image->planes[3]; + p->pbuf = (CVPixelBufferRef)mapper->src->planes[3]; CVPixelBufferRetain(p->pbuf); const bool planar = CVPixelBufferIsPlanar(p->pbuf); const int planes = CVPixelBufferGetPlaneCount(p->pbuf); assert((planar && planes == p->desc.num_planes) || p->desc.num_planes == 1); - cleanup_textures(hw); - for (int i = 0; i < p->desc.num_planes; i++) { - const struct gl_format *fmt = p->desc.planes[i]; - GLenum format = fmt->format; - GLenum internal_format = fmt->internal_format; - - if (hw->gl->es >= 300) { - // In GLES3 mode, CVOpenGLESTextureCacheCreateTextureFromImage() - // will return error -6683 unless invoked with GL_LUMINANCE and - // GL_LUMINANCE_ALPHA (http://stackoverflow.com/q/36213994/332798) - if (format == GL_RED) { - format = internal_format = GL_LUMINANCE; - } else if (format == GL_RG) { - format = internal_format = GL_LUMINANCE_ALPHA; - } - } + const struct ra_format *fmt = p->desc.planes[i]; + + GLint internal_format; + GLenum format; + GLenum type; + ra_gl_get_format(fmt, &internal_format, &format, &type); CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage( kCFAllocatorDefault, @@ -169,12 +217,12 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, CVPixelBufferGetWidthOfPlane(p->pbuf, i), CVPixelBufferGetHeightOfPlane(p->pbuf, i), format, - fmt->type, + type, i, &p->gl_planes[i]); if (err != noErr) { - MP_ERR(hw, "error creating texture for plane %d: %d\n", i, err); + MP_ERR(mapper, "error creating texture for plane %d: %d\n", i, err); return -1; } @@ -185,39 +233,46 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl->BindTexture(GL_TEXTURE_2D, 0); - out_frame->planes[i] = (struct gl_hwdec_plane){ - .gl_texture = CVOpenGLESTextureGetName(p->gl_planes[i]), - .gl_target = GL_TEXTURE_2D, - .gl_format = format, - .tex_w = CVPixelBufferGetWidthOfPlane(p->pbuf, i), - .tex_h = CVPixelBufferGetHeightOfPlane(p->pbuf, i), + struct ra_tex_params params = { + .dimensions = 2, + .w = CVPixelBufferGetWidthOfPlane(p->pbuf, i), + .h = CVPixelBufferGetHeightOfPlane(p->pbuf, i), + .d = 1, + .format = fmt, + .render_src = true, + .src_linear = true, }; + + mapper->tex[i] = ra_create_wrapped_tex(mapper->ra, ¶ms, + p->gl_planes[i]); + if (!mapper->tex[i]) + return -1; } return 0; } -static void destroy(struct gl_hwdec *hw) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - - cleanup_textures(hw); + struct priv *p = mapper->priv; CVPixelBufferRelease(p->pbuf); CFRelease(p->gl_texture_cache); p->gl_texture_cache = NULL; - - av_buffer_unref(&p->hwctx.av_device_ref); - - hwdec_devices_remove(hw->devs, &p->hwctx); } -const struct gl_hwdec_driver gl_hwdec_videotoolbox = { +const struct ra_hwdec_driver ra_hwdec_videotoolbox = { .name = "videotoolbox", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_VIDEOTOOLBOX, - .imgfmt = IMGFMT_VIDEOTOOLBOX, - .create = create_hwdec, - .reinit = reinit, - .map_frame = map_frame, - .destroy = destroy, + .imgfmts = {IMGFMT_VIDEOTOOLBOX, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/hwdec_osx.c b/video/out/opengl/hwdec_osx.c index 81cd155cc5..348a5e19c5 100644 --- a/video/out/opengl/hwdec_osx.c +++ b/video/out/opengl/hwdec_osx.c @@ -30,21 +30,27 @@ #include "video/mp_image_pool.h" #include "video/vt.h" -#include "formats.h" +#include "ra_gl.h" #include "hwdec.h" -struct priv { +struct priv_owner { struct mp_hwdec_ctx hwctx; +}; +struct priv { CVPixelBufferRef pbuf; GLuint gl_planes[MP_MAX_PLANES]; - struct gl_imgfmt_desc desc; + struct ra_imgfmt_desc desc; }; -static bool check_hwdec(struct gl_hwdec *hw) +static bool check_hwdec(struct ra_hwdec *hw) { - if (hw->gl->version < 300) { + if (!ra_is_gl(hw->ra)) + return false; + + GL *gl = ra_gl_get(hw->ra); + if (gl->version < 300) { MP_ERR(hw, "need >= OpenGL 3.0 for core rectangle texture support\n"); return false; } @@ -57,16 +63,13 @@ static bool check_hwdec(struct gl_hwdec *hw) return true; } -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { + struct priv_owner *p = hw->priv; + if (!check_hwdec(hw)) return -1; - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - - hw->gl->GenTextures(MP_MAX_PLANES, p->gl_planes); - p->hwctx = (struct mp_hwdec_ctx){ .type = HWDEC_VIDEOTOOLBOX, .download_image = mp_vt_download_image, @@ -83,39 +86,68 @@ static int create(struct gl_hwdec *hw) return 0; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; + struct priv_owner *p = hw->priv; - assert(params->imgfmt == hw->driver->imgfmt); + if (p->hwctx.ctx) + hwdec_devices_remove(hw->devs, &p->hwctx); + av_buffer_unref(&p->hwctx.av_device_ref); +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); - if (!params->hw_subfmt) { - MP_ERR(hw, "Unsupported CVPixelBuffer format.\n"); + gl->GenTextures(MP_MAX_PLANES, p->gl_planes); + + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = mapper->src_params.hw_subfmt; + mapper->dst_params.hw_subfmt = 0; + + if (!mapper->dst_params.imgfmt) { + MP_ERR(mapper, "Unsupported CVPixelBuffer format.\n"); return -1; } - if (!gl_get_imgfmt_desc(hw->gl, params->hw_subfmt, &p->desc)) { - MP_ERR(hw, "Unsupported texture format.\n"); + if (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &p->desc)) { + MP_ERR(mapper, "Unsupported texture format.\n"); return -1; } - params->imgfmt = params->hw_subfmt; - params->hw_subfmt = 0; + for (int n = 0; n < p->desc.num_planes; n++) { + if (p->desc.planes[n]->ctype != RA_CTYPE_UNORM) { + MP_ERR(mapper, "Format unsupported.\n"); + return -1; + } + } return 0; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static void mapper_unmap(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + // Is this sane? No idea how to release the texture without deleting it. CVPixelBufferRelease(p->pbuf); - p->pbuf = (CVPixelBufferRef)hw_image->planes[3]; + p->pbuf = NULL; + + for (int i = 0; i < p->desc.num_planes; i++) + ra_tex_free(mapper->ra, &mapper->tex[i]); +} + +static int mapper_map(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + + CVPixelBufferRelease(p->pbuf); + p->pbuf = (CVPixelBufferRef)mapper->src->planes[3]; CVPixelBufferRetain(p->pbuf); IOSurfaceRef surface = CVPixelBufferGetIOSurface(p->pbuf); if (!surface) { - MP_ERR(hw, "CVPixelBuffer has no IOSurface\n"); + MP_ERR(mapper, "CVPixelBuffer has no IOSurface\n"); return -1; } @@ -126,53 +158,71 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, GLenum gl_target = GL_TEXTURE_RECTANGLE; for (int i = 0; i < p->desc.num_planes; i++) { - const struct gl_format *fmt = p->desc.planes[i]; + const struct ra_format *fmt = p->desc.planes[i]; + + GLint internal_format; + GLenum format; + GLenum type; + ra_gl_get_format(fmt, &internal_format, &format, &type); gl->BindTexture(gl_target, p->gl_planes[i]); CGLError err = CGLTexImageIOSurface2D( CGLGetCurrentContext(), gl_target, - fmt->internal_format, + internal_format, IOSurfaceGetWidthOfPlane(surface, i), IOSurfaceGetHeightOfPlane(surface, i), - fmt->format, fmt->type, surface, i); - - if (err != kCGLNoError) - MP_ERR(hw, "error creating IOSurface texture for plane %d: %s (%x)\n", - i, CGLErrorString(err), gl->GetError()); + format, type, surface, i); gl->BindTexture(gl_target, 0); - out_frame->planes[i] = (struct gl_hwdec_plane){ - .gl_texture = p->gl_planes[i], - .gl_target = gl_target, - .tex_w = IOSurfaceGetWidthOfPlane(surface, i), - .tex_h = IOSurfaceGetHeightOfPlane(surface, i), + if (err != kCGLNoError) { + MP_ERR(mapper, + "error creating IOSurface texture for plane %d: %s (%x)\n", + i, CGLErrorString(err), gl->GetError()); + return -1; + } + + struct ra_tex_params params = { + .dimensions = 2, + .w = IOSurfaceGetWidthOfPlane(surface, i), + .h = IOSurfaceGetHeightOfPlane(surface, i), + .d = 1, + .format = fmt, + .render_src = true, + .src_linear = true, + .non_normalized = gl_target == GL_TEXTURE_RECTANGLE, }; + + mapper->tex[i] = ra_create_wrapped_tex(mapper->ra, ¶ms, + p->gl_planes[i]); + if (!mapper->tex[i]) + return -1; } return 0; } -static void destroy(struct gl_hwdec *hw) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); - CVPixelBufferRelease(p->pbuf); gl->DeleteTextures(MP_MAX_PLANES, p->gl_planes); - - av_buffer_unref(&p->hwctx.av_device_ref); - - hwdec_devices_remove(hw->devs, &p->hwctx); } -const struct gl_hwdec_driver gl_hwdec_videotoolbox = { +const struct ra_hwdec_driver ra_hwdec_videotoolbox = { .name = "videotoolbox", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_VIDEOTOOLBOX, - .imgfmt = IMGFMT_VIDEOTOOLBOX, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .destroy = destroy, + .imgfmts = {IMGFMT_VIDEOTOOLBOX, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/hwdec_rpi.c b/video/out/opengl/hwdec_rpi.c index daa1a9a54c..72270b5787 100644 --- a/video/out/opengl/hwdec_rpi.c +++ b/video/out/opengl/hwdec_rpi.c @@ -103,7 +103,7 @@ static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) talloc_free(mpi); } -static void disable_renderer(struct gl_hwdec *hw) +static void disable_renderer(struct ra_hwdec *hw) { struct priv *p = hw->priv; @@ -122,7 +122,7 @@ static void disable_renderer(struct gl_hwdec *hw) } // check_window_only: assume params and dst/src rc are unchanged -static void update_overlay(struct gl_hwdec *hw, bool check_window_only) +static void update_overlay(struct ra_hwdec *hw, bool check_window_only) { struct priv *p = hw->priv; GL *gl = hw->gl; @@ -183,7 +183,7 @@ static void update_overlay(struct gl_hwdec *hw, bool check_window_only) MP_WARN(p, "could not set video rectangle\n"); } -static int enable_renderer(struct gl_hwdec *hw) +static int enable_renderer(struct ra_hwdec *hw) { struct priv *p = hw->priv; MMAL_PORT_T *input = p->renderer->input[0]; @@ -244,29 +244,13 @@ static int enable_renderer(struct gl_hwdec *hw) return 0; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) -{ - struct priv *p = hw->priv; - - p->params = *params; - - *params = (struct mp_image_params){0}; - - disable_renderer(hw); - - if (enable_renderer(hw) < 0) - return -1; - - return 0; -} - static void free_mmal_buffer(void *arg) { MMAL_BUFFER_HEADER_T *buffer = arg; mmal_buffer_header_release(buffer); } -static struct mp_image *upload(struct gl_hwdec *hw, struct mp_image *hw_image) +static struct mp_image *upload(struct ra_hwdec *hw, struct mp_image *hw_image) { struct priv *p = hw->priv; @@ -295,11 +279,21 @@ static struct mp_image *upload(struct gl_hwdec *hw, struct mp_image *hw_image) return new_ref; } -static int overlay_frame(struct gl_hwdec *hw, struct mp_image *hw_image, +static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image, struct mp_rect *src, struct mp_rect *dst, bool newframe) { struct priv *p = hw->priv; + if (hw_image && !mp_image_params_equal(&p->params, &hw_image->params)) { + p->params = *params; + + disable_renderer(hw); + mp_image_unrefp(&p->current_frame); + + if (enable_renderer(hw) < 0) + return -1; + } + if (hw_image && p->current_frame && !newframe) { if (!mp_rect_equals(&p->src, src) ||mp_rect_equals(&p->dst, dst)) { p->src = *src; @@ -347,7 +341,7 @@ static int overlay_frame(struct gl_hwdec *hw, struct mp_image *hw_image, return 0; } -static void destroy(struct gl_hwdec *hw) +static void destroy(struct ra_hwdec *hw) { struct priv *p = hw->priv; @@ -359,10 +353,9 @@ static void destroy(struct gl_hwdec *hw) mmal_vc_deinit(); } -static int create(struct gl_hwdec *hw) +static int create(struct ra_hwdec *hw) { - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; + struct priv *p = hw->priv; p->log = hw->log; bcm_host_init(); @@ -382,18 +375,13 @@ static int create(struct gl_hwdec *hw) return 0; } -static bool test_format(struct gl_hwdec *hw, int imgfmt) -{ - return imgfmt == IMGFMT_MMAL || imgfmt == IMGFMT_420P; -} - -const struct gl_hwdec_driver gl_hwdec_rpi_overlay = { +const struct ra_hwdec_driver ra_hwdec_rpi_overlay = { .name = "rpi-overlay", .api = HWDEC_RPI, - .test_format = test_format, - .create = create, - .reinit = reinit, + .priv_size = sizeof(struct priv), + .imgfmts = {IMGFMT_MMAL, IMGFMT_420P, 0}, + .init = create, .overlay_frame = overlay_frame, .overlay_adjust = overlay_adjust, - .destroy = destroy, + .uninit = destroy, }; diff --git a/video/out/opengl/hwdec_vaegl.c b/video/out/opengl/hwdec_vaegl.c index 8306541586..a0e3222cfc 100644 --- a/video/out/opengl/hwdec_vaegl.c +++ b/video/out/opengl/hwdec_vaegl.c @@ -34,7 +34,7 @@ #include "video/vaapi.h" #include "video/mp_image_pool.h" #include "common.h" -#include "formats.h" +#include "ra_gl.h" #ifndef GL_OES_EGL_image typedef void* GLeglImageOES; @@ -113,17 +113,20 @@ static VADisplay *create_native_va_display(GL *gl, struct mp_log *log) return NULL; } -struct priv { - struct mp_log *log; +struct priv_owner { struct mp_vaapi_ctx *ctx; VADisplay *display; + int *formats; + bool probing_formats; // temporary during init +}; + +struct priv { + int num_planes; + struct ra_tex *tex[4]; GLuint gl_textures[4]; EGLImageKHR images[4]; VAImage current_image; bool buffer_acquired; - int current_mpfmt; - int *formats; - bool probing_formats; // temporary during init EGLImageKHR (EGLAPIENTRY *CreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, @@ -132,111 +135,58 @@ struct priv { void (EGLAPIENTRY *EGLImageTargetTexture2DOES)(GLenum, GLeglImageOES); }; -static void determine_working_formats(struct gl_hwdec *hw); - -static void unmap_frame(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - VAStatus status; - - for (int n = 0; n < 4; n++) { - if (p->images[n]) - p->DestroyImageKHR(eglGetCurrentDisplay(), p->images[n]); - p->images[n] = 0; - } - - if (p->buffer_acquired) { - status = vaReleaseBufferHandle(p->display, p->current_image.buf); - CHECK_VA_STATUS(p, "vaReleaseBufferHandle()"); - p->buffer_acquired = false; - } - if (p->current_image.image_id != VA_INVALID_ID) { - status = vaDestroyImage(p->display, p->current_image.image_id); - CHECK_VA_STATUS(p, "vaDestroyImage()"); - p->current_image.image_id = VA_INVALID_ID; - } -} - -static void destroy_textures(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - GL *gl = hw->gl; +static void determine_working_formats(struct ra_hwdec *hw); - gl->DeleteTextures(4, p->gl_textures); - for (int n = 0; n < 4; n++) - p->gl_textures[n] = 0; -} - -static void destroy(struct gl_hwdec *hw) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; - unmap_frame(hw); - destroy_textures(hw); + struct priv_owner *p = hw->priv; if (p->ctx) hwdec_devices_remove(hw->devs, &p->ctx->hwctx); va_destroy(p->ctx); } -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { - GL *gl = hw->gl; - - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - p->current_image.buf = p->current_image.image_id = VA_INVALID_ID; - p->log = hw->log; + struct priv_owner *p = hw->priv; - if (!eglGetCurrentContext()) + if (!ra_is_gl(hw->ra) || !eglGetCurrentContext()) return -1; const char *exts = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS); if (!exts) return -1; + GL *gl = ra_gl_get(hw->ra); if (!strstr(exts, "EXT_image_dma_buf_import") || !strstr(exts, "EGL_KHR_image_base") || !strstr(gl->extensions, "GL_OES_EGL_image") || !(gl->mpgl_caps & MPGL_CAP_TEX_RG)) return -1; - // EGL_KHR_image_base - p->CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"); - p->DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"); - // GL_OES_EGL_image - p->EGLImageTargetTexture2DOES = - (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"); - - if (!p->CreateImageKHR || !p->DestroyImageKHR || - !p->EGLImageTargetTexture2DOES) - return -1; - p->display = create_native_va_display(gl, hw->log); if (!p->display) { MP_VERBOSE(hw, "Could not create a VA display.\n"); return -1; } - p->ctx = va_initialize(p->display, p->log, true); + p->ctx = va_initialize(p->display, hw->log, true); if (!p->ctx) { vaTerminate(p->display); return -1; } if (!p->ctx->av_device_ref) { MP_VERBOSE(hw, "libavutil vaapi code rejected the driver?\n"); - destroy(hw); return -1; } if (hw->probing && va_guess_if_emulated(p->ctx)) { - destroy(hw); return -1; } - MP_VERBOSE(p, "using VAAPI EGL interop\n"); + MP_VERBOSE(hw, "using VAAPI EGL interop\n"); determine_working_formats(hw); if (!p->formats || !p->formats[0]) { - destroy(hw); return -1; } @@ -246,43 +196,119 @@ static int create(struct gl_hwdec *hw) return 0; } -static bool check_fmt(struct priv *p, int fmt) +static void mapper_unmap(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + VADisplay *display = p_owner->display; + struct priv *p = mapper->priv; + VAStatus status; + + for (int n = 0; n < 4; n++) { + if (p->images[n]) + p->DestroyImageKHR(eglGetCurrentDisplay(), p->images[n]); + p->images[n] = 0; + } + + if (p->buffer_acquired) { + status = vaReleaseBufferHandle(display, p->current_image.buf); + CHECK_VA_STATUS(mapper, "vaReleaseBufferHandle()"); + p->buffer_acquired = false; + } + if (p->current_image.image_id != VA_INVALID_ID) { + status = vaDestroyImage(display, p->current_image.image_id); + CHECK_VA_STATUS(mapper, "vaDestroyImage()"); + p->current_image.image_id = VA_INVALID_ID; + } +} + +static void mapper_uninit(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + + gl->DeleteTextures(4, p->gl_textures); + for (int n = 0; n < 4; n++) { + p->gl_textures[n] = 0; + ra_tex_free(mapper->ra, &p->tex[n]); + } +} + +static bool check_fmt(struct ra_hwdec_mapper *mapper, int fmt) { - for (int n = 0; p->formats[n]; n++) { - if (p->formats[n] == fmt) + struct priv_owner *p_owner = mapper->owner->priv; + for (int n = 0; p_owner->formats && p_owner->formats[n]; n++) { + if (p_owner->formats[n] == fmt) return true; } return false; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static int mapper_init(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + + p->current_image.buf = p->current_image.image_id = VA_INVALID_ID; + + // EGL_KHR_image_base + p->CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"); + p->DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"); + // GL_OES_EGL_image + p->EGLImageTargetTexture2DOES = + (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"); - // Recreate them to get rid of all previous image data (possibly). - destroy_textures(hw); + if (!p->CreateImageKHR || !p->DestroyImageKHR || + !p->EGLImageTargetTexture2DOES) + return -1; + + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = mapper->src_params.hw_subfmt; + mapper->dst_params.hw_subfmt = 0; + + struct ra_imgfmt_desc desc = {0}; + struct mp_image layout = {0}; + + if (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &desc)) + return -1; + + p->num_planes = desc.num_planes; + mp_image_set_params(&layout, &mapper->dst_params); gl->GenTextures(4, p->gl_textures); - for (int n = 0; n < 4; n++) { + for (int n = 0; n < desc.num_planes; n++) { gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - gl->BindTexture(GL_TEXTURE_2D, 0); + gl->BindTexture(GL_TEXTURE_2D, 0); + + struct ra_tex_params params = { + .dimensions = 2, + .w = mp_image_plane_w(&layout, n), + .h = mp_image_plane_h(&layout, n), + .d = 1, + .format = desc.planes[n], + .render_src = true, + .src_linear = true, + }; - p->current_mpfmt = params->hw_subfmt; + if (params.format->ctype != RA_CTYPE_UNORM) + return -1; - if (!p->probing_formats && !check_fmt(p, p->current_mpfmt)) { - MP_FATAL(p, "unsupported VA image format %s\n", - mp_imgfmt_to_name(p->current_mpfmt)); - return -1; + p->tex[n] = ra_create_wrapped_tex(mapper->ra, ¶ms, + p->gl_textures[n]); + if (!p->tex[n]) + return -1; } - params->imgfmt = p->current_mpfmt; - params->hw_subfmt = 0; + if (!p_owner->probing_formats && !check_fmt(mapper, mapper->dst_params.imgfmt)) + { + MP_FATAL(mapper, "unsupported VA image format %s\n", + mp_imgfmt_to_name(mapper->dst_params.imgfmt)); + return -1; + } return 0; } @@ -295,34 +321,25 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) attribs[num_attribs] = EGL_NONE; \ } while(0) -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); VAStatus status; VAImage *va_image = &p->current_image; + VADisplay *display = p_owner->display; - unmap_frame(hw); - - status = vaDeriveImage(p->display, va_surface_id(hw_image), va_image); - if (!CHECK_VA_STATUS(p, "vaDeriveImage()")) + status = vaDeriveImage(display, va_surface_id(mapper->src), va_image); + if (!CHECK_VA_STATUS(mapper, "vaDeriveImage()")) goto err; VABufferInfo buffer_info = {.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME}; - status = vaAcquireBufferHandle(p->display, va_image->buf, &buffer_info); - if (!CHECK_VA_STATUS(p, "vaAcquireBufferHandle()")) + status = vaAcquireBufferHandle(display, va_image->buf, &buffer_info); + if (!CHECK_VA_STATUS(mapper, "vaAcquireBufferHandle()")) goto err; p->buffer_acquired = true; - struct mp_image layout = {0}; - mp_image_set_params(&layout, &hw_image->params); - mp_image_setfmt(&layout, p->current_mpfmt); - - struct gl_imgfmt_desc desc; - if (!gl_get_imgfmt_desc(gl, p->current_mpfmt, &desc)) - goto err; - int drm_fmts[8] = { // 1 bytes per component, 1-4 components MKTAG('R', '8', ' ', ' '), // DRM_FORMAT_R8 @@ -336,18 +353,13 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, 0, // N/A }; - for (int n = 0; n < layout.num_planes; n++) { + for (int n = 0; n < p->num_planes; n++) { int attribs[20] = {EGL_NONE}; int num_attribs = 0; - const struct gl_format *fmt = desc.planes[n]; - if (gl_format_type(fmt) != MPGL_TYPE_UNORM) - goto err; - - int n_comp = gl_format_components(fmt->format); - int comp_s = gl_component_size(fmt->type); - if (!gl_format_is_regular(fmt)) - goto err; + const struct ra_format *fmt = p->tex[n]->params.format; + int n_comp = fmt->num_components; + int comp_s = fmt->component_size[n] / 8; if (n_comp < 1 || n_comp > 3 || comp_s < 1 || comp_s > 2) goto err; int drm_fmt = drm_fmts[n_comp - 1 + (comp_s - 1) * 4]; @@ -355,8 +367,8 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, goto err; ADD_ATTRIB(EGL_LINUX_DRM_FOURCC_EXT, drm_fmt); - ADD_ATTRIB(EGL_WIDTH, mp_image_plane_w(&layout, n)); - ADD_ATTRIB(EGL_HEIGHT, mp_image_plane_h(&layout, n)); + ADD_ATTRIB(EGL_WIDTH, p->tex[n]->params.w); + ADD_ATTRIB(EGL_HEIGHT, p->tex[n]->params.h); ADD_ATTRIB(EGL_DMA_BUF_PLANE0_FD_EXT, buffer_info.handle); ADD_ATTRIB(EGL_DMA_BUF_PLANE0_OFFSET_EXT, va_image->offsets[n]); ADD_ATTRIB(EGL_DMA_BUF_PLANE0_PITCH_EXT, va_image->pitches[n]); @@ -369,42 +381,34 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); p->EGLImageTargetTexture2DOES(GL_TEXTURE_2D, p->images[n]); - out_frame->planes[n] = (struct gl_hwdec_plane){ - .gl_texture = p->gl_textures[n], - .gl_target = GL_TEXTURE_2D, - .tex_w = mp_image_plane_w(&layout, n), - .tex_h = mp_image_plane_h(&layout, n), - }; + mapper->tex[n] = p->tex[n]; } gl->BindTexture(GL_TEXTURE_2D, 0); if (va_image->format.fourcc == VA_FOURCC_YV12) - MPSWAP(struct gl_hwdec_plane, out_frame->planes[1], out_frame->planes[2]); + MPSWAP(struct ra_tex*, mapper->tex[1], mapper->tex[2]); return 0; err: - if (!p->probing_formats) - MP_FATAL(p, "mapping VAAPI EGL image failed\n"); - unmap_frame(hw); + if (!p_owner->probing_formats) + MP_FATAL(mapper, "mapping VAAPI EGL image failed\n"); return -1; } -static bool try_format(struct gl_hwdec *hw, struct mp_image *surface) +static bool try_format(struct ra_hwdec *hw, struct mp_image *surface) { bool ok = false; - struct mp_image_params params = surface->params; - if (reinit(hw, ¶ms) >= 0) { - struct gl_hwdec_frame frame = {0}; - ok = map_frame(hw, surface, &frame) >= 0; - } - unmap_frame(hw); + struct ra_hwdec_mapper *mapper = ra_hwdec_mapper_create(hw, &surface->params); + if (mapper) + ok = ra_hwdec_mapper_map(mapper, surface) >= 0; + ra_hwdec_mapper_free(&mapper); return ok; } -static void determine_working_formats(struct gl_hwdec *hw) +static void determine_working_formats(struct ra_hwdec *hw) { - struct priv *p = hw->priv; + struct priv_owner *p = hw->priv; int num_formats = 0; int *formats = NULL; @@ -457,13 +461,18 @@ done: MP_VERBOSE(hw, " %s\n", mp_imgfmt_to_name(formats[n])); } -const struct gl_hwdec_driver gl_hwdec_vaegl = { +const struct ra_hwdec_driver ra_hwdec_vaegl = { .name = "vaapi-egl", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_VAAPI, - .imgfmt = IMGFMT_VAAPI, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .unmap = unmap_frame, - .destroy = destroy, + .imgfmts = {IMGFMT_VAAPI, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/hwdec_vaglx.c b/video/out/opengl/hwdec_vaglx.c index fb75b48d06..8db15c4468 100644 --- a/video/out/opengl/hwdec_vaglx.c +++ b/video/out/opengl/hwdec_vaglx.c @@ -25,73 +25,48 @@ #include <va/va_x11.h> #include "video/out/x11_common.h" +#include "ra_gl.h" #include "hwdec.h" #include "video/vaapi.h" -struct priv { - struct mp_log *log; +struct priv_owner { struct mp_vaapi_ctx *ctx; VADisplay *display; Display *xdisplay; - GLuint gl_texture; GLXFBConfig fbc; +}; + +struct priv { + GLuint gl_texture; Pixmap pixmap; GLXPixmap glxpixmap; void (*glXBindTexImage)(Display *dpy, GLXDrawable draw, int buffer, int *a); void (*glXReleaseTexImage)(Display *dpy, GLXDrawable draw, int buffer); }; -static void destroy_texture(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - GL *gl = hw->gl; - - if (p->glxpixmap) { - p->glXReleaseTexImage(p->xdisplay, p->glxpixmap, GLX_FRONT_EXT); - glXDestroyPixmap(p->xdisplay, p->glxpixmap); - } - p->glxpixmap = 0; - - if (p->pixmap) - XFreePixmap(p->xdisplay, p->pixmap); - p->pixmap = 0; - - gl->DeleteTextures(1, &p->gl_texture); - p->gl_texture = 0; -} - -static void destroy(struct gl_hwdec *hw) +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; - destroy_texture(hw); + struct priv_owner *p = hw->priv; if (p->ctx) hwdec_devices_remove(hw->devs, &p->ctx->hwctx); va_destroy(p->ctx); } -static int create(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) { Display *x11disp = glXGetCurrentDisplay(); - if (!x11disp) + if (!x11disp || !ra_is_gl(hw->ra)) return -1; int x11scr = DefaultScreen(x11disp); - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - p->log = hw->log; + struct priv_owner *p = hw->priv; p->xdisplay = x11disp; const char *glxext = glXQueryExtensionsString(x11disp, x11scr); if (!glxext || !strstr(glxext, "GLX_EXT_texture_from_pixmap")) return -1; - p->glXBindTexImage = - (void*)glXGetProcAddressARB((void*)"glXBindTexImageEXT"); - p->glXReleaseTexImage = - (void*)glXGetProcAddressARB((void*)"glXReleaseTexImageEXT"); - if (!p->glXBindTexImage || !p->glXReleaseTexImage) - return -1; p->display = vaGetDisplay(x11disp); if (!p->display) return -1; - p->ctx = va_initialize(p->display, p->log, true); + p->ctx = va_initialize(p->display, hw->log, true); if (!p->ctx) { vaTerminate(p->display); return -1; @@ -117,8 +92,7 @@ static int create(struct gl_hwdec *hw) if (fbc) XFree(fbc); if (!fbcount) { - MP_VERBOSE(p, "No texture-from-pixmap support.\n"); - destroy(hw); + MP_VERBOSE(hw, "No texture-from-pixmap support.\n"); return -1; } @@ -127,12 +101,19 @@ static int create(struct gl_hwdec *hw) return 0; } -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) +static int mapper_init(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + Display *xdisplay = p_owner->xdisplay; - destroy_texture(hw); + p->glXBindTexImage = + (void*)glXGetProcAddressARB((void*)"glXBindTexImageEXT"); + p->glXReleaseTexImage = + (void*)glXGetProcAddressARB((void*)"glXReleaseTexImageEXT"); + if (!p->glXBindTexImage || !p->glXReleaseTexImage) + return -1; gl->GenTextures(1, &p->gl_texture); gl->BindTexture(GL_TEXTURE_2D, p->gl_texture); @@ -142,11 +123,11 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl->BindTexture(GL_TEXTURE_2D, 0); - p->pixmap = XCreatePixmap(p->xdisplay, - RootWindow(p->xdisplay, DefaultScreen(p->xdisplay)), - params->w, params->h, 24); + p->pixmap = XCreatePixmap(xdisplay, + RootWindow(xdisplay, DefaultScreen(xdisplay)), + mapper->src_params.w, mapper->src_params.h, 24); if (!p->pixmap) { - MP_FATAL(hw, "could not create pixmap\n"); + MP_FATAL(mapper, "could not create pixmap\n"); return -1; } @@ -156,54 +137,90 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) GLX_MIPMAP_TEXTURE_EXT, False, None, }; - p->glxpixmap = glXCreatePixmap(p->xdisplay, p->fbc, p->pixmap, attribs); + p->glxpixmap = glXCreatePixmap(xdisplay, p_owner->fbc, p->pixmap, attribs); gl->BindTexture(GL_TEXTURE_2D, p->gl_texture); - p->glXBindTexImage(p->xdisplay, p->glxpixmap, GLX_FRONT_EXT, NULL); + p->glXBindTexImage(xdisplay, p->glxpixmap, GLX_FRONT_EXT, NULL); gl->BindTexture(GL_TEXTURE_2D, 0); - params->imgfmt = IMGFMT_RGB0; - params->hw_subfmt = 0; + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w, + .h = mapper->src_params.h, + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, 4), // unsure + .render_src = true, + .src_linear = true, + }; + if (!params.format) + return -1; + + mapper->tex[0] = ra_create_wrapped_tex(mapper->ra, ¶ms, p->gl_texture); + if (!mapper->tex[0]) + return -1; + + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = IMGFMT_RGB0; + mapper->dst_params.hw_subfmt = 0; return 0; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + Display *xdisplay = p_owner->xdisplay; + + if (p->glxpixmap) { + p->glXReleaseTexImage(xdisplay, p->glxpixmap, GLX_FRONT_EXT); + glXDestroyPixmap(xdisplay, p->glxpixmap); + } + p->glxpixmap = 0; + + if (p->pixmap) + XFreePixmap(xdisplay, p->pixmap); + p->pixmap = 0; + + ra_tex_free(mapper->ra, &mapper->tex[0]); + gl->DeleteTextures(1, &p->gl_texture); + p->gl_texture = 0; +} + +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; VAStatus status; + struct mp_image *hw_image = mapper->src; + if (!p->pixmap) return -1; - status = vaPutSurface(p->display, va_surface_id(hw_image), p->pixmap, + status = vaPutSurface(p_owner->display, va_surface_id(hw_image), p->pixmap, 0, 0, hw_image->w, hw_image->h, 0, 0, hw_image->w, hw_image->h, NULL, 0, va_get_colorspace_flag(hw_image->params.color.space)); - CHECK_VA_STATUS(p, "vaPutSurface()"); - - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->gl_texture, - .gl_target = GL_TEXTURE_2D, - .tex_w = hw_image->w, - .tex_h = hw_image->h, - }, - }, - }; + CHECK_VA_STATUS(mapper, "vaPutSurface()"); + return 0; } -const struct gl_hwdec_driver gl_hwdec_vaglx = { +const struct ra_hwdec_driver ra_hwdec_vaglx = { .name = "vaapi-glx", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_VAAPI, - .imgfmt = IMGFMT_VAAPI, + .imgfmts = {IMGFMT_VAAPI, 0}, .testing_only = true, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .destroy = destroy, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + }, }; diff --git a/video/out/opengl/hwdec_vdpau.c b/video/out/opengl/hwdec_vdpau.c index 9ddec18e06..8f09d549e7 100644 --- a/video/out/opengl/hwdec_vdpau.c +++ b/video/out/opengl/hwdec_vdpau.c @@ -21,7 +21,7 @@ #include <GL/glx.h> #include "hwdec.h" -#include "gl_utils.h" +#include "ra_gl.h" #include "video/vdpau.h" #include "video/vdpau_mixer.h" @@ -29,13 +29,14 @@ // follow it. I'm not sure about the original nvidia headers. #define BRAINDEATH(x) ((void *)(uintptr_t)(x)) -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params); +struct priv_owner { + struct mp_vdpau_ctx *ctx; +}; struct priv { - struct mp_log *log; struct mp_vdpau_ctx *ctx; + GL *gl; uint64_t preemption_counter; - struct mp_image_params image_params; GLuint gl_textures[4]; bool vdpgl_initialized; GLvdpauSurfaceNV vdpgl_surface; @@ -45,10 +46,40 @@ struct priv { bool mapped; }; -static void unmap(struct gl_hwdec *hw) +static int init(struct ra_hwdec *hw) +{ + Display *x11disp = glXGetCurrentDisplay(); + if (!x11disp || !ra_is_gl(hw->ra)) + return -1; + GL *gl = ra_gl_get(hw->ra); + if (!(gl->mpgl_caps & MPGL_CAP_VDPAU)) + return -1; + struct priv_owner *p = hw->priv; + p->ctx = mp_vdpau_create_device_x11(hw->log, x11disp, true); + if (!p->ctx) + return -1; + if (mp_vdpau_handle_preemption(p->ctx, NULL) < 1) + return -1; + if (hw->probing && mp_vdpau_guess_if_emulated(p->ctx)) + return -1; + p->ctx->hwctx.driver_name = hw->driver->name; + hwdec_devices_add(hw->devs, &p->ctx->hwctx); + return 0; +} + +static void uninit(struct ra_hwdec *hw) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv_owner *p = hw->priv; + + if (p->ctx) + hwdec_devices_remove(hw->devs, &p->ctx->hwctx); + mp_vdpau_destroy(p->ctx); +} + +static void mapper_unmap(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + GL *gl = p->gl; if (p->mapped) { gl->VDPAUUnmapSurfacesNV(1, &p->vdpgl_surface); @@ -60,96 +91,69 @@ static void unmap(struct gl_hwdec *hw) p->mapped = false; } -static void mark_vdpau_objects_uninitialized(struct gl_hwdec *hw) +static void mark_vdpau_objects_uninitialized(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; + struct priv *p = mapper->priv; p->vdp_surface = VDP_INVALID_HANDLE; p->mapped = false; } -static void destroy_objects(struct gl_hwdec *hw) +static void mapper_uninit(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + GL *gl = p->gl; struct vdp_functions *vdp = &p->ctx->vdp; VdpStatus vdp_st; - unmap(hw); + assert(!p->mapped); if (p->vdpgl_surface) gl->VDPAUUnregisterSurfaceNV(p->vdpgl_surface); p->vdpgl_surface = 0; - glDeleteTextures(4, p->gl_textures); - for (int n = 0; n < 4; n++) + gl->DeleteTextures(4, p->gl_textures); + for (int n = 0; n < 4; n++) { p->gl_textures[n] = 0; + ra_tex_free(mapper->ra, &mapper->tex[n]); + } if (p->vdp_surface != VDP_INVALID_HANDLE) { vdp_st = vdp->output_surface_destroy(p->vdp_surface); - CHECK_VDP_WARNING(p, "Error when calling vdp_output_surface_destroy"); + CHECK_VDP_WARNING(mapper, "Error when calling vdp_output_surface_destroy"); } p->vdp_surface = VDP_INVALID_HANDLE; - gl_check_error(gl, hw->log, "Before uninitializing OpenGL interop"); + gl_check_error(gl, mapper->log, "Before uninitializing OpenGL interop"); if (p->vdpgl_initialized) gl->VDPAUFiniNV(); p->vdpgl_initialized = false; - gl_check_error(gl, hw->log, "After uninitializing OpenGL interop"); -} + gl_check_error(gl, mapper->log, "After uninitializing OpenGL interop"); -static void destroy(struct gl_hwdec *hw) -{ - struct priv *p = hw->priv; - - destroy_objects(hw); mp_vdpau_mixer_destroy(p->mixer); - if (p->ctx) - hwdec_devices_remove(hw->devs, &p->ctx->hwctx); - mp_vdpau_destroy(p->ctx); } -static int create(struct gl_hwdec *hw) +static int mapper_init(struct ra_hwdec_mapper *mapper) { - GL *gl = hw->gl; - Display *x11disp = glXGetCurrentDisplay(); - if (!x11disp) - return -1; - if (!(gl->mpgl_caps & MPGL_CAP_VDPAU)) - return -1; - struct priv *p = talloc_zero(hw, struct priv); - hw->priv = p; - p->log = hw->log; - p->ctx = mp_vdpau_create_device_x11(hw->log, x11disp, true); - if (!p->ctx) - return -1; - if (mp_vdpau_handle_preemption(p->ctx, &p->preemption_counter) < 1) - return -1; - p->vdp_surface = VDP_INVALID_HANDLE; - p->mixer = mp_vdpau_mixer_create(p->ctx, hw->log); - if (hw->probing && mp_vdpau_guess_if_emulated(p->ctx)) { - destroy(hw); - return -1; - } - p->ctx->hwctx.driver_name = hw->driver->name; - hwdec_devices_add(hw->devs, &p->ctx->hwctx); - return 0; -} + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; -static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) -{ - struct priv *p = hw->priv; - GL *gl = hw->gl; + p->gl = ra_gl_get(mapper->ra); + p->ctx = p_owner->ctx; + + GL *gl = p->gl; struct vdp_functions *vdp = &p->ctx->vdp; VdpStatus vdp_st; - destroy_objects(hw); + p->vdp_surface = VDP_INVALID_HANDLE; + p->mixer = mp_vdpau_mixer_create(p->ctx, mapper->log); + if (!p->mixer) + return -1; - assert(params->imgfmt == hw->driver->imgfmt); - p->image_params = *params; + mapper->dst_params = mapper->src_params; if (mp_vdpau_handle_preemption(p->ctx, &p->preemption_counter) < 0) return -1; @@ -158,28 +162,73 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) p->vdpgl_initialized = true; - p->direct_mode = params->hw_subfmt == IMGFMT_NV12 || - params->hw_subfmt == IMGFMT_420P; + p->direct_mode = mapper->dst_params.hw_subfmt == IMGFMT_NV12 || + mapper->dst_params.hw_subfmt == IMGFMT_420P; + mapper->vdpau_fields = p->direct_mode; gl->GenTextures(4, p->gl_textures); - for (int n = 0; n < 4; n++) { - gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); - GLenum filter = p->direct_mode ? GL_NEAREST : GL_LINEAR; - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - gl->BindTexture(GL_TEXTURE_2D, 0); if (p->direct_mode) { - params->imgfmt = IMGFMT_NV12; - params->hw_subfmt = 0; + mapper->dst_params.imgfmt = IMGFMT_NV12; + mapper->dst_params.hw_subfmt = 0; + + for (int n = 0; n < 4; n++) { + gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl->BindTexture(GL_TEXTURE_2D, 0); + + bool chroma = n >= 2; + + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w / (chroma ? 2 : 1), + .h = mapper->src_params.h / (chroma ? 4 : 2), + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, chroma ? 2 : 1), + .render_src = true, + }; + + if (!params.format) + return -1; + + mapper->tex[n] = + ra_create_wrapped_tex(mapper->ra, ¶ms, p->gl_textures[n]); + if (!mapper->tex[n]) + return -1; + } } else { + gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[0]); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl->BindTexture(GL_TEXTURE_2D, 0); + + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w, + .h = mapper->src_params.h, + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, 4), + .render_src = true, + .src_linear = true, + }; + + if (!params.format) + return -1; + + mapper->tex[0] = + ra_create_wrapped_tex(mapper->ra, ¶ms, p->gl_textures[0]); + if (!mapper->tex[0]) + return -1; + vdp_st = vdp->output_surface_create(p->ctx->vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, - params->w, params->h, &p->vdp_surface); - CHECK_VDP_ERROR(p, "Error when calling vdp_output_surface_create"); + params.w, params.h, &p->vdp_surface); + CHECK_VDP_ERROR(mapper, "Error when calling vdp_output_surface_create"); p->vdpgl_surface = gl->VDPAURegisterOutputSurfaceNV(BRAINDEATH(p->vdp_surface), GL_TEXTURE_2D, @@ -189,41 +238,40 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) gl->VDPAUSurfaceAccessNV(p->vdpgl_surface, GL_READ_ONLY); - params->imgfmt = IMGFMT_RGB0; - params->hw_subfmt = 0; + mapper->dst_params.imgfmt = IMGFMT_RGB0; + mapper->dst_params.hw_subfmt = 0; } - gl_check_error(gl, hw->log, "After initializing vdpau OpenGL interop"); + gl_check_error(gl, mapper->log, "After initializing vdpau OpenGL interop"); return 0; } -static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, - struct gl_hwdec_frame *out_frame) +static int mapper_map(struct ra_hwdec_mapper *mapper) { - struct priv *p = hw->priv; - GL *gl = hw->gl; + struct priv *p = mapper->priv; + GL *gl = p->gl; struct vdp_functions *vdp = &p->ctx->vdp; VdpStatus vdp_st; int pe = mp_vdpau_handle_preemption(p->ctx, &p->preemption_counter); if (pe < 1) { - mark_vdpau_objects_uninitialized(hw); + mark_vdpau_objects_uninitialized(mapper); if (pe < 0) return -1; - struct mp_image_params params = p->image_params; - if (reinit(hw, ¶ms) < 0) + mapper_uninit(mapper); + if (mapper_init(mapper) < 0) return -1; } if (p->direct_mode) { - VdpVideoSurface surface = (intptr_t)hw_image->planes[3]; + VdpVideoSurface surface = (intptr_t)mapper->src->planes[3]; // We need the uncropped size. VdpChromaType s_chroma_type; uint32_t s_w, s_h; vdp_st = vdp->video_surface_get_parameters(surface, &s_chroma_type, &s_w, &s_h); - CHECK_VDP_ERROR(hw, "Error when calling vdp_video_surface_get_parameters"); + CHECK_VDP_ERROR(mapper, "Error when calling vdp_video_surface_get_parameters"); p->vdpgl_surface = gl->VDPAURegisterVideoSurfaceNV(BRAINDEATH(surface), GL_TEXTURE_2D, @@ -235,49 +283,33 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, gl->VDPAUMapSurfacesNV(1, &p->vdpgl_surface); p->mapped = true; - *out_frame = (struct gl_hwdec_frame){ - .vdpau_fields = true, - }; - for (int n = 0; n < 4; n++) { - bool chroma = n >= 2; - out_frame->planes[n] = (struct gl_hwdec_plane){ - .gl_texture = p->gl_textures[n], - .gl_target = GL_TEXTURE_2D, - .tex_w = s_w / (chroma ? 2 : 1), - .tex_h = s_h / (chroma ? 4 : 2), - }; - }; } else { if (!p->vdpgl_surface) return -1; - mp_vdpau_mixer_render(p->mixer, NULL, p->vdp_surface, NULL, hw_image, NULL); + mp_vdpau_mixer_render(p->mixer, NULL, p->vdp_surface, NULL, mapper->src, + NULL); gl->VDPAUMapSurfacesNV(1, &p->vdpgl_surface); p->mapped = true; - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->gl_textures[0], - .gl_target = GL_TEXTURE_2D, - .tex_w = p->image_params.w, - .tex_h = p->image_params.h, - }, - }, - }; } return 0; } -const struct gl_hwdec_driver gl_hwdec_vdpau = { +const struct ra_hwdec_driver ra_hwdec_vdpau = { .name = "vdpau-glx", + .priv_size = sizeof(struct priv_owner), .api = HWDEC_VDPAU, - .imgfmt = IMGFMT_VDPAU, - .create = create, - .reinit = reinit, - .map_frame = map_frame, - .unmap = unmap, - .destroy = destroy, + .imgfmts = {IMGFMT_VDPAU, 0}, + .init = init, + .uninit = uninit, + .mapper = &(const struct ra_hwdec_mapper_driver){ + .priv_size = sizeof(struct priv), + .init = mapper_init, + .uninit = mapper_uninit, + .map = mapper_map, + .unmap = mapper_unmap, + }, }; diff --git a/video/out/opengl/ra_gl.c b/video/out/opengl/ra_gl.c index 18689abe05..78dde1091d 100644 --- a/video/out/opengl/ra_gl.c +++ b/video/out/opengl/ra_gl.c @@ -159,17 +159,15 @@ static void gl_tex_destroy(struct ra *ra, struct ra_tex *tex) talloc_free(tex); } -static struct ra_tex *gl_tex_create(struct ra *ra, - const struct ra_tex_params *params) +static struct ra_tex *gl_tex_create_blank(struct ra *ra, + const struct ra_tex_params *params) { - GL *gl = ra_gl_get(ra); - struct ra_tex *tex = talloc_zero(NULL, struct ra_tex); tex->params = *params; + tex->params.initial_data = NULL; struct ra_tex_gl *tex_gl = tex->priv = talloc_zero(NULL, struct ra_tex_gl); const struct gl_format *fmt = params->format->priv; - tex_gl->own_objects = true; tex_gl->internal_format = fmt->internal_format; tex_gl->format = fmt->format; tex_gl->type = fmt->type; @@ -183,6 +181,24 @@ static struct ra_tex *gl_tex_create(struct ra *ra, assert(params->dimensions == 2); tex_gl->target = GL_TEXTURE_RECTANGLE; } + if (params->external_oes) { + assert(params->dimensions == 2 && !params->non_normalized); + tex_gl->target = GL_TEXTURE_EXTERNAL_OES; + } + + return tex; +} + +static struct ra_tex *gl_tex_create(struct ra *ra, + const struct ra_tex_params *params) +{ + GL *gl = ra_gl_get(ra); + struct ra_tex *tex = gl_tex_create_blank(ra, params); + if (!tex) + return NULL; + struct ra_tex_gl *tex_gl = tex->priv; + + tex_gl->own_objects = true; gl->GenTextures(1, &tex_gl->texture); gl->BindTexture(tex_gl->target, tex_gl->texture); @@ -218,8 +234,6 @@ static struct ra_tex *gl_tex_create(struct ra *ra, gl->BindTexture(tex_gl->target, 0); - tex->params.initial_data = NULL; - gl_check_error(gl, ra->log, "after creating texture"); if (tex->params.render_dst) { @@ -253,6 +267,22 @@ static struct ra_tex *gl_tex_create(struct ra *ra, return tex; } +// Create a ra_tex that merely wraps an existing texture. The returned object +// is freed with ra_tex_free(), but this will not delete the texture passed to +// this function. +// Some features are unsupported, e.g. setting params->initial_data or render_dst. +struct ra_tex *ra_create_wrapped_tex(struct ra *ra, + const struct ra_tex_params *params, + GLuint gl_texture) +{ + struct ra_tex *tex = gl_tex_create_blank(ra, params); + if (!tex) + return NULL; + struct ra_tex_gl *tex_gl = tex->priv; + tex_gl->texture = gl_texture; + return tex; +} + static const struct ra_format fbo_dummy_format = { .name = "unknown_fbo", .priv = (void *)&(const struct gl_format){ @@ -263,98 +293,63 @@ static const struct ra_format fbo_dummy_format = { .renderable = true, }; -static const struct ra_format tex_dummy_format = { - .name = "unknown_tex", - .priv = (void *)&(const struct gl_format){ - .name = "unknown", - .format = GL_RGBA, - .flags = F_TF, - }, - .renderable = true, - .linear_filter = true, -}; - -static const struct ra_format *find_similar_format(struct ra *ra, - GLint gl_iformat, - GLenum gl_format, - GLenum gl_type) -{ - if (gl_iformat || gl_format || gl_type) { - for (int n = 0; n < ra->num_formats; n++) { - const struct ra_format *fmt = ra->formats[n]; - const struct gl_format *gl_fmt = fmt->priv; - if ((gl_fmt->internal_format == gl_iformat || !gl_iformat) && - (gl_fmt->format == gl_format || !gl_format) && - (gl_fmt->type == gl_type || !gl_type)) - return fmt; - } - } - return NULL; -} - -static struct ra_tex *wrap_tex_fbo(struct ra *ra, GLuint gl_obj, bool is_fbo, - GLenum gl_target, GLint gl_iformat, - GLenum gl_format, GLenum gl_type, - int w, int h) +// Create a ra_tex that merely wraps an existing framebuffer. gl_fbo can be 0 +// to wrap the default framebuffer. +// The returned object is freed with ra_tex_free(), but this will not delete +// the framebuffer object passed to this function. +struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h) { - const struct ra_format *format = - find_similar_format(ra, gl_iformat, gl_format, gl_type); - if (!format) - format = is_fbo ? &fbo_dummy_format : &tex_dummy_format; - struct ra_tex *tex = talloc_zero(ra, struct ra_tex); *tex = (struct ra_tex){ .params = { .dimensions = 2, .w = w, .h = h, .d = 1, - .format = format, - .render_dst = is_fbo, - .render_src = !is_fbo, - .non_normalized = gl_target == GL_TEXTURE_RECTANGLE, - .external_oes = gl_target == GL_TEXTURE_EXTERNAL_OES, + .format = &fbo_dummy_format, + .render_dst = true, }, }; struct ra_tex_gl *tex_gl = tex->priv = talloc_zero(NULL, struct ra_tex_gl); *tex_gl = (struct ra_tex_gl){ - .target = gl_target, - .texture = is_fbo ? 0 : gl_obj, - .fbo = is_fbo ? gl_obj : 0, - .internal_format = gl_iformat, - .format = gl_format, - .type = gl_type, + .fbo = gl_fbo, + .internal_format = 0, + .format = GL_RGBA, + .type = 0, }; return tex; } -// Create a ra_tex that merely wraps an existing texture. gl_format and gl_type -// can be 0, in which case possibly nonsensical fallbacks are chosen. -// Works for 2D textures only. Integer textures are not supported. -// The returned object is freed with ra_tex_free(), but this will not delete -// the texture passed to this function. -struct ra_tex *ra_create_wrapped_texture(struct ra *ra, GLuint gl_texture, - GLenum gl_target, GLint gl_iformat, - GLenum gl_format, GLenum gl_type, - int w, int h) +GL *ra_gl_get(struct ra *ra) { - return wrap_tex_fbo(ra, gl_texture, false, gl_target, gl_iformat, gl_format, - gl_type, w, h); + struct ra_gl *p = ra->priv; + return p->gl; } -// Create a ra_tex that merely wraps an existing framebuffer. gl_fbo can be 0 -// to wrap the default framebuffer. -// The returned object is freed with ra_tex_free(), but this will not delete -// the framebuffer object passed to this function. -struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h) +// Return the associate glTexImage arguments for the given format. Sets all +// fields to 0 on failure. +void ra_gl_get_format(const struct ra_format *fmt, GLint *out_internal_format, + GLenum *out_format, GLenum *out_type) { - return wrap_tex_fbo(ra, gl_fbo, true, 0, GL_RGBA, 0, 0, w, h); + const struct gl_format *gl_format = fmt->priv; + *out_internal_format = gl_format->internal_format; + *out_format = gl_format->format; + *out_type = gl_format->type; } -GL *ra_gl_get(struct ra *ra) +void ra_gl_get_raw_tex(struct ra *ra, struct ra_tex *tex, + GLuint *out_texture, GLenum *out_target) { - struct ra_gl *p = ra->priv; - return p->gl; + struct ra_tex_gl *tex_gl = tex->priv; + *out_texture = tex_gl->texture; + *out_target = tex_gl->target; +} + +// Return whether the ra instance was created with ra_create_gl(). This is the +// _only_ function that can be called on a ra instance of any type. +bool ra_is_gl(struct ra *ra) +{ + return ra->fns == &ra_fns_gl; } static void gl_tex_upload(struct ra *ra, struct ra_tex *tex, diff --git a/video/out/opengl/ra_gl.h b/video/out/opengl/ra_gl.h index 3b6202cbfb..8707b423dd 100644 --- a/video/out/opengl/ra_gl.h +++ b/video/out/opengl/ra_gl.h @@ -40,10 +40,14 @@ struct ra_renderpass_gl { }; struct ra *ra_create_gl(GL *gl, struct mp_log *log); -struct ra_tex *ra_create_wrapped_texture(struct ra *ra, GLuint gl_texture, - GLenum gl_target, GLint gl_iformat, - GLenum gl_format, GLenum gl_type, - int w, int h); +struct ra_tex *ra_create_wrapped_tex(struct ra *ra, + const struct ra_tex_params *params, + GLuint gl_texture); struct ra_tex *ra_create_wrapped_fb(struct ra *ra, GLuint gl_fbo, int w, int h); GL *ra_gl_get(struct ra *ra); void ra_gl_set_debug(struct ra *ra, bool enable); +void ra_gl_get_format(const struct ra_format *fmt, GLint *out_internal_format, + GLenum *out_format, GLenum *out_type); +void ra_gl_get_raw_tex(struct ra *ra, struct ra_tex *tex, + GLuint *out_texture, GLenum *out_target); +bool ra_is_gl(struct ra *ra); diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 8ed21d4380..d118fe928d 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -96,8 +96,6 @@ struct video_image { struct mp_image *mpi; // original input image uint64_t id; // unique ID identifying mpi contents bool hwdec_mapped; - // Temporary wrappers for GL hwdec textures. - struct ra_tex *hwdec_tex[4]; }; enum plane_type { @@ -287,7 +285,8 @@ struct gl_video { struct cached_file *files; int num_files; - struct gl_hwdec *hwdec; + struct ra_hwdec *hwdec; + struct ra_hwdec_mapper *hwdec_mapper; bool hwdec_active; bool dsi_warned; @@ -804,12 +803,14 @@ static int find_comp(struct ra_imgfmt_desc *desc, int component) static void init_video(struct gl_video *p) { - p->hwdec_active = false; p->use_integer_conversion = false; - if (p->hwdec && gl_hwdec_test_format(p->hwdec, p->image_params.imgfmt)) { - if (p->hwdec->driver->reinit(p->hwdec, &p->image_params) < 0) + if (p->hwdec && ra_hwdec_test_format(p->hwdec, p->image_params.imgfmt)) { + p->hwdec_mapper = ra_hwdec_mapper_create(p->hwdec, &p->image_params); + if (!p->hwdec_mapper) MP_ERR(p, "Initializing texture for hardware decoding failed.\n"); + if (p->hwdec_mapper) + p->image_params = p->hwdec_mapper->dst_params; const char **exts = p->hwdec->glsl_extensions; for (int n = 0; exts && exts[n]; n++) gl_sc_enable_extension(p->sc, (char *)exts[n]); @@ -906,11 +907,8 @@ static void unmap_current_image(struct gl_video *p) struct video_image *vimg = &p->image; if (vimg->hwdec_mapped) { - assert(p->hwdec_active); - for (int n = 0; n < 4; n++) - ra_tex_free(p->ra, &vimg->hwdec_tex[n]); - if (p->hwdec->driver->unmap) - p->hwdec->driver->unmap(p->hwdec); + assert(p->hwdec_active && p->hwdec_mapper); + ra_hwdec_mapper_unmap(p->hwdec_mapper); memset(vimg->planes, 0, sizeof(vimg->planes)); vimg->hwdec_mapped = false; vimg->id = 0; // needs to be mapped again @@ -997,6 +995,7 @@ static void uninit_video(struct gl_video *p) p->real_image_params = (struct mp_image_params){0}; p->image_params = p->real_image_params; p->hwdec_active = false; + ra_hwdec_mapper_free(&p->hwdec_mapper); } static void pass_record(struct gl_video *p, struct mp_pass_perf perf) @@ -1228,6 +1227,8 @@ static void finish_pass_fbo(struct gl_video *p, struct fbotex *dst_fbo, static const char *get_tex_swizzle(struct img_tex *img) { + if (!img->tex) + return "rgba"; return img->tex->params.format->luminance_alpha ? "raaa" : "rgba"; } @@ -3155,23 +3156,19 @@ void gl_video_perfdata(struct gl_video *p, struct voctrl_performance_data *out) } // This assumes nv12, with textures set to GL_NEAREST filtering. -static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame, - struct ra_tex *output[4]) +static void reinterleave_vdpau(struct gl_video *p, + struct ra_tex *input[4], struct ra_tex *output[2]) { - struct gl_hwdec_frame res = {0}; for (int n = 0; n < 2; n++) { struct fbotex *fbo = &p->vdpau_deinterleave_fbo[n]; // This is an array of the 2 to-merge planes. - struct gl_hwdec_plane *src = &frame->planes[n * 2]; - int w = src[0].tex_w; - int h = src[0].tex_h; + struct ra_tex **src = &input[n * 2]; + int w = src[0]->params.w; + int h = src[0]->params.h; int ids[2]; - struct ra_tex *tmp[2]; for (int t = 0; t < 2; t++) { - tmp[t] = ra_create_wrapped_texture(p->ra, src[t].gl_texture, - GL_TEXTURE_2D, 0, 0, 0, w, h); ids[t] = pass_bind(p, (struct img_tex){ - .tex = tmp[t], + .tex = src[t], .multiplier = 1.0, .transform = identity_trans, .w = w, @@ -3190,12 +3187,8 @@ static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame, pass_describe(p, "vdpau reinterleaving"); finish_pass_direct(p, fbo->fbo, &(struct mp_rect){0, 0, w, h * 2}); - for (int t = 0; t < 2; t++) - ra_tex_free(p->ra, &tmp[t]); - output[n] = fbo->tex; } - *frame = res; } // Returns false on failure. @@ -3219,11 +3212,13 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t if (p->hwdec_active) { // Hardware decoding - struct gl_hwdec_frame gl_frame = {0}; + + if (!p->hwdec_mapper) + goto error; pass_describe(p, "map frame (hwdec)"); timer_pool_start(p->upload_timer); - bool ok = p->hwdec->driver->map_frame(p->hwdec, vimg->mpi, &gl_frame) >= 0; + bool ok = ra_hwdec_mapper_map(p->hwdec_mapper, vimg->mpi) >= 0; timer_pool_stop(p->upload_timer); pass_record(p, timer_pool_measure(p->upload_timer)); @@ -3231,20 +3226,17 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t if (ok) { struct mp_image layout = {0}; mp_image_set_params(&layout, &p->image_params); - struct ra_tex *tex[4] = {0}; - if (gl_frame.vdpau_fields) - reinterleave_vdpau(p, &gl_frame, tex); + struct ra_tex **tex = p->hwdec_mapper->tex; + struct ra_tex *tmp[4] = {0}; + if (p->hwdec_mapper->vdpau_fields) { + reinterleave_vdpau(p, tex, tmp); + tex = tmp; + } for (int n = 0; n < p->plane_count; n++) { - struct gl_hwdec_plane *plane = &gl_frame.planes[n]; - if (!tex[n]) { - vimg->hwdec_tex[n] = ra_create_wrapped_texture(p->ra, - plane->gl_texture, plane->gl_target, 0, - plane->gl_format, 0, plane->tex_w, plane->tex_h); - } vimg->planes[n] = (struct texplane){ .w = mp_image_plane_w(&layout, n), .h = mp_image_plane_h(&layout, n), - .tex = tex[n] ? tex[n] : vimg->hwdec_tex[n], + .tex = tex[n], }; } } else { @@ -3528,7 +3520,7 @@ bool gl_video_check_format(struct gl_video *p, int mp_format) if (ra_get_imgfmt_desc(p->ra, mp_format, &desc) && is_imgfmt_desc_supported(p, &desc)) return true; - if (p->hwdec && gl_hwdec_test_format(p->hwdec, mp_format)) + if (p->hwdec && ra_hwdec_test_format(p->hwdec, mp_format)) return true; return false; } @@ -3743,10 +3735,11 @@ void gl_video_set_ambient_lux(struct gl_video *p, int lux) } } -void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec) +void gl_video_set_hwdec(struct gl_video *p, struct ra_hwdec *hwdec) { - p->hwdec = hwdec; unref_current_image(p); + ra_hwdec_mapper_free(&p->hwdec_mapper); + p->hwdec = hwdec; } void *gl_video_dr_alloc_buffer(struct gl_video *p, size_t size) diff --git a/video/out/opengl/video.h b/video/out/opengl/video.h index db5837b12b..a71f5d6b3d 100644 --- a/video/out/opengl/video.h +++ b/video/out/opengl/video.h @@ -179,8 +179,8 @@ struct mp_colorspace gl_video_get_output_colorspace(struct gl_video *p); void gl_video_reset(struct gl_video *p); bool gl_video_showing_interpolated_frame(struct gl_video *p); -struct gl_hwdec; -void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec); +struct ra_hwdec; +void gl_video_set_hwdec(struct gl_video *p, struct ra_hwdec *hwdec); struct vo; void gl_video_configure_queue(struct gl_video *p, struct vo *vo); diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index e70fbafa5f..5e8a3c7110 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -72,7 +72,7 @@ struct gl_priv { struct gl_video *renderer; - struct gl_hwdec *hwdec; + struct ra_hwdec *hwdec; int events; @@ -210,7 +210,7 @@ static void request_hwdec_api(struct vo *vo, void *api) if (p->hwdec) return; - p->hwdec = gl_hwdec_load_api(p->vo->log, p->gl, p->vo->global, + p->hwdec = ra_hwdec_load_api(p->vo->log, p->ra, p->vo->global, vo->hwdec_devs, (intptr_t)api); gl_video_set_hwdec(p->renderer, p->hwdec); } @@ -383,7 +383,7 @@ static void uninit(struct vo *vo) struct gl_priv *p = vo->priv; gl_video_uninit(p->renderer); - gl_hwdec_uninit(p->hwdec); + ra_hwdec_uninit(p->hwdec); if (vo->hwdec_devs) { hwdec_devices_set_loader(vo->hwdec_devs, NULL, NULL); hwdec_devices_destroy(vo->hwdec_devs); @@ -444,7 +444,7 @@ static int preinit(struct vo *vo) hwdec_devices_set_loader(vo->hwdec_devs, call_request_hwdec_api, vo); - p->hwdec = gl_hwdec_load(p->vo->log, p->gl, vo->global, + p->hwdec = ra_hwdec_load(p->vo->log, p->ra, vo->global, vo->hwdec_devs, vo->opts->gl_hwdec_interop); gl_video_set_hwdec(p->renderer, p->hwdec); diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index d9289d16f6..4a9b60d4ff 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -90,7 +90,7 @@ struct mpv_opengl_cb_context { GL *gl; struct ra *ra; struct gl_video *renderer; - struct gl_hwdec *hwdec; + struct ra_hwdec *hwdec; struct m_config_cache *vo_opts_cache; struct mp_vo_opts *vo_opts; }; @@ -182,7 +182,7 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts, m_config_cache_update(ctx->vo_opts_cache); ctx->hwdec_devs = hwdec_devices_create(); - ctx->hwdec = gl_hwdec_load(ctx->log, ctx->gl, ctx->global, + ctx->hwdec = ra_hwdec_load(ctx->log, ctx->ra, ctx->global, ctx->hwdec_devs, ctx->vo_opts->gl_hwdec_interop); gl_video_set_hwdec(ctx->renderer, ctx->hwdec); @@ -223,7 +223,7 @@ int mpv_opengl_cb_uninit_gl(struct mpv_opengl_cb_context *ctx) gl_video_uninit(ctx->renderer); ctx->renderer = NULL; - gl_hwdec_uninit(ctx->hwdec); + ra_hwdec_uninit(ctx->hwdec); ctx->hwdec = NULL; hwdec_devices_destroy(ctx->hwdec_devs); ctx->hwdec_devs = NULL; diff --git a/video/vdpau.c b/video/vdpau.c index 8d0b524b60..b07926276d 100644 --- a/video/vdpau.c +++ b/video/vdpau.c @@ -474,6 +474,9 @@ struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, Display *x11 void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx) { + if (!ctx) + return; + struct vdp_functions *vdp = &ctx->vdp; VdpStatus vdp_st; |