diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 2a4838ead5abe..6b9e20158625a 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -33,6 +33,9 @@ API changes :: --- mpv 0.40.0 --- + 2.6 - add MPV_RENDER_API_TYPE_D3D11 render API backend, along with + MPV_RENDER_PARAM_D3D11_INIT_PARAMS and MPV_RENDER_PARAM_D3D11_FBO, + and a new render_d3d11.h header. 2.5 - Deprecate MPV_RENDER_PARAM_AMBIENT_LIGHT. no replacement. --- mpv 0.39.0 --- 2.4 - mpv_render_param with the MPV_RENDER_PARAM_ICC_PROFILE argument no diff --git a/DOCS/interface-changes/libmpv-d3d11.txt b/DOCS/interface-changes/libmpv-d3d11.txt new file mode 100644 index 0000000000000..e45d5f54babf4 --- /dev/null +++ b/DOCS/interface-changes/libmpv-d3d11.txt @@ -0,0 +1 @@ +add `MPV_RENDER_API_TYPE_D3D11` render API with `MPV_RENDER_PARAM_D3D11_INIT_PARAMS` and `MPV_RENDER_PARAM_D3D11_FBO`, see `mpv/render_d3d11.h` diff --git a/include/mpv/client.h b/include/mpv/client.h index f72a0e0a46a01..f970b9ab5dc79 100644 --- a/include/mpv/client.h +++ b/include/mpv/client.h @@ -248,7 +248,7 @@ extern "C" { * relational operators (<, >, <=, >=). */ #define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL) -#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(2, 5) +#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(2, 6) /** * The API user is allowed to "#define MPV_ENABLE_DEPRECATED 0" before diff --git a/include/mpv/render.h b/include/mpv/render.h index 99aadeb5d837d..cdbf6dd397ebc 100644 --- a/include/mpv/render.h +++ b/include/mpv/render.h @@ -49,6 +49,7 @@ extern "C" { * Supported backends * ------------------ * + * Direct3D 11: via MPV_RENDER_API_TYPE_D3D11, see render_d3d11.h header. * OpenGL: via MPV_RENDER_API_TYPE_OPENGL, see render_gl.h header. * Software: via MPV_RENDER_API_TYPE_SW, see section "Software renderer" * @@ -422,6 +423,17 @@ typedef enum mpv_render_param_type { * See MPV_RENDER_PARAM_SW_STRIDE for alignment requirements. */ MPV_RENDER_PARAM_SW_POINTER = 20, + /** + * Required parameters for initializing the Direct3D 11 renderer. Valid + * for mpv_render_context_create(). + * Type: mpv_d3d11_init_params* + */ + MPV_RENDER_PARAM_D3D11_INIT_PARAMS = 21, + /** + * Describes a D3D11 render target. Valid for mpv_render_context_render(). + * Type: mpv_d3d11_fbo* + */ + MPV_RENDER_PARAM_D3D11_FBO = 22, } mpv_render_param_type; /** @@ -464,6 +476,8 @@ typedef struct mpv_render_param { /** * Predefined values for MPV_RENDER_PARAM_API_TYPE. */ +// See render_d3d11.h +#define MPV_RENDER_API_TYPE_D3D11 "d3d11" // See render_gl.h #define MPV_RENDER_API_TYPE_OPENGL "opengl" // See section "Software renderer" diff --git a/include/mpv/render_d3d11.h b/include/mpv/render_d3d11.h new file mode 100644 index 0000000000000..8c2c62ed572e3 --- /dev/null +++ b/include/mpv/render_d3d11.h @@ -0,0 +1,104 @@ +/* Copyright (C) 2024 the mpv developers + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MPV_CLIENT_API_RENDER_D3D11_H_ +#define MPV_CLIENT_API_RENDER_D3D11_H_ + +#include "render.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Direct3D 11 backend + * ------------------- + * + * This header contains definitions for using Direct3D 11 with the render.h + * API. + * + * API use + * ------- + * + * The mpv_render_* API is used. That API supports multiple backends, and this + * section documents specifics for the Direct3D 11 backend. + * + * Use mpv_render_context_create() with MPV_RENDER_PARAM_API_TYPE set to + * MPV_RENDER_API_TYPE_D3D11, and MPV_RENDER_PARAM_D3D11_INIT_PARAMS provided. + * + * Call mpv_render_context_render() with MPV_RENDER_PARAM_D3D11_FBO to render + * the video frame to a D3D11 texture. The API user is responsible for creating + * and presenting the texture (for example, via a DXGI swap chain). + * + * Threading + * --------- + * + * Unlike OpenGL, Direct3D 11 does not use a per-thread implicit context. Any + * thread may call the mpv_render_* functions with this backend, subject to the + * general restrictions described in render.h. + * + * The ID3D11Device passed in mpv_d3d11_init_params must be usable from the + * thread that calls the mpv_render_* functions. An ID3D11Device created with + * D3D11_CREATE_DEVICE_SINGLETHREADED is therefore not supported. + */ + +/** + * For initializing the mpv D3D11 state via MPV_RENDER_PARAM_D3D11_INIT_PARAMS. + */ +typedef struct mpv_d3d11_init_params { + /** + * The ID3D11Device to use for rendering. libmpv will add a reference to + * the device, so it is safe to release the caller's reference after + * mpv_render_context_create() returns. + * + * The device must remain valid until mpv_render_context_free() is called. + * + * Type: ID3D11Device* + */ + void *device; +} mpv_d3d11_init_params; + +/** + * For MPV_RENDER_PARAM_D3D11_FBO. + */ +typedef struct mpv_d3d11_fbo { + /** + * The D3D11 texture to render into. This must be a 2D texture + * (ID3D11Texture2D) created on the same ID3D11Device that was passed to + * mpv_render_context_create() via mpv_d3d11_init_params. + * + * The texture must have been created with at least the + * D3D11_BIND_RENDER_TARGET bind flag and D3D11_USAGE_DEFAULT usage. It + * must not be multisampled, a texture array, or mipmapped. + * + * The texture is owned by the caller. libmpv does not take a reference, + * so the caller must ensure the texture remains valid for the duration of + * the mpv_render_context_render() call. + * + * Type: ID3D11Texture2D* + */ + void *tex; + /** + * Dimensions of the render target in pixels. Must always be set, and must + * match the actual size of the texture. + */ + int w, h; +} mpv_d3d11_fbo; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/meson.build b/meson.build index a40e4f1aec520..6fe4a6f533c4b 100644 --- a/meson.build +++ b/meson.build @@ -1039,7 +1039,8 @@ d3d11 = get_option('d3d11').require( features += {'d3d11': d3d11.allowed()} if features['d3d11'] sources += files('video/out/d3d11/context.c', - 'video/out/d3d11/ra_d3d11.c') + 'video/out/d3d11/ra_d3d11.c', + 'video/out/d3d11/libmpv_d3d11.c') endif wayland = { @@ -1816,7 +1817,8 @@ if get_option('libmpv') description: 'mpv media player client library') headers = ['include/mpv/client.h', 'include/mpv/render.h', - 'include/mpv/render_gl.h', 'include/mpv/stream_cb.h'] + 'include/mpv/render_d3d11.h', 'include/mpv/render_gl.h', + 'include/mpv/stream_cb.h'] install_headers(headers, subdir: 'mpv') # Allow projects to build with libmpv by cloning into ./subprojects/mpv diff --git a/video/out/d3d11/libmpv_d3d11.c b/video/out/d3d11/libmpv_d3d11.c new file mode 100644 index 0000000000000..a5a25bab67ebb --- /dev/null +++ b/video/out/d3d11/libmpv_d3d11.c @@ -0,0 +1,109 @@ +/* + * 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 "common/msg.h" +#include "mpv/render_d3d11.h" +#include "osdep/windows_utils.h" +#include "ra_d3d11.h" +#include "video/out/gpu/libmpv_gpu.h" +#include "video/out/gpu/ra.h" + +struct priv { + ID3D11Device *device; + struct ra_tex *wrapped_tex; + ID3D11Texture2D *wrapped_d3d_tex; +}; + +static int init(struct libmpv_gpu_context *ctx, mpv_render_param *params) +{ + struct priv *p = ctx->priv = talloc_zero(NULL, struct priv); + + mpv_d3d11_init_params *init_params = + get_mpv_render_param(params, MPV_RENDER_PARAM_D3D11_INIT_PARAMS, NULL); + if (!init_params || !init_params->device) + return MPV_ERROR_INVALID_PARAMETER; + + p->device = init_params->device; + ID3D11Device_AddRef(p->device); + + struct ra_ctx *ra_ctx = talloc_zero(p, struct ra_ctx); + ra_ctx->log = ctx->log; + ra_ctx->global = ctx->global; + + if (!spirv_compiler_init(ra_ctx)) + return MPV_ERROR_UNSUPPORTED; + + ra_ctx->ra = ra_d3d11_create(p->device, ctx->log, ra_ctx->spirv); + if (!ra_ctx->ra) + return MPV_ERROR_UNSUPPORTED; + + ctx->ra_ctx = ra_ctx; + return 0; +} + +static int wrap_fbo(struct libmpv_gpu_context *ctx, mpv_render_param *params, + struct ra_tex **out) +{ + struct priv *p = ctx->priv; + + mpv_d3d11_fbo *fbo = + get_mpv_render_param(params, MPV_RENDER_PARAM_D3D11_FBO, NULL); + if (!fbo || !fbo->tex) + return MPV_ERROR_INVALID_PARAMETER; + + // Cache the ra_tex across frames when the same D3D11 texture is reused. + // This is common for swap chain back buffers, which are recycled. + if (p->wrapped_d3d_tex != fbo->tex) { + ra_tex_free(ctx->ra_ctx->ra, &p->wrapped_tex); + p->wrapped_d3d_tex = fbo->tex; + p->wrapped_tex = ra_d3d11_wrap_tex(ctx->ra_ctx->ra, + (ID3D11Resource *)fbo->tex); + if (!p->wrapped_tex) { + p->wrapped_d3d_tex = NULL; + return MPV_ERROR_UNSUPPORTED; + } + } + + *out = p->wrapped_tex; + return 0; +} + +static void done_frame(struct libmpv_gpu_context *ctx, bool ds) +{ + ra_d3d11_flush(ctx->ra_ctx->ra); +} + +static void destroy(struct libmpv_gpu_context *ctx) +{ + struct priv *p = ctx->priv; + + if (ctx->ra_ctx && ctx->ra_ctx->ra) { + ra_tex_free(ctx->ra_ctx->ra, &p->wrapped_tex); + // ra_d3d11 frees its own struct from inside its destroy callback. + ctx->ra_ctx->ra->fns->destroy(ctx->ra_ctx->ra); + ctx->ra_ctx->ra = NULL; + } + SAFE_RELEASE(p->device); +} + +const struct libmpv_gpu_context_fns libmpv_gpu_context_d3d11 = { + .api_name = MPV_RENDER_API_TYPE_D3D11, + .init = init, + .wrap_fbo = wrap_fbo, + .done_frame = done_frame, + .destroy = destroy, +}; diff --git a/video/out/gpu/libmpv_gpu.c b/video/out/gpu/libmpv_gpu.c index 1b13c79632e5a..abeef947b68a3 100644 --- a/video/out/gpu/libmpv_gpu.c +++ b/video/out/gpu/libmpv_gpu.c @@ -6,6 +6,9 @@ #include "video/out/libmpv.h" static const struct libmpv_gpu_context_fns *context_backends[] = { +#if HAVE_D3D11 + &libmpv_gpu_context_d3d11, +#endif #if HAVE_GL &libmpv_gpu_context_gl, #endif diff --git a/video/out/gpu/libmpv_gpu.h b/video/out/gpu/libmpv_gpu.h index 497dcc3f694c8..fad1a00c0a6d9 100644 --- a/video/out/gpu/libmpv_gpu.h +++ b/video/out/gpu/libmpv_gpu.h @@ -38,3 +38,4 @@ struct libmpv_gpu_context_fns { }; extern const struct libmpv_gpu_context_fns libmpv_gpu_context_gl; +extern const struct libmpv_gpu_context_fns libmpv_gpu_context_d3d11;