diff options
author | rcombs <rcombs@rcombs.me> | 2022-07-13 21:26:14 -0500 |
---|---|---|
committer | rcombs <rcombs@rcombs.me> | 2023-11-16 09:48:20 -0800 |
commit | ca45b71edc9148ab6074947fa8ca0cd1eb4d5572 (patch) | |
tree | cb9340e07515d15122c7fdc195b2e7c736bf93c2 /video/out | |
parent | 62b1ce0a55b165c1bad2f5ca4ec136f929b792db (diff) | |
download | mpv-ca45b71edc9148ab6074947fa8ca0cd1eb4d5572.tar.bz2 mpv-ca45b71edc9148ab6074947fa8ca0cd1eb4d5572.tar.xz |
hwdec: support videotoolbox with libplacebo
Diffstat (limited to 'video/out')
-rw-r--r-- | video/out/gpu/hwdec.c | 2 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_ios_gl.m (renamed from video/out/opengl/hwdec_ios.m) | 90 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_mac_gl.c (renamed from video/out/opengl/hwdec_osx.c) | 91 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vt.c | 141 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vt.h | 63 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vt_pl.m | 312 |
6 files changed, 552 insertions, 147 deletions
diff --git a/video/out/gpu/hwdec.c b/video/out/gpu/hwdec.c index d8be6da777..c8098f3aad 100644 --- a/video/out/gpu/hwdec.c +++ b/video/out/gpu/hwdec.c @@ -44,7 +44,7 @@ const struct ra_hwdec_driver *const ra_hwdec_drivers[] = { #if HAVE_VAAPI &ra_hwdec_vaapi, #endif -#if HAVE_VIDEOTOOLBOX_GL || HAVE_IOS_GL +#if HAVE_VIDEOTOOLBOX_GL || HAVE_IOS_GL || HAVE_VIDEOTOOLBOX_PL &ra_hwdec_videotoolbox, #endif #if HAVE_D3D_HWACCEL diff --git a/video/out/opengl/hwdec_ios.m b/video/out/hwdec/hwdec_ios_gl.m index 380c107ec1..633cc3ddc1 100644 --- a/video/out/opengl/hwdec_ios.m +++ b/video/out/hwdec/hwdec_ios_gl.m @@ -27,20 +27,10 @@ #include "video/out/gpu/hwdec.h" #include "video/mp_image_pool.h" -#include "ra_gl.h" +#include "video/out/opengl/ra_gl.h" +#include "hwdec_vt.h" -struct priv_owner { - struct mp_hwdec_ctx hwctx; -}; - -struct priv { - CVPixelBufferRef pbuf; - CVOpenGLESTextureCacheRef gl_texture_cache; - CVOpenGLESTextureRef gl_planes[MP_MAX_PLANES]; - struct ra_imgfmt_desc desc; -}; - -static bool check_hwdec(struct ra_hwdec *hw) +static bool check_hwdec(const struct ra_hwdec *hw) { if (!ra_is_gl(hw->ra_ctx->ra)) return false; @@ -59,38 +49,6 @@ static bool check_hwdec(struct ra_hwdec *hw) return true; } -static int init(struct ra_hwdec *hw) -{ - struct priv_owner *p = hw->priv; - - if (!check_hwdec(hw)) - return -1; - - p->hwctx = (struct mp_hwdec_ctx){ - .driver_name = hw->driver->name, - .hw_imgfmt = IMGFMT_VIDEOTOOLBOX, - }; - - int ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref, - AV_HWDEVICE_TYPE_VIDEOTOOLBOX, NULL, NULL, 0); - if (ret != 0) { - MP_VERBOSE(hw, "Failed to create hwdevice_ctx: %s\n", av_err2str(ret)); - return -1; - } - - hwdec_devices_add(hw->devs, &p->hwctx); - - return 0; -} - -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); -} - // In GLES3 mode, CVOpenGLESTextureCacheCreateTextureFromImage() // will return error -6683 unless invoked with GL_LUMINANCE and // GL_LUMINANCE_ALPHA (http://stackoverflow.com/q/36213994/332798) @@ -130,20 +88,6 @@ static int mapper_init(struct ra_hwdec_mapper *mapper) { struct priv *p = mapper->priv; - 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 (!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) { @@ -262,17 +206,17 @@ static void mapper_uninit(struct ra_hwdec_mapper *mapper) } } -const struct ra_hwdec_driver ra_hwdec_videotoolbox = { - .name = "videotoolbox", - .priv_size = sizeof(struct priv_owner), - .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, - }, -}; +bool vt_gl_init(const struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + if (!check_hwdec(hw)) + return false; + + p->interop_init = mapper_init; + p->interop_uninit = mapper_uninit; + p->interop_map = mapper_map; + p->interop_unmap = mapper_unmap; + + return true; +} diff --git a/video/out/opengl/hwdec_osx.c b/video/out/hwdec/hwdec_mac_gl.c index 8bbe54bd4c..b73f5b967d 100644 --- a/video/out/opengl/hwdec_osx.c +++ b/video/out/hwdec/hwdec_mac_gl.c @@ -28,20 +28,10 @@ #include "video/mp_image_pool.h" #include "video/out/gpu/hwdec.h" -#include "ra_gl.h" +#include "video/out/opengl/ra_gl.h" +#include "hwdec_vt.h" -struct priv_owner { - struct mp_hwdec_ctx hwctx; -}; - -struct priv { - CVPixelBufferRef pbuf; - GLuint gl_planes[MP_MAX_PLANES]; - - struct ra_imgfmt_desc desc; -}; - -static bool check_hwdec(struct ra_hwdec *hw) +static bool check_hwdec(const struct ra_hwdec *hw) { if (!ra_is_gl(hw->ra_ctx->ra)) return false; @@ -60,38 +50,6 @@ static bool check_hwdec(struct ra_hwdec *hw) return true; } -static int init(struct ra_hwdec *hw) -{ - struct priv_owner *p = hw->priv; - - if (!check_hwdec(hw)) - return -1; - - p->hwctx = (struct mp_hwdec_ctx){ - .driver_name = hw->driver->name, - .hw_imgfmt = IMGFMT_VIDEOTOOLBOX, - }; - - int ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref, - AV_HWDEVICE_TYPE_VIDEOTOOLBOX, NULL, NULL, 0); - if (ret != 0) { - MP_VERBOSE(hw, "Failed to create hwdevice_ctx: %s\n", av_err2str(ret)); - return -1; - } - - hwdec_devices_add(hw->devs, &p->hwctx); - - return 0; -} - -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); -} - static int mapper_init(struct ra_hwdec_mapper *mapper) { struct priv *p = mapper->priv; @@ -99,26 +57,13 @@ static int mapper_init(struct ra_hwdec_mapper *mapper) 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 (!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++) { if (p->desc.planes[n]->ctype != RA_CTYPE_UNORM) { MP_ERR(mapper, "Format unsupported.\n"); return -1; } } + return 0; } @@ -208,17 +153,17 @@ static void mapper_uninit(struct ra_hwdec_mapper *mapper) gl->DeleteTextures(MP_MAX_PLANES, p->gl_planes); } -const struct ra_hwdec_driver ra_hwdec_videotoolbox = { - .name = "videotoolbox", - .priv_size = sizeof(struct priv_owner), - .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, - }, -}; +bool vt_gl_init(const struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + if (!check_hwdec(hw)) + return false; + + p->interop_init = mapper_init; + p->interop_uninit = mapper_uninit; + p->interop_map = mapper_map; + p->interop_unmap = mapper_unmap; + + return true; +} diff --git a/video/out/hwdec/hwdec_vt.c b/video/out/hwdec/hwdec_vt.c new file mode 100644 index 0000000000..ab41d027cf --- /dev/null +++ b/video/out/hwdec/hwdec_vt.c @@ -0,0 +1,141 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stddef.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <libavutil/hwcontext.h> +#include <libavutil/hwcontext_videotoolbox.h> + +#include "config.h" + +#include "video/out/gpu/hwdec.h" +#include "video/out/hwdec/hwdec_vt.h" + +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); +} + +const static vt_interop_init interop_inits[] = { +#if HAVE_VIDEOTOOLBOX_GL || HAVE_IOS_GL + vt_gl_init, +#endif +#if HAVE_VIDEOTOOLBOX_PL + vt_pl_init, +#endif + NULL +}; + +static int init(struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + for (int i = 0; interop_inits[i]; i++) { + if (interop_inits[i](hw)) { + break; + } + } + + if (!p->interop_map || !p->interop_unmap) { + MP_VERBOSE(hw, "VT hwdec only works with OpenGL or Vulkan backends.\n"); + return -1; + } + + p->hwctx = (struct mp_hwdec_ctx){ + .driver_name = hw->driver->name, + .hw_imgfmt = IMGFMT_VIDEOTOOLBOX, + }; + + int ret = av_hwdevice_ctx_create(&p->hwctx.av_device_ref, + AV_HWDEVICE_TYPE_VIDEOTOOLBOX, NULL, NULL, 0); + if (ret != 0) { + MP_VERBOSE(hw, "Failed to create hwdevice_ctx: %s\n", av_err2str(ret)); + return -1; + } + + hwdec_devices_add(hw->devs, &p->hwctx); + + return 0; +} + +static void mapper_unmap(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + + p_owner->interop_unmap(mapper); +} + +static void mapper_uninit(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + if (p_owner->interop_uninit) { + p_owner->interop_uninit(mapper); + } +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + struct priv *p = mapper->priv; + + 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 (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &p->desc)) { + MP_ERR(mapper, "Unsupported texture format.\n"); + return -1; + } + + if (p_owner->interop_init) + return p_owner->interop_init(mapper); + + return 0; +} + +static int mapper_map(struct ra_hwdec_mapper *mapper) +{ + struct priv_owner *p_owner = mapper->owner->priv; + + return p_owner->interop_map(mapper); +} + +const struct ra_hwdec_driver ra_hwdec_videotoolbox = { + .name = "videotoolbox", + .priv_size = sizeof(struct priv_owner), + .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/hwdec/hwdec_vt.h b/video/out/hwdec/hwdec_vt.h new file mode 100644 index 0000000000..b79c64198d --- /dev/null +++ b/video/out/hwdec/hwdec_vt.h @@ -0,0 +1,63 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <CoreVideo/CoreVideo.h> + +#include "config.h" +#include "video/out/gpu/hwdec.h" + +struct priv_owner { + struct mp_hwdec_ctx hwctx; + + int (*interop_init)(struct ra_hwdec_mapper *mapper); + void (*interop_uninit)(struct ra_hwdec_mapper *mapper); + + int (*interop_map)(struct ra_hwdec_mapper *mapper); + void (*interop_unmap)(struct ra_hwdec_mapper *mapper); +}; + +#ifndef __OBJC__ +typedef struct __CVMetalTextureCache *CVMetalTextureCacheRef; +typedef CVImageBufferRef CVMetalTextureRef; +#endif + +struct priv { + void *interop_mapper_priv; + + CVPixelBufferRef pbuf; + +#if HAVE_VIDEOTOOLBOX_GL + GLuint gl_planes[MP_MAX_PLANES]; +#elif HAVE_IOS_GL + CVOpenGLESTextureCacheRef gl_texture_cache; + CVOpenGLESTextureRef gl_planes[MP_MAX_PLANES]; +#endif + +#if HAVE_VIDEOTOOLBOX_PL + CVMetalTextureCacheRef mtl_texture_cache; + CVMetalTextureRef mtl_planes[MP_MAX_PLANES]; +#endif + + struct ra_imgfmt_desc desc; +}; + +typedef bool (*vt_interop_init)(const struct ra_hwdec *hw); + +bool vt_gl_init(const struct ra_hwdec *hw); +bool vt_pl_init(const struct ra_hwdec *hw); diff --git a/video/out/hwdec/hwdec_vt_pl.m b/video/out/hwdec/hwdec_vt_pl.m new file mode 100644 index 0000000000..cd133a0adc --- /dev/null +++ b/video/out/hwdec/hwdec_vt_pl.m @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com> + * 2017 Aman Gupta <ffmpeg@tmm1.net> + * 2023 rcombs <rcombs@rcombs.me> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> + +#include <CoreVideo/CoreVideo.h> +#include <Metal/Metal.h> + +#include <libavutil/hwcontext.h> + +#include <libplacebo/renderer.h> + +#include "config.h" + +#include "video/out/gpu/hwdec.h" +#include "video/out/placebo/ra_pl.h" +#include "video/mp_image_pool.h" + +#if HAVE_VULKAN +#include "video/out/vulkan/common.h" +#endif + +#include "hwdec_vt.h" + +static bool check_hwdec(const struct ra_hwdec *hw) +{ + pl_gpu gpu = ra_pl_get(hw->ra_ctx->ra); + if (!gpu) { + // This is not a libplacebo RA; + return false; + } + + if (!(gpu->import_caps.tex & PL_HANDLE_MTL_TEX)) { + MP_VERBOSE(hw, "VideoToolbox libplacebo interop requires support for " + "PL_HANDLE_MTL_TEX import.\n"); + return false; + } + + return true; +} + +static int mapper_init(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + + 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 (!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++) { + if (!p->desc.planes[n] || p->desc.planes[n]->ctype != RA_CTYPE_UNORM) { + MP_ERR(mapper, "Format unsupported.\n"); + return -1; + } + } + + id<MTLDevice> mtl_device = nil; + +#ifdef VK_EXT_METAL_OBJECTS_SPEC_VERSION + pl_gpu gpu = ra_pl_get(mapper->ra); + if (gpu) { + pl_vulkan vulkan = pl_vulkan_get(gpu); + if (vulkan && vulkan->device && vulkan->instance && vulkan->get_proc_addr) { + PFN_vkExportMetalObjectsEXT pExportMetalObjects = (PFN_vkExportMetalObjectsEXT)vulkan->get_proc_addr(vulkan->instance, "vkExportMetalObjectsEXT"); + if (pExportMetalObjects) { + VkExportMetalDeviceInfoEXT device_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT, + .pNext = NULL, + .mtlDevice = nil, + }; + + VkExportMetalObjectsInfoEXT objects_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT, + .pNext = &device_info, + }; + + pExportMetalObjects(vulkan->device, &objects_info); + + mtl_device = device_info.mtlDevice; + [mtl_device retain]; + } + } + } +#endif + + if (!mtl_device) { + mtl_device = MTLCreateSystemDefaultDevice(); + } + + CVReturn err = CVMetalTextureCacheCreate( + kCFAllocatorDefault, + NULL, + mtl_device, + NULL, + &p->mtl_texture_cache); + + [mtl_device release]; + + if (err != noErr) { + MP_ERR(mapper, "Failure in CVOpenGLESTextureCacheCreate: %d\n", err); + return -1; + } + + return 0; +} + +static void mapper_unmap(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + + for (int i = 0; i < p->desc.num_planes; i++) { + ra_tex_free(mapper->ra, &mapper->tex[i]); + if (p->mtl_planes[i]) { + CFRelease(p->mtl_planes[i]); + p->mtl_planes[i] = NULL; + } + } + + CVMetalTextureCacheFlush(p->mtl_texture_cache, 0); +} + +static const struct { + const char *glsl; + MTLPixelFormat mtl; +} mtl_fmts[] = { + {"r16f", MTLPixelFormatR16Float }, + {"r32f", MTLPixelFormatR32Float }, + {"rg16f", MTLPixelFormatRG16Float }, + {"rg32f", MTLPixelFormatRG32Float }, + {"rgba16f", MTLPixelFormatRGBA16Float }, + {"rgba32f", MTLPixelFormatRGBA32Float }, + {"r11f_g11f_b10f", MTLPixelFormatRG11B10Float }, + + {"r8", MTLPixelFormatR8Unorm }, + {"r16", MTLPixelFormatR16Unorm }, + {"rg8", MTLPixelFormatRG8Unorm }, + {"rg16", MTLPixelFormatRG16Unorm }, + {"rgba8", MTLPixelFormatRGBA8Unorm }, + {"rgba16", MTLPixelFormatRGBA16Unorm }, + {"rgb10_a2", MTLPixelFormatRGB10A2Unorm }, + + {"r8_snorm", MTLPixelFormatR8Snorm }, + {"r16_snorm", MTLPixelFormatR16Snorm }, + {"rg8_snorm", MTLPixelFormatRG8Snorm }, + {"rg16_snorm", MTLPixelFormatRG16Snorm }, + {"rgba8_snorm", MTLPixelFormatRGBA8Snorm }, + {"rgba16_snorm", MTLPixelFormatRGBA16Snorm }, + + {"r8ui", MTLPixelFormatR8Uint }, + {"r16ui", MTLPixelFormatR16Uint }, + {"r32ui", MTLPixelFormatR32Uint }, + {"rg8ui", MTLPixelFormatRG8Uint }, + {"rg16ui", MTLPixelFormatRG16Uint }, + {"rg32ui", MTLPixelFormatRG32Uint }, + {"rgba8ui", MTLPixelFormatRGBA8Uint }, + {"rgba16ui", MTLPixelFormatRGBA16Uint }, + {"rgba32ui", MTLPixelFormatRGBA32Uint }, + {"rgb10_a2ui", MTLPixelFormatRGB10A2Uint }, + + {"r8i", MTLPixelFormatR8Sint }, + {"r16i", MTLPixelFormatR16Sint }, + {"r32i", MTLPixelFormatR32Sint }, + {"rg8i", MTLPixelFormatRG8Sint }, + {"rg16i", MTLPixelFormatRG16Sint }, + {"rg32i", MTLPixelFormatRG32Sint }, + {"rgba8i", MTLPixelFormatRGBA8Sint }, + {"rgba16i", MTLPixelFormatRGBA16Sint }, + {"rgba32i", MTLPixelFormatRGBA32Sint }, + + { NULL, MTLPixelFormatInvalid }, +}; + +static MTLPixelFormat get_mtl_fmt(const char* glsl) +{ + if (!glsl) + return MTLPixelFormatInvalid; + + for (int i = 0; mtl_fmts[i].glsl; i++) { + if (!strcmp(glsl, mtl_fmts[i].glsl)) + return mtl_fmts[i].mtl; + } + + return MTLPixelFormatInvalid; +} + +static int mapper_map(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + pl_gpu gpu = ra_pl_get(mapper->owner->ra_ctx->ra); + + CVPixelBufferRelease(p->pbuf); + 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); + + for (int i = 0; i < p->desc.num_planes; i++) { + const struct ra_format *fmt = p->desc.planes[i]; + + pl_fmt plfmt = ra_pl_fmt_get(fmt); + MTLPixelFormat format = get_mtl_fmt(plfmt->glsl_format); + + if (!format) { + MP_ERR(mapper, "Format unsupported.\n"); + return -1; + } + + size_t width = CVPixelBufferGetWidthOfPlane(p->pbuf, i), + height = CVPixelBufferGetHeightOfPlane(p->pbuf, i); + + CVReturn err = CVMetalTextureCacheCreateTextureFromImage( + kCFAllocatorDefault, + p->mtl_texture_cache, + p->pbuf, + NULL, + format, + width, + height, + i, + &p->mtl_planes[i]); + + if (err != noErr) { + MP_ERR(mapper, "error creating texture for plane %d: %d\n", i, err); + return -1; + } + + struct pl_tex_params tex_params = { + .w = width, + .h = height, + .d = 0, + .format = plfmt, + .sampleable = true, + .import_handle = PL_HANDLE_MTL_TEX, + .shared_mem = (struct pl_shared_mem) { + .handle = { + .handle = CVMetalTextureGetTexture(p->mtl_planes[i]), + }, + }, + }; + + pl_tex pltex = pl_tex_create(gpu, &tex_params); + if (!pltex) + return -1; + + struct ra_tex *ratex = talloc_ptrtype(NULL, ratex); + int ret = mppl_wrap_tex(mapper->ra, pltex, ratex); + if (!ret) { + pl_tex_destroy(gpu, &pltex); + talloc_free(ratex); + return -1; + } + mapper->tex[i] = ratex; + } + + return 0; +} + +static void mapper_uninit(struct ra_hwdec_mapper *mapper) +{ + struct priv *p = mapper->priv; + + CVPixelBufferRelease(p->pbuf); + if (p->mtl_texture_cache) { + CFRelease(p->mtl_texture_cache); + p->mtl_texture_cache = NULL; + } +} + +bool vt_pl_init(const struct ra_hwdec *hw) +{ + struct priv_owner *p = hw->priv; + + if (!check_hwdec(hw)) + return false; + + p->interop_init = mapper_init; + p->interop_uninit = mapper_uninit; + p->interop_map = mapper_map; + p->interop_unmap = mapper_unmap; + + return true; +} |