summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/out/opengl/hwdec.c144
-rw-r--r--video/out/opengl/hwdec.h122
-rw-r--r--video/out/opengl/hwdec_cuda.c168
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c185
-rw-r--r--video/out/opengl/hwdec_d3d11eglrgb.c142
-rw-r--r--video/out/opengl/hwdec_dxva2egl.c226
-rw-r--r--video/out/opengl/hwdec_dxva2gldx.c187
-rw-r--r--video/out/opengl/hwdec_ios.m209
-rw-r--r--video/out/opengl/hwdec_osx.c154
-rw-r--r--video/out/opengl/hwdec_rpi.c58
-rw-r--r--video/out/opengl/hwdec_vaegl.c291
-rw-r--r--video/out/opengl/hwdec_vaglx.c163
-rw-r--r--video/out/opengl/hwdec_vdpau.c264
-rw-r--r--video/out/opengl/ra_gl.c147
-rw-r--r--video/out/opengl/ra_gl.h12
-rw-r--r--video/out/opengl/video.c73
-rw-r--r--video/out/opengl/video.h4
-rw-r--r--video/out/vo_opengl.c8
-rw-r--r--video/out/vo_opengl_cb.c6
-rw-r--r--video/vdpau.c3
20 files changed, 1428 insertions, 1138 deletions
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, &params);
+ 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, &params,
+ 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, &params, 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, &params, 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, &params, 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, &params,
+ 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, &params,
+ 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, &params,
+ 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, &params) >= 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, &params, 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, &params, 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, &params, 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, &params) < 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;