summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-10 17:48:33 +0200
committerwm4 <wm4@nowhere>2017-08-10 21:24:31 +0200
commitc6fafbffaca16959dfa2b4bf1eb97861ad66b5ef (patch)
treedecef889171128c27f3a8cb2fcfb552f1b7297be
parentb2fb3f1340ed7ceb9b3fc8ba4ddec107e3a41a13 (diff)
downloadmpv-c6fafbffaca16959dfa2b4bf1eb97861ad66b5ef.tar.bz2
mpv-c6fafbffaca16959dfa2b4bf1eb97861ad66b5ef.tar.xz
vo_opengl: separate hwdec context and mapping, port it to use ra
This does two separate rather intrusive things: 1. Make the hwdec context (which does initialization, provides the device to the decoder, and other basic state) and frame mapping (getting textures from a mp_image) separate. This is more flexible, and you could map multiple images at once. It will help removing some hwdec special-casing from video.c. 2. Switch all hwdec API use to ra. Of course all code is still GL specific, but in theory it would be possible to support other backends. The most important change is that the hwdec interop returns ra objects, instead of anything GL specific. This removes the last dependency on GL-specific header files from video.c. I'm mixing these separate changes because both requires essentially rewriting all the glue code, so better do them at once. For the same reason, this change isn't done incrementally. hwdec_ios.m is untested, since I can't test it. Apart from superficial mistakes, this also requires dealing with Apple's texture format fuckups: they force you to use GL_LUMINANCE[_ALPHA] instead of GL_RED and GL_RG. We also need to report the correct format via ra_tex to the renderer, which is done by find_la_variant(). It's unknown whether this works correctly. hwdec_rpi.c as well as vo_rpi.c are still broken. (I need to pull my RPI out of a dusty pile of devices and cables, so, later.)
-rw-r--r--options/options.c2
-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
21 files changed, 1429 insertions, 1139 deletions
diff --git a/options/options.c b/options/options.c
index b07c576d4f..b13d9e5803 100644
--- a/options/options.c
+++ b/options/options.c
@@ -179,7 +179,7 @@ static const m_option_t mp_vo_opt_list[] = {
#endif
#if HAVE_GL
OPT_STRING_VALIDATE("opengl-hwdec-interop", gl_hwdec_interop, 0,
- gl_hwdec_validate_opt),
+ ra_hwdec_validate_opt),
OPT_REPLACED("hwdec-preload", "opengl-hwdec-interop"),
#endif
{0}
diff --git a/video/out/opengl/hwdec.c b/video/out/opengl/hwdec.c
index c9256c9c5b..5fbc1aa4a9 100644
--- a/video/out/opengl/hwdec.c
+++ b/video/out/opengl/hwdec.c
@@ -25,84 +25,85 @@
#include "options/m_config.h"
#include "hwdec.h"
-extern const struct gl_hwdec_driver gl_hwdec_vaegl;
-extern const struct gl_hwdec_driver gl_hwdec_vaglx;
-extern const struct gl_hwdec_driver gl_hwdec_videotoolbox;
-extern const struct gl_hwdec_driver gl_hwdec_vdpau;
-extern const struct gl_hwdec_driver gl_hwdec_dxva2egl;
-extern const struct gl_hwdec_driver gl_hwdec_d3d11egl;
-extern const struct gl_hwdec_driver gl_hwdec_d3d11eglrgb;
-extern const struct gl_hwdec_driver gl_hwdec_dxva2gldx;
-extern const struct gl_hwdec_driver gl_hwdec_dxva2;
-extern const struct gl_hwdec_driver gl_hwdec_cuda;
-extern const struct gl_hwdec_driver gl_hwdec_rpi_overlay;
-
-static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = {
+extern const struct ra_hwdec_driver ra_hwdec_vaegl;
+extern const struct ra_hwdec_driver ra_hwdec_vaglx;
+extern const struct ra_hwdec_driver ra_hwdec_videotoolbox;
+extern const struct ra_hwdec_driver ra_hwdec_vdpau;
+extern const struct ra_hwdec_driver ra_hwdec_dxva2egl;
+extern const struct ra_hwdec_driver ra_hwdec_d3d11egl;
+extern const struct ra_hwdec_driver ra_hwdec_d3d11eglrgb;
+extern const struct ra_hwdec_driver ra_hwdec_dxva2gldx;
+extern const struct ra_hwdec_driver ra_hwdec_dxva2;
+extern const struct ra_hwdec_driver ra_hwdec_cuda;
+extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay;
+
+static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = {
#if HAVE_VAAPI_EGL
- &gl_hwdec_vaegl,
+ &ra_hwdec_vaegl,
#endif
#if HAVE_VAAPI_GLX
- &gl_hwdec_vaglx,
+ &ra_hwdec_vaglx,
#endif
#if HAVE_VDPAU_GL_X11
- &gl_hwdec_vdpau,
+ &ra_hwdec_vdpau,
#endif
#if HAVE_VIDEOTOOLBOX_GL || HAVE_IOS_GL
- &gl_hwdec_videotoolbox,
+ &ra_hwdec_videotoolbox,
#endif
#if HAVE_D3D_HWACCEL
- &gl_hwdec_d3d11egl,
- &gl_hwdec_d3d11eglrgb,
+ &ra_hwdec_d3d11egl,
+ &ra_hwdec_d3d11eglrgb,
#if HAVE_D3D9_HWACCEL
- &gl_hwdec_dxva2egl,
+ &ra_hwdec_dxva2egl,
#endif
#endif
#if HAVE_GL_DXINTEROP_D3D9
- &gl_hwdec_dxva2gldx,
+ &ra_hwdec_dxva2gldx,
#endif
#if HAVE_CUDA_HWACCEL
- &gl_hwdec_cuda,
+ &ra_hwdec_cuda,
#endif
#if HAVE_RPI
- &gl_hwdec_rpi_overlay,
+ &ra_hwdec_rpi_overlay,
#endif
NULL
};
-static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl,
+static struct ra_hwdec *load_hwdec_driver(struct mp_log *log, struct ra *ra,
struct mpv_global *global,
struct mp_hwdec_devices *devs,
- const struct gl_hwdec_driver *drv,
+ const struct ra_hwdec_driver *drv,
bool is_auto)
{
- struct gl_hwdec *hwdec = talloc(NULL, struct gl_hwdec);
- *hwdec = (struct gl_hwdec) {
+ struct ra_hwdec *hwdec = talloc(NULL, struct ra_hwdec);
+ *hwdec = (struct ra_hwdec) {
.driver = drv,
.log = mp_log_new(hwdec, log, drv->name),
.global = global,
- .gl = gl,
+ .ra = ra,
.devs = devs,
.probing = is_auto,
+ .priv = talloc_zero_size(hwdec, drv->priv_size),
};
mp_verbose(log, "Loading hwdec driver '%s'\n", drv->name);
- if (hwdec->driver->create(hwdec) < 0) {
- talloc_free(hwdec);
+ if (hwdec->driver->init(hwdec) < 0) {
+ ra_hwdec_uninit(hwdec);
mp_verbose(log, "Loading failed.\n");
return NULL;
}
return hwdec;
}
-struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl,
+struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra,
struct mpv_global *g,
struct mp_hwdec_devices *devs,
enum hwdec_type api)
{
bool is_auto = HWDEC_IS_AUTO(api);
for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
- const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n];
+ const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n];
if ((is_auto || api == drv->api) && !drv->testing_only) {
- struct gl_hwdec *r = load_hwdec_driver(log, gl, g, devs, drv, is_auto);
+ struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, is_auto);
if (r)
return r;
}
@@ -111,7 +112,7 @@ struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl,
}
// Load by option name.
-struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl,
+struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra,
struct mpv_global *g,
struct mp_hwdec_devices *devs,
const char *name)
@@ -128,25 +129,25 @@ struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl,
}
for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
- const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n];
+ const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n];
if (name && strcmp(drv->name, name) == 0) {
- struct gl_hwdec *r = load_hwdec_driver(log, gl, g, devs, drv, false);
+ struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, false);
if (r)
return r;
}
}
- return gl_hwdec_load_api(log, gl, g, devs, api_id);
+ return ra_hwdec_load_api(log, ra, g, devs, api_id);
}
-int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
+int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param)
{
bool help = bstr_equals0(param, "help");
if (help)
mp_info(log, "Available hwdecs:\n");
for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
- const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n];
+ const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n];
const char *api_name = m_opt_choice_str(mp_hwdec_names, drv->api);
if (help) {
mp_info(log, " %s [%s]\n", drv->name, api_name);
@@ -172,18 +173,67 @@ int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
return M_OPT_INVALID;
}
-void gl_hwdec_uninit(struct gl_hwdec *hwdec)
+void ra_hwdec_uninit(struct ra_hwdec *hwdec)
{
if (hwdec)
- hwdec->driver->destroy(hwdec);
+ hwdec->driver->uninit(hwdec);
talloc_free(hwdec);
}
-bool gl_hwdec_test_format(struct gl_hwdec *hwdec, int imgfmt)
+bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt)
+{
+ for (int n = 0; hwdec->driver->imgfmts[n]; n++) {
+ if (hwdec->driver->imgfmts[n] == imgfmt)
+ return true;
+ }
+ return false;
+}
+
+struct ra_hwdec_mapper *ra_hwdec_mapper_create(struct ra_hwdec *hwdec,
+ struct mp_image_params *params)
+{
+ assert(ra_hwdec_test_format(hwdec, params->imgfmt));
+
+ struct ra_hwdec_mapper *mapper = talloc_ptrtype(NULL, mapper);
+ *mapper = (struct ra_hwdec_mapper){
+ .owner = hwdec,
+ .driver = hwdec->driver->mapper,
+ .log = hwdec->log,
+ .ra = hwdec->ra,
+ .priv = talloc_zero_size(mapper, hwdec->driver->mapper->priv_size),
+ .src_params = *params,
+ .dst_params = *params,
+ };
+ if (mapper->driver->init(mapper) < 0)
+ ra_hwdec_mapper_free(&mapper);
+ return mapper;
+}
+
+void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper)
+{
+ struct ra_hwdec_mapper *p = *mapper;
+ if (p) {
+ ra_hwdec_mapper_unmap(p);
+ p->driver->uninit(p);
+ talloc_free(p);
+ }
+ *mapper = NULL;
+}
+
+void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper)
{
- if (!imgfmt)
- return false;
- if (hwdec->driver->test_format)
- return hwdec->driver->test_format(hwdec, imgfmt);
- return hwdec->driver->imgfmt == imgfmt;
+ if (mapper->driver->unmap)
+ mapper->driver->unmap(mapper);
+ mp_image_unrefp(&mapper->src);
+}
+
+int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img)
+{
+ ra_hwdec_mapper_unmap(mapper);
+ mp_image_setrefp(&mapper->src, img);
+ if (mapper->driver->map(mapper) < 0) {
+ ra_hwdec_mapper_unmap(mapper);
+ return -1;
+ }
+ return 0;
}
diff --git a/video/out/opengl/hwdec.h b/video/out/opengl/hwdec.h
index 6d4dc5d591..f978b70018 100644
--- a/video/out/opengl/hwdec.h
+++ b/video/out/opengl/hwdec.h
@@ -2,13 +2,14 @@
#define MPGL_HWDEC_H_
#include "common.h"
+#include "ra.h"
#include "video/hwdec.h"
-struct gl_hwdec {
- const struct gl_hwdec_driver *driver;
+struct ra_hwdec {
+ const struct ra_hwdec_driver *driver;
struct mp_log *log;
struct mpv_global *global;
- GL *gl;
+ struct ra *ra;
struct mp_hwdec_devices *devs;
// GLSL extensions required to sample textures from this.
const char **glsl_extensions;
@@ -20,79 +21,110 @@ struct gl_hwdec {
float overlay_colorkey[4];
};
-struct gl_hwdec_plane {
- GLuint gl_texture;
- GLenum gl_target;
- // Like struct gl_format.format (GL_RED etc.). Currently to detect
- // GL_LUMINANCE_ALPHA and integer formats - can be left to 0 otherwise.
- GLenum gl_format;
- int tex_w, tex_h; // allocated texture size
-};
+struct ra_hwdec_mapper {
+ const struct ra_hwdec_mapper_driver *driver;
+ struct mp_log *log;
+ struct ra *ra;
+ void *priv;
+ struct ra_hwdec *owner;
+ // Input frame parameters. (Set before init(), immutable.)
+ struct mp_image_params src_params;
+ // Output frame parameters (represents the format the textures return). Must
+ // be set by init(), immutable afterwards,
+ struct mp_image_params dst_params;
+
+ // The currently mapped source image (or the image about to be mapped in
+ // ->map()). NULL if unmapped. The mapper can also clear this reference if
+ // the mapped textures contain a full copy.
+ struct mp_image *src;
-struct gl_hwdec_frame {
- struct gl_hwdec_plane planes[4];
+ // The mapped textures and metadata about them. These fields change if a
+ // new frame is mapped (or unmapped), but otherwise remain constant.
+ // The common code won't mess with these, so you can e.g. set them in the
+ // .init() callback.
+ struct ra_tex *tex[4];
bool vdpau_fields;
};
-struct gl_hwdec_driver {
+// This can be used to map frames of a specific hw format as GL textures.
+struct ra_hwdec_mapper_driver {
+ // Used to create ra_hwdec_mapper.priv.
+ size_t priv_size;
+
+ // Init the mapper implementation. At this point, the field src_params,
+ // fns, devs, priv are initialized.
+ int (*init)(struct ra_hwdec_mapper *mapper);
+ // Destroy the mapper. unmap is called before this.
+ void (*uninit)(struct ra_hwdec_mapper *mapper);
+
+ // Map mapper->src as texture, and set mapper->frame to textures using it.
+ // It is expected that that the textures remain valid until the next unmap
+ // or uninit call.
+ // The function is allowed to unref mapper->src if it's not needed (i.e.
+ // this function creates a copy).
+ // The underlying format can change, so you might need to do some form
+ // of change detection. You also must reject unsupported formats with an
+ // error.
+ // On error, returns negative value on error and remains unmapped.
+ int (*map)(struct ra_hwdec_mapper *mapper);
+ // Unmap the frame. Does nothing if already unmapped. Optional.
+ void (*unmap)(struct ra_hwdec_mapper *mapper);
+};
+
+struct ra_hwdec_driver {
// Name of the interop backend. This is used for informational purposes only.
const char *name;
+ // Used to create ra_hwdec.priv.
+ size_t priv_size;
// Used to explicitly request a specific API.
enum hwdec_type api;
- // The hardware surface IMGFMT_ that must be passed to map_image later.
- // If the test_format callback is set, this field is ignored!
- int imgfmt;
+ // One of the hardware surface IMGFMT_ that must be passed to map_image later.
+ // Terminated with a 0 entry. (Extend the array size as needed.)
+ const int imgfmts[3];
// Dosn't load this unless requested by name.
bool testing_only;
+
// Create the hwdec device. It must add it to hw->devs, if applicable.
- int (*create)(struct gl_hwdec *hw);
- // Prepare for rendering video. (E.g. create textures.)
- // Called on initialization, and every time the video size changes.
- // *params must be set to the format the hw textures return.
- int (*reinit)(struct gl_hwdec *hw, struct mp_image_params *params);
- // Return textures that contain a copy or reference of the given hw_image.
- // The textures mirror the format returned by the reinit params argument.
- // The textures must remain valid until unmap is called.
- // hw_image remains referenced by the caller until unmap is called.
- int (*map_frame)(struct gl_hwdec *hw, struct mp_image *hw_image,
- struct gl_hwdec_frame *out_frame);
- // Must be idempotent.
- void (*unmap)(struct gl_hwdec *hw);
-
- void (*destroy)(struct gl_hwdec *hw);
-
- // Optional callback for checking input format support.
- bool (*test_format)(struct gl_hwdec *hw, int imgfmt);
-
- // The following functions provide an alternative API. Each gl_hwdec_driver
- // must have either map_frame or overlay_frame set (not both or none), and
+ int (*init)(struct ra_hwdec *hw);
+ void (*uninit)(struct ra_hwdec *hw);
+
+ // This will be used to create a ra_hwdec_mapper from ra_hwdec.
+ const struct ra_hwdec_mapper_driver *mapper;
+
+ // The following function provides an alternative API. Each ra_hwdec_driver
+ // must have either provide a mapper or overlay_frame (not both or none), and
// if overlay_frame is set, it operates in overlay mode. In this mode,
// OSD etc. is rendered via OpenGL, but the video is rendered as a separate
// layer below it.
// Non-overlay mode is strictly preferred, so try not to use overlay mode.
-
// Set the given frame as overlay, replacing the previous one. This can also
// just change the position of the overlay.
// hw_image==src==dst==NULL is passed to clear the overlay.
- int (*overlay_frame)(struct gl_hwdec *hw, struct mp_image *hw_image,
+ int (*overlay_frame)(struct ra_hwdec *hw, struct mp_image *hw_image,
struct mp_rect *src, struct mp_rect *dst, bool newframe);
};
-struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl,
+struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra,
struct mpv_global *g,
struct mp_hwdec_devices *devs,
enum hwdec_type api);
-struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl,
+struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra,
struct mpv_global *g,
struct mp_hwdec_devices *devs,
const char *name);
-int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
+int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param);
-void gl_hwdec_uninit(struct gl_hwdec *hwdec);
+void ra_hwdec_uninit(struct ra_hwdec *hwdec);
+
+bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt);
-bool gl_hwdec_test_format(struct gl_hwdec *hwdec, int imgfmt);
+struct ra_hwdec_mapper *ra_hwdec_mapper_create(struct ra_hwdec *hwdec,
+ struct mp_image_params *params);
+void ra_hwdec_mapper_free(struct ra_hwdec_mapper **mapper);
+void ra_hwdec_mapper_unmap(struct ra_hwdec_mapper *mapper);
+int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img);
#endif
diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c
index fd432ee7f8..d40bafee24 100644
--- a/video/out/opengl/hwdec_cuda.c
+++ b/video/out/opengl/hwdec_cuda.c
@@ -35,21 +35,24 @@
#include "formats.h"
#include "hwdec.h"
#include "options/m_config.h"
+#include "ra_gl.h"
#include "video.h"
-struct priv {
+struct priv_owner {
struct mp_hwdec_ctx hwctx;
+ CUcontext display_ctx;
+ CUcontext decode_ctx;
+};
+
+struct priv {
struct mp_image layout;
- GLuint gl_textures[4];
CUgraphicsResource cu_res[4];
CUarray cu_array[4];
- int plane_bytes[4];
CUcontext display_ctx;
- CUcontext decode_ctx;
};
-static int check_cu(struct gl_hwdec *hw, CUresult err, const char *func)
+static int check_cu(struct ra_hwdec *hw, CUresult err, const char *func)
{
const char *err_name;
const char *err_string;
@@ -72,22 +75,24 @@ static int check_cu(struct gl_hwdec *hw, CUresult err, const char *func)
#define CHECK_CU(x) check_cu(hw, (x), #x)
-static int cuda_create(struct gl_hwdec *hw)
+static int cuda_init(struct ra_hwdec *hw)
{
CUdevice display_dev;
AVBufferRef *hw_device_ctx = NULL;
CUcontext dummy;
unsigned int device_count;
int ret = 0;
+ struct priv_owner *p = hw->priv;
- if (hw->gl->version < 210 && hw->gl->es < 300) {
+ if (!ra_is_gl(hw->ra))
+ return -1;
+
+ GL *gl = ra_gl_get(hw->ra);
+ if (gl->version < 210 && gl->es < 300) {
MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n");
return -1;
}
- struct priv *p = talloc_zero(hw, struct priv);
- hw->priv = p;
-
bool loaded = cuda_load();
if (!loaded) {
MP_VERBOSE(hw, "Failed to load CUDA symbols\n");
@@ -171,22 +176,43 @@ static int cuda_create(struct gl_hwdec *hw)
return -1;
}
-static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
+static void cuda_uninit(struct ra_hwdec *hw)
+{
+ struct priv_owner *p = hw->priv;
+
+ if (p->hwctx.ctx)
+ hwdec_devices_remove(hw->devs, &p->hwctx);
+ av_buffer_unref(&p->hwctx.av_device_ref);
+
+ if (p->decode_ctx && p->decode_ctx != p->display_ctx)
+ CHECK_CU(cuCtxDestroy(p->decode_ctx));
+
+ if (p->display_ctx)
+ CHECK_CU(cuCtxDestroy(p->display_ctx));
+}
+
+#undef CHECK_CU
+#define CHECK_CU(x) check_cu((mapper)->owner, (x), #x)
+
+static int mapper_init(struct ra_hwdec_mapper *mapper)
{
- struct priv *p = hw->priv;
- GL *gl = hw->gl;
+ struct priv_owner *p_owner = mapper->owner->priv;
+ struct priv *p = mapper->priv;
CUcontext dummy;
int ret = 0, eret = 0;
- assert(params->imgfmt == hw->driver->imgfmt);
- params->imgfmt = params->hw_subfmt;
- params->hw_subfmt = 0;
+ p->display_ctx = p_owner->display_ctx;
- mp_image_set_params(&p->layout, params);
+ int imgfmt = mapper->src_params.hw_subfmt;
+ mapper->dst_params = mapper->src_params;
+ mapper->dst_params.imgfmt = imgfmt;
+ mapper->dst_params.hw_subfmt = 0;
- struct gl_imgfmt_desc desc;
- if (!gl_get_imgfmt_desc(gl, params->imgfmt, &desc)) {
- MP_ERR(hw, "Unsupported format: %s\n", mp_imgfmt_to_name(params->imgfmt));
+ mp_image_set_params(&p->layout, &mapper->dst_params);
+
+ struct ra_imgfmt_desc desc;
+ if (!ra_get_imgfmt_desc(mapper->ra, imgfmt, &desc)) {
+ MP_ERR(mapper, "Unsupported format: %s\n", mp_imgfmt_to_name(imgfmt));
return -1;
}
@@ -194,26 +220,30 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
if (ret < 0)
return ret;
- gl->GenTextures(4, p->gl_textures);
for (int n = 0; n < desc.num_planes; n++) {
- const struct gl_format *fmt = desc.planes[n];
-
- p->plane_bytes[n] = gl_bytes_per_pixel(fmt->format, fmt->type);
-
- gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]);
- GLenum filter = GL_LINEAR;
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl->TexImage2D(GL_TEXTURE_2D, 0, fmt->internal_format,
- mp_image_plane_w(&p->layout, n),
- mp_image_plane_h(&p->layout, n),
- 0, fmt->format, fmt->type, NULL);
- gl->BindTexture(GL_TEXTURE_2D, 0);
-
- ret = CHECK_CU(cuGraphicsGLRegisterImage(&p->cu_res[n], p->gl_textures[n],
- GL_TEXTURE_2D,
+ const struct ra_format *format = desc.planes[n];
+
+ struct ra_tex_params params = {
+ .dimensions = 2,
+ .w = mp_image_plane_w(&p->layout, n),
+ .h = mp_image_plane_h(&p->layout, n),
+ .d = 1,
+ .format = format,
+ .render_src = true,
+ .src_linear = format->linear_filter,
+ };
+
+ mapper->tex[n] = ra_tex_create(mapper->ra, &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;