From 046a0e24d92593407313243886ecfac4bea31be0 Mon Sep 17 00:00:00 2001 From: ourfor Date: Sat, 26 Apr 2025 13:25:22 +0800 Subject: [PATCH] video/out/d3d11: add d3d11 composition mode support --- DOCS/interface-changes/vo-d3d11.txt | 1 + DOCS/man/input.rst | 6 ++++++ DOCS/man/options.rst | 8 ++++++++ player/command.c | 20 ++++++++++++++++++- video/out/d3d11/context.c | 31 +++++++++++++++++++++++------ video/out/gpu/context.h | 1 + video/out/gpu/d3d11_helpers.c | 8 +++++++- video/out/vo.c | 5 +++++ video/out/vo.h | 4 ++++ video/out/w32_common.c | 5 +++++ video/out/w32_common.h | 1 + 11 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 DOCS/interface-changes/vo-d3d11.txt diff --git a/DOCS/interface-changes/vo-d3d11.txt b/DOCS/interface-changes/vo-d3d11.txt new file mode 100644 index 0000000000000..101b340b3336e --- /dev/null +++ b/DOCS/interface-changes/vo-d3d11.txt @@ -0,0 +1 @@ +add `--d3d11-output-mode` enable use specific output mode for creating the D3D11 swapchain. diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 4e594f5e3671b..f25c56323f63c 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -3015,6 +3015,12 @@ Property list Read-only - mpv's window id. May not always be available, i.e due to window not being opened yet or not being supported by the VO. +``display-swapchain`` + Read-only - Direct3D 11 swapchain address. Returns an int64 type value + representing the memory address of the D3D11 swapchain. May not always be + available, i.e d3d11-output-mode is not set to ``composition`` or the VO + does not support it. + ``mouse-pos`` Read-only - last known mouse position, normalized to OSD dimensions. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 93841aa53bf52..2fd83fdc8edec 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6124,6 +6124,14 @@ them. support D3D11. While the extended GPU features will work with WARP, they can be very slow. +``--d3d11-output-mode=`` + Use a specific output mode for creating the D3D11 swapchain. "composition" + will not create a window. If you want to use the D3D11 GPU backend in WinUI + applications, you need to set this to "composition". "window" will create + a window and use the DWM to present the video. "auto" is the same as + "window". After creating the swapchain, you can get the swapchain address + (int64 type value) by getting the ``display-swapchain`` property. + ``--d3d11-feature-level=<12_1|12_0|11_1|11_0|10_1|10_0|9_3|9_2|9_1>`` Select a specific feature level when using the D3D11 GPU backend. By default, the highest available feature level is used. This option can be diff --git a/player/command.c b/player/command.c index 8a45b0ef161e0..16e3460b3d2a1 100644 --- a/player/command.c +++ b/player/command.c @@ -2512,6 +2512,23 @@ static struct mp_image_params get_video_out_params(struct MPContext *mpctx) return o_params; } +static int mp_property_vo_display_swapchain(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + struct vo *vo = mpctx->video_out; + if (!vo) + return M_PROPERTY_UNAVAILABLE; + + void *swapchain_ptr = vo_get_display_swapchain(vo); + if (swapchain_ptr == NULL) + return M_PROPERTY_UNAVAILABLE; + + int64_t swapchain = (intptr_t)swapchain_ptr; + + return m_property_int64_ro(action, arg, swapchain); +} + static int mp_property_vo_imgparams(void *ctx, struct m_property *prop, int action, void *arg) { @@ -2834,7 +2851,7 @@ static int mp_property_display_names(void *ctx, struct m_property *prop, { MPContext *mpctx = ctx; struct vo *vo = mpctx->video_out; - if (!vo) + if (!vo || vo->display_swapchain) return M_PROPERTY_UNAVAILABLE; switch (action) { @@ -4318,6 +4335,7 @@ static const struct m_property mp_properties_base[] = { {"deinterlace-active", mp_property_deinterlace}, {"idle-active", mp_property_idle}, {"window-id", mp_property_window_id}, + {"display-swapchain", mp_property_vo_display_swapchain}, {"chapter-list", mp_property_list_chapters}, {"track-list", mp_property_list_tracks}, diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c index 1395d00b31354..a692f20ea0268 100644 --- a/video/out/d3d11/context.c +++ b/video/out/d3d11/context.c @@ -36,6 +36,7 @@ struct d3d11_opts { int output_format; int color_space; bool exclusive_fs; + int output_mode; }; #define OPT_BASE_STRUCT struct d3d11_opts @@ -82,6 +83,12 @@ const struct m_sub_options d3d11_conf = { .flags = UPDATE_VO, }, {"d3d11-exclusive-fs", OPT_BOOL(exclusive_fs)}, + {"d3d11-output-mode", OPT_CHOICE(output_mode, + {"auto", -1}, + {"window", 0}, + {"composition", 1}), + .flags = UPDATE_VO, + }, {0} }, .defaults = &(const struct d3d11_opts) { @@ -92,6 +99,7 @@ const struct m_sub_options d3d11_conf = { .adapter_name = NULL, .output_format = DXGI_FORMAT_UNKNOWN, .color_space = -1, + .output_mode = -1, }, .size = sizeof(struct d3d11_opts) }; @@ -157,7 +165,8 @@ static bool resize(struct ra_ctx *ctx) static bool d3d11_reconfig(struct ra_ctx *ctx) { - vo_w32_config(ctx->vo); + if (!ctx->opts.composition) + vo_w32_config(ctx->vo); return resize(ctx); } @@ -454,7 +463,7 @@ static int d3d11_control(struct ra_ctx *ctx, int *events, int request, void *arg fullscreen_switch_needed = false; } - ret = vo_w32_control(ctx->vo, events, request, arg); + ret = ctx->opts.composition ? VO_TRUE : vo_w32_control(ctx->vo, events, request, arg); // if entering full screen, handle d3d11 after general windowing stuff if (fullscreen_switch_needed && p->vo_opts->fullscreen) { @@ -481,7 +490,11 @@ static void d3d11_uninit(struct ra_ctx *ctx) if (ctx->ra) ra_tex_free(ctx->ra, &p->backbuffer); SAFE_RELEASE(p->swapchain); - vo_w32_uninit(ctx->vo); + if (!ctx->opts.composition) { + vo_w32_uninit(ctx->vo); + } else { + vo_w32_swapchain(ctx->vo, NULL); + } SAFE_RELEASE(p->device); // Destroy the RA last to prevent objects we hold from showing up in D3D's @@ -534,10 +547,11 @@ static bool d3d11_init(struct ra_ctx *ctx) if (!ctx->ra) goto error; - if (!vo_w32_init(ctx->vo)) + ctx->opts.composition = p->opts->output_mode == 1; + if (!ctx->opts.composition && !vo_w32_init(ctx->vo)) goto error; - if (ctx->opts.want_alpha) + if (!ctx->opts.composition && ctx->opts.want_alpha) vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha); UINT usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT; @@ -548,7 +562,7 @@ static bool d3d11_init(struct ra_ctx *ctx) } struct d3d11_swapchain_opts scopts = { - .window = vo_w32_hwnd(ctx->vo), + .window = ctx->opts.composition ? NULL : vo_w32_hwnd(ctx->vo), .width = ctx->vo->dwidth, .height = ctx->vo->dheight, .format = p->opts->output_format, @@ -563,6 +577,9 @@ static bool d3d11_init(struct ra_ctx *ctx) if (!mp_d3d11_create_swapchain(p->device, ctx->log, &scopts, &p->swapchain)) goto error; + if (ctx->opts.composition) + vo_w32_swapchain(ctx->vo, p->swapchain); + return true; error: @@ -572,6 +589,8 @@ static bool d3d11_init(struct ra_ctx *ctx) static void d3d11_update_render_opts(struct ra_ctx *ctx) { + if (ctx->opts.composition) + return; vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha); } diff --git a/video/out/gpu/context.h b/video/out/gpu/context.h index 6773f061ca325..02799d60f59b9 100644 --- a/video/out/gpu/context.h +++ b/video/out/gpu/context.h @@ -12,6 +12,7 @@ struct ra_ctx_opts { bool want_alpha; // create an alpha framebuffer if possible bool debug; // enable debugging layers/callbacks etc. bool probing; // the backend was auto-probed + bool composition; // enable swapchain composition struct m_obj_settings *context_list; // list of `ra_ctx_fns.name` to probe struct m_obj_settings *context_type_list; // list of `ra_ctx_fns.type` to probe }; diff --git a/video/out/gpu/d3d11_helpers.c b/video/out/gpu/d3d11_helpers.c index f4f2e534951f5..aabef45e5cc36 100644 --- a/video/out/gpu/d3d11_helpers.c +++ b/video/out/gpu/d3d11_helpers.c @@ -674,8 +674,14 @@ static HRESULT create_swapchain_1_2(ID3D11Device *dev, IDXGIFactory2 *factory, desc.BufferCount = 1; } - hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown*)dev, + if (opts->window == NULL) { + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + hr = IDXGIFactory2_CreateSwapChainForComposition(factory, (IUnknown*)dev, + &desc, NULL, &swapchain1); + } else { + hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown*)dev, opts->window, &desc, NULL, NULL, &swapchain1); + } if (FAILED(hr)) goto done; hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain, diff --git a/video/out/vo.c b/video/out/vo.c index fc90c428d5817..12113284c0f33 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -1417,6 +1417,11 @@ double vo_get_display_fps(struct vo *vo) return res; } +void * vo_get_display_swapchain(struct vo *vo) +{ + return vo->display_swapchain; +} + // Set specific event flags, and wakeup the playback core if needed. // vo_query_and_reset_events() can retrieve the events again. void vo_event(struct vo *vo, int event) diff --git a/video/out/vo.h b/video/out/vo.h index 40da6b163e9b1..4d6ab6c7158c0 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -525,6 +525,9 @@ struct vo { // current GPU context (--vo=gpu and --vo=gpu-next only) const char *context_name; + + // composition swapchain (--d3d11-output-mode=composition only) + void *display_swapchain; }; struct mpv_global; @@ -559,6 +562,7 @@ double vo_get_vsync_interval(struct vo *vo); double vo_get_estimated_vsync_interval(struct vo *vo); double vo_get_estimated_vsync_jitter(struct vo *vo); double vo_get_display_fps(struct vo *vo); +void * vo_get_display_swapchain(struct vo *vo); double vo_get_delay(struct vo *vo); void vo_discard_timing_info(struct vo *vo); struct vo_frame *vo_get_current_vo_frame(struct vo *vo); diff --git a/video/out/w32_common.c b/video/out/w32_common.c index 26dd2c36f75d4..ef5ee81ec57df 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -2499,6 +2499,11 @@ HWND vo_w32_hwnd(struct vo *vo) return w32->window; // immutable, so no synchronization needed } +void vo_w32_swapchain(struct vo *vo, void *swapchain) +{ + vo->display_swapchain = swapchain; +} + void vo_w32_run_on_thread(struct vo *vo, void (*cb)(void *ctx), void *ctx) { struct vo_w32_state *w32 = vo->w32; diff --git a/video/out/w32_common.h b/video/out/w32_common.h index bc22a2d3e0a7e..75c441634e686 100644 --- a/video/out/w32_common.h +++ b/video/out/w32_common.h @@ -31,6 +31,7 @@ void vo_w32_uninit(struct vo *vo); int vo_w32_control(struct vo *vo, int *events, int request, void *arg); void vo_w32_config(struct vo *vo); HWND vo_w32_hwnd(struct vo *vo); +void vo_w32_swapchain(struct vo *vo, void *swapchain); void vo_w32_run_on_thread(struct vo *vo, void (*cb)(void *ctx), void *ctx); void vo_w32_set_transparency(struct vo *vo, bool enable);