From 648d7859300562a99f035e06a0d42245c3c46e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Ekstr=C3=B6m?= Date: Sat, 12 Oct 2019 00:35:22 +0300 Subject: vo_gpu/d3d11: add support for configuring swap chain format Query information on the system output most linked to the swap chain, and either utilize a user-configured format, or either 8bit RGBA or 10bit RGB with 2bit alpha depending on the system output's bit depth. --- DOCS/interface-changes.rst | 2 + DOCS/man/options.rst | 12 +++++ video/out/d3d11/context.c | 9 ++++ video/out/gpu/d3d11_helpers.c | 120 +++++++++++++++++++++++++++++++++++++++++- video/out/gpu/d3d11_helpers.h | 1 + wscript | 2 +- 6 files changed, 144 insertions(+), 2 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 925a24420d..038b87b6c1 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -25,6 +25,8 @@ Interface changes :: --- mpv 0.30.0 --- + - add `--d3d11-output-format` to enable explicit selection of a D3D11 + swap chain format. - rewrite DVB channel switching to use an integer value `--dvbin-channel-switch-offset` for switching instead of the old stream controls which are now gone. Cycling this property up or down will diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 277bf0df12..b6263f0485 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4708,6 +4708,18 @@ The following video options are currently all specific to ``--vo=gpu`` and functionality to receive a device, such as D3D11VA or DXVA2's DXGI mode, will be affected by this choice. +``--d3d11-output-format=`` + Select a specific D3D11 output format to utilize for D3D11 rendering. + "auto" is the default, which will pick either rgba8 or rgb10_a2 depending + on the configured desktop bit depth. rgba16f and bgra8 are left out of + the autodetection logic, and are available for manual testing. + + .. note:: + + Desktop bit depth querying is only available from an API available + from Windows 10. Thus on older systems it will only automatically + utilize the rgba8 output format. + ``--d3d11va-zero-copy=`` By default, when using hardware decoding with ``--gpu-api=d3d11``, the video image will be copied (GPU-to-GPU) from the decoder surface to a diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c index 003e3ff173..d2062a5619 100644 --- a/video/out/d3d11/context.c +++ b/video/out/d3d11/context.c @@ -36,6 +36,7 @@ struct d3d11_opts { int flip; int sync_interval; char *adapter_name; + int output_format; }; #define OPT_BASE_STRUCT struct d3d11_opts @@ -59,6 +60,12 @@ const struct m_sub_options d3d11_conf = { OPT_INTRANGE("d3d11-sync-interval", sync_interval, 0, 0, 4), OPT_STRING_VALIDATE("d3d11-adapter", adapter_name, 0, d3d11_validate_adapter), + OPT_CHOICE("d3d11-output-format", output_format, 0, + ({"auto", DXGI_FORMAT_UNKNOWN}, + {"rgba8", DXGI_FORMAT_R8G8B8A8_UNORM}, + {"bgra8", DXGI_FORMAT_B8G8R8A8_UNORM}, + {"rgb10_a2", DXGI_FORMAT_R10G10B10A2_UNORM}, + {"rgba16f", DXGI_FORMAT_R16G16B16A16_FLOAT})), {0} }, .defaults = &(const struct d3d11_opts) { @@ -67,6 +74,7 @@ const struct m_sub_options d3d11_conf = { .flip = 1, .sync_interval = 1, .adapter_name = NULL, + .output_format = DXGI_FORMAT_UNKNOWN, }, .size = sizeof(struct d3d11_opts) }; @@ -372,6 +380,7 @@ static bool d3d11_init(struct ra_ctx *ctx) .window = vo_w32_hwnd(ctx->vo), .width = ctx->vo->dwidth, .height = ctx->vo->dheight, + .format = p->opts->output_format, .flip = p->opts->flip, // Add one frame for the backbuffer and one frame of "slack" to reduce // contention with the window manager when acquiring the backbuffer diff --git a/video/out/gpu/d3d11_helpers.c b/video/out/gpu/d3d11_helpers.c index 14a30faa86..9e05b7b878 100644 --- a/video/out/gpu/d3d11_helpers.c +++ b/video/out/gpu/d3d11_helpers.c @@ -17,7 +17,8 @@ #include #include -#include +#include +#include #include #include "common/common.h" @@ -62,6 +63,71 @@ static bool load_d3d11_functions(struct mp_log *log) return true; } +static bool query_output_format_and_colorspace(struct mp_log *log, + IDXGISwapChain *swapchain, + DXGI_FORMAT *out_fmt, + DXGI_COLOR_SPACE_TYPE *out_cspace) +{ + IDXGIOutput *output = NULL; + IDXGIOutput6 *output6 = NULL; + DXGI_OUTPUT_DESC1 desc = { 0 }; + char *monitor_name = NULL; + bool success = false; + + if (!out_fmt || !out_cspace) + return false; + + HRESULT hr = IDXGISwapChain_GetContainingOutput(swapchain, &output); + if (FAILED(hr)) { + mp_err(log, "Failed to get swap chain's containing output: %s!\n", + mp_HRESULT_to_str(hr)); + goto done; + } + + hr = IDXGIOutput_QueryInterface(output, &IID_IDXGIOutput6, + (void**)&output6); + if (FAILED(hr)) { + // point where systems older than Windows 10 would fail, + // thus utilizing error log level only with windows 10+ + mp_msg(log, IsWindows10OrGreater() ? MSGL_ERR : MSGL_V, + "Failed to create a DXGI 1.6 output interface: %s\n", + mp_HRESULT_to_str(hr)); + goto done; + } + + hr = IDXGIOutput6_GetDesc1(output6, &desc); + if (FAILED(hr)) { + mp_err(log, "Failed to query swap chain's output information: %s\n", + mp_HRESULT_to_str(hr)); + goto done; + } + + monitor_name = mp_to_utf8(NULL, desc.DeviceName); + + mp_verbose(log, "Queried output: %s, %ldx%ld @ %d bits, colorspace: %d\n", + monitor_name, + desc.DesktopCoordinates.right - desc.DesktopCoordinates.left, + desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top, + desc.BitsPerColor, desc.ColorSpace); + + *out_cspace = desc.ColorSpace; + + // limit ourselves to the 8bit and 10bit formats for now. + // while the 16bit float format would be preferable as something + // to default to, it seems to be hard-coded to linear transfer + // in windowed mode, and follows configured colorspace in full screen. + *out_fmt = desc.BitsPerColor > 8 ? + DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM; + + success = true; + +done: + talloc_free(monitor_name); + SAFE_RELEASE(output6); + SAFE_RELEASE(output); + return success; +} + // Get a const array of D3D_FEATURE_LEVELs from max_fl to min_fl (inclusive) static int get_feature_levels(int max_fl, int min_fl, const D3D_FEATURE_LEVEL **out) @@ -400,6 +466,56 @@ static HRESULT create_swapchain_1_1(ID3D11Device *dev, IDXGIFactory1 *factory, swapchain_out); } +static bool update_swapchain_format(struct mp_log *log, + IDXGISwapChain *swapchain, + DXGI_FORMAT format) +{ + DXGI_SWAP_CHAIN_DESC desc; + + HRESULT hr = IDXGISwapChain_GetDesc(swapchain, &desc); + if (FAILED(hr)) { + mp_fatal(log, "Failed to query swap chain's current state: %s\n", + mp_HRESULT_to_str(hr)); + return false; + } + + hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, desc.BufferDesc.Width, + desc.BufferDesc.Height, + format, 0); + if (FAILED(hr)) { + mp_fatal(log, "Couldn't update swapchain format: %s\n", + mp_HRESULT_to_str(hr)); + return false; + } + + return true; +} + +static bool configure_created_swapchain(struct mp_log *log, + IDXGISwapChain *swapchain, + DXGI_FORMAT requested_format) +{ + DXGI_FORMAT probed_format = DXGI_FORMAT_UNKNOWN; + DXGI_FORMAT selected_format = DXGI_FORMAT_UNKNOWN; + DXGI_COLOR_SPACE_TYPE probed_colorspace; + + query_output_format_and_colorspace(log, swapchain, + &probed_format, + &probed_colorspace); + + + selected_format = requested_format != DXGI_FORMAT_UNKNOWN ? + requested_format : + (probed_format != DXGI_FORMAT_UNKNOWN ? + probed_format : DXGI_FORMAT_R8G8B8A8_UNORM); + + mp_verbose(log, "Selected swapchain format %d, attempting " + "to utilize it.\n", + selected_format); + + return update_swapchain_format(log, swapchain, selected_format); +} + // Create a Direct3D 11 swapchain bool mp_d3d11_create_swapchain(ID3D11Device *dev, struct mp_log *log, struct d3d11_swapchain_opts *opts, @@ -472,6 +588,8 @@ bool mp_d3d11_create_swapchain(ID3D11Device *dev, struct mp_log *log, mp_verbose(log, "Using DXGI 1.1\n"); } + configure_created_swapchain(log, swapchain, opts->format); + DXGI_SWAP_CHAIN_DESC scd = {0}; IDXGISwapChain_GetDesc(swapchain, &scd); if (scd.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) { diff --git a/video/out/gpu/d3d11_helpers.h b/video/out/gpu/d3d11_helpers.h index 705c5a59cb..cd22d4b145 100644 --- a/video/out/gpu/d3d11_helpers.h +++ b/video/out/gpu/d3d11_helpers.h @@ -71,6 +71,7 @@ struct d3d11_swapchain_opts { HWND window; int width; int height; + DXGI_FORMAT format; // Use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL if possible bool flip; diff --git a/wscript b/wscript index 696636758b..5baa274645 100644 --- a/wscript +++ b/wscript @@ -770,7 +770,7 @@ video_output_features = [ 'name': '--d3d11', 'desc': 'Direct3D 11 video output', 'deps': 'win32-desktop && shaderc && spirv-cross', - 'func': check_cc(header_name=['d3d11_1.h', 'dxgi1_2.h']), + 'func': check_cc(header_name=['d3d11_1.h', 'dxgi1_6.h']), }, { 'name': '--rpi', 'desc': 'Raspberry Pi support', -- cgit v1.2.3