From 51de1d8436100f725f3576aefa24a2bd2057bc28 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 22:36:56 +0200 Subject: Adding upstream version 0.37.0. Signed-off-by: Daniel Baumann --- video/out/opengl/hwdec_dxva2gldx.c | 247 +++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 video/out/opengl/hwdec_dxva2gldx.c (limited to 'video/out/opengl/hwdec_dxva2gldx.c') diff --git a/video/out/opengl/hwdec_dxva2gldx.c b/video/out/opengl/hwdec_dxva2gldx.c new file mode 100644 index 0000000..0172813 --- /dev/null +++ b/video/out/opengl/hwdec_dxva2gldx.c @@ -0,0 +1,247 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include + +#include "common/common.h" +#include "osdep/windows_utils.h" +#include "video/out/gpu/hwdec.h" +#include "ra_gl.h" +#include "video/hwdec.h" +#include "video/d3d.h" + +// for WGL_ACCESS_READ_ONLY_NV +#include + +#define SHARED_SURFACE_D3DFMT D3DFMT_X8R8G8B8 + +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 uninit(struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + hwdec_devices_remove(hw->devs, &p->hwctx); + av_buffer_unref(&p->hwctx.av_device_ref); + + if (p->device) + IDirect3DDevice9Ex_Release(p->device); +} + +static int init(struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + struct ra *ra = hw->ra_ctx->ra; + + if (!ra_is_gl(ra)) + return -1; + GL *gl = ra_gl_get(ra); + if (!(gl->mpgl_caps & MPGL_CAP_DXINTEROP)) + return -1; + + // 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 = ra_get_native_resource(ra, "dxinterop_device_HANDLE"); + if (!p->device_h) + return -1; + + // But we also still need the actual D3D device + p->device = ra_get_native_resource(ra, "IDirect3DDevice9Ex"); + if (!p->device) + return -1; + IDirect3DDevice9Ex_AddRef(p->device); + + p->hwctx = (struct mp_hwdec_ctx){ + .driver_name = hw->driver->name, + .av_device_ref = d3d9_wrap_device_ref((IDirect3DDevice9 *)p->device), + .hw_imgfmt = IMGFMT_DXVA2, + }; + + if (!p->hwctx.av_device_ref) { + MP_VERBOSE(hw, "Failed to create hwdevice_ctx\n"); + return -1; + } + + hwdec_devices_add(hw->devs, &p->hwctx); + return 0; +} + +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_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + GL *gl = ra_gl_get(mapper->ra); + HRESULT hr; + + p->device = p_owner->device; + p->device_h = p_owner->device_h; + + HANDLE share_handle = NULL; + hr = IDirect3DDevice9Ex_CreateRenderTarget( + p->device, + mapper->src_params.w, mapper->src_params.h, + SHARED_SURFACE_D3DFMT, D3DMULTISAMPLE_NONE, 0, FALSE, + &p->rtarget, &share_handle); + if (FAILED(hr)) { + MP_ERR(mapper, "Failed creating offscreen Direct3D surface: %s\n", + mp_HRESULT_to_str(hr)); + return -1; + } + + if (share_handle && + !gl->DXSetResourceShareHandleNV(p->rtarget, share_handle)) { + MP_ERR(mapper, "Failed setting Direct3D/OpenGL share handle for surface: %s\n", + mp_LastError_to_str()); + return -1; + } + + gl->GenTextures(1, &p->texture); + gl->BindTexture(GL_TEXTURE_2D, p->texture); + 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); + + p->rtarget_h = gl->DXRegisterObjectNV(p->device_h, p->rtarget, p->texture, + GL_TEXTURE_2D, + WGL_ACCESS_READ_ONLY_NV); + if (!p->rtarget_h) { + MP_ERR(mapper, "Failed to register Direct3D surface with OpenGL: %s\n", + mp_LastError_to_str()); + return -1; + } + + if (!gl->DXLockObjectsNV(p->device_h, 1, &p->rtarget_h)) { + MP_ERR(mapper, "Failed locking texture for access by OpenGL %s\n", + mp_LastError_to_str()); + return -1; + } + + struct ra_tex_params params = { + .dimensions = 2, + .w = mapper->src_params.w, + .h = mapper->src_params.h, + .d = 1, + .format = ra_find_unorm_format(mapper->ra, 1, 4), + .render_src = true, + .src_linear = true, + }; + if (!params.format) + return -1; + + mapper->tex[0] = ra_create_wrapped_tex(mapper->ra, ¶ms, p->texture); + if (!mapper->tex[0]) + return -1; + + mapper->dst_params = mapper->src_params; + mapper->dst_params.imgfmt = IMGFMT_RGB0; + mapper->dst_params.hw_subfmt = 0; + + return 0; +} + +static int mapper_map(struct ra_hwdec_mapper *mapper) +{ + 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(mapper, "Failed unlocking texture for access by OpenGL: %s\n", + mp_LastError_to_str()); + return -1; + } + + 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(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(mapper, "Failed locking texture for access by OpenGL: %s\n", + mp_LastError_to_str()); + return -1; + } + + return 0; +} + +const struct ra_hwdec_driver ra_hwdec_dxva2gldx = { + .name = "dxva2-dxinterop", + .priv_size = sizeof(struct priv_owner), + .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, + }, +}; -- cgit v1.2.3