diff options
Diffstat (limited to 'video/out/gpu')
-rw-r--r-- | video/out/gpu/context.c | 213 | ||||
-rw-r--r-- | video/out/gpu/context.h | 27 | ||||
-rw-r--r-- | video/out/gpu/d3d11_helpers.c | 210 | ||||
-rw-r--r-- | video/out/gpu/d3d11_helpers.h | 32 | ||||
-rw-r--r-- | video/out/gpu/error_diffusion.c | 7 | ||||
-rw-r--r-- | video/out/gpu/hwdec.c | 246 | ||||
-rw-r--r-- | video/out/gpu/hwdec.h | 42 | ||||
-rw-r--r-- | video/out/gpu/lcms.c | 251 | ||||
-rw-r--r-- | video/out/gpu/lcms.h | 28 | ||||
-rw-r--r-- | video/out/gpu/libmpv_gpu.c | 14 | ||||
-rw-r--r-- | video/out/gpu/libmpv_gpu.h | 2 | ||||
-rw-r--r-- | video/out/gpu/osd.c | 12 | ||||
-rw-r--r-- | video/out/gpu/osd.h | 2 | ||||
-rw-r--r-- | video/out/gpu/ra.c | 44 | ||||
-rw-r--r-- | video/out/gpu/ra.h | 19 | ||||
-rw-r--r-- | video/out/gpu/shader_cache.c | 50 | ||||
-rw-r--r-- | video/out/gpu/shader_cache.h | 6 | ||||
-rw-r--r-- | video/out/gpu/spirv.c | 3 | ||||
-rw-r--r-- | video/out/gpu/user_shaders.c | 8 | ||||
-rw-r--r-- | video/out/gpu/user_shaders.h | 2 | ||||
-rw-r--r-- | video/out/gpu/utils.c | 25 | ||||
-rw-r--r-- | video/out/gpu/utils.h | 5 | ||||
-rw-r--r-- | video/out/gpu/video.c | 994 | ||||
-rw-r--r-- | video/out/gpu/video.h | 86 | ||||
-rw-r--r-- | video/out/gpu/video_shaders.c | 382 | ||||
-rw-r--r-- | video/out/gpu/video_shaders.h | 16 |
26 files changed, 1738 insertions, 988 deletions
diff --git a/video/out/gpu/context.c b/video/out/gpu/context.c index 9561b534d8..3202729741 100644 --- a/video/out/gpu/context.c +++ b/video/out/gpu/context.c @@ -37,24 +37,47 @@ extern const struct ra_ctx_fns ra_ctx_glx; extern const struct ra_ctx_fns ra_ctx_x11_egl; extern const struct ra_ctx_fns ra_ctx_drm_egl; -extern const struct ra_ctx_fns ra_ctx_cocoa; extern const struct ra_ctx_fns ra_ctx_wayland_egl; extern const struct ra_ctx_fns ra_ctx_wgl; extern const struct ra_ctx_fns ra_ctx_angle; extern const struct ra_ctx_fns ra_ctx_dxgl; -extern const struct ra_ctx_fns ra_ctx_rpi; extern const struct ra_ctx_fns ra_ctx_android; /* Vulkan */ extern const struct ra_ctx_fns ra_ctx_vulkan_wayland; extern const struct ra_ctx_fns ra_ctx_vulkan_win; extern const struct ra_ctx_fns ra_ctx_vulkan_xlib; -extern const struct ra_ctx_fnd ra_ctx_vulkan_android; +extern const struct ra_ctx_fns ra_ctx_vulkan_android; +extern const struct ra_ctx_fns ra_ctx_vulkan_display; +extern const struct ra_ctx_fns ra_ctx_vulkan_mac; /* Direct3D 11 */ extern const struct ra_ctx_fns ra_ctx_d3d11; +/* No API */ +extern const struct ra_ctx_fns ra_ctx_wldmabuf; + +/* Autoprobe dummy. Always fails to create. */ +static bool dummy_init(struct ra_ctx *ctx) +{ + return false; +} + +static void dummy_uninit(struct ra_ctx *ctx) +{ +} + +static const struct ra_ctx_fns ra_ctx_dummy = { + .type = "auto", + .name = "auto", + .description = "Auto detect", + .init = dummy_init, + .uninit = dummy_uninit, +}; + static const struct ra_ctx_fns *contexts[] = { + &ra_ctx_dummy, +// Direct3D contexts: #if HAVE_D3D11 &ra_ctx_d3d11, #endif @@ -63,12 +86,6 @@ static const struct ra_ctx_fns *contexts[] = { #if HAVE_EGL_ANDROID &ra_ctx_android, #endif -#if HAVE_RPI - &ra_ctx_rpi, -#endif -#if HAVE_GL_COCOA - &ra_ctx_cocoa, -#endif #if HAVE_EGL_ANGLE_WIN32 &ra_ctx_angle, #endif @@ -78,7 +95,7 @@ static const struct ra_ctx_fns *contexts[] = { #if HAVE_GL_DXINTEROP &ra_ctx_dxgl, #endif -#if HAVE_GL_WAYLAND +#if HAVE_EGL_WAYLAND &ra_ctx_wayland_egl, #endif #if HAVE_EGL_X11 @@ -106,55 +123,134 @@ static const struct ra_ctx_fns *contexts[] = { #if HAVE_X11 &ra_ctx_vulkan_xlib, #endif +#if HAVE_VK_KHR_DISPLAY + &ra_ctx_vulkan_display, +#endif +#if HAVE_COCOA && HAVE_SWIFT + &ra_ctx_vulkan_mac, +#endif +#endif +}; +static const struct ra_ctx_fns *no_api_contexts[] = { + &ra_ctx_dummy, +/* No API contexts: */ +#if HAVE_DMABUF_WAYLAND + &ra_ctx_wldmabuf, #endif }; -int ra_ctx_validate_api(struct mp_log *log, const struct m_option *opt, - struct bstr name, struct bstr param) +static bool get_desc(struct m_obj_desc *dst, int index) { - if (bstr_equals0(param, "help")) { - mp_info(log, "GPU APIs (contexts):\n"); - mp_info(log, " auto (autodetect)\n"); - for (int n = 0; n < MP_ARRAY_SIZE(contexts); n++) - mp_info(log, " %s (%s)\n", contexts[n]->type, contexts[n]->name); - return M_OPT_EXIT; - } - if (bstr_equals0(param, "auto")) - return 1; + if (index >= MP_ARRAY_SIZE(contexts)) + return false; + const struct ra_ctx_fns *ctx = contexts[index]; + *dst = (struct m_obj_desc) { + .name = ctx->name, + .description = ctx->description, + }; + return true; +} + +static bool check_unknown_entry(const char *name) +{ + struct bstr param = bstr0(name); for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { - if (bstr_equals0(param, contexts[i]->type)) - return 1; + if (bstr_equals0(param, contexts[i]->name)) + return true; } - return M_OPT_INVALID; + return false; } -int ra_ctx_validate_context(struct mp_log *log, const struct m_option *opt, - struct bstr name, struct bstr param) +const struct m_obj_list ra_ctx_obj_list = { + .get_desc = get_desc, + .check_unknown_entry = check_unknown_entry, + .description = "GPU contexts", + .allow_trailer = true, + .disallow_positional_parameters = true, + .use_global_options = true, +}; + +static int ra_ctx_api_help(struct mp_log *log, const struct m_option *opt, + struct bstr name) { - if (bstr_equals0(param, "help")) { - mp_info(log, "GPU contexts (APIs):\n"); - mp_info(log, " auto (autodetect)\n"); - for (int n = 0; n < MP_ARRAY_SIZE(contexts); n++) - mp_info(log, " %s (%s)\n", contexts[n]->name, contexts[n]->type); - return M_OPT_EXIT; + mp_info(log, "GPU APIs (contexts):\n"); + for (int n = 0; n < MP_ARRAY_SIZE(contexts); n++) { + mp_info(log, " %s (%s)\n", contexts[n]->type, contexts[n]->name); } - if (bstr_equals0(param, "auto")) - return 1; + return M_OPT_EXIT; +} + +static inline OPT_STRING_VALIDATE_FUNC(ra_ctx_validate_api) +{ + struct bstr param = bstr0(*value); for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { - if (bstr_equals0(param, contexts[i]->name)) + if (bstr_equals0(param, contexts[i]->type)) return 1; } return M_OPT_INVALID; } +#define OPT_BASE_STRUCT struct ra_ctx_opts +const struct m_sub_options ra_ctx_conf = { + .opts = (const m_option_t[]) { + {"gpu-context", + OPT_SETTINGSLIST(context_list, &ra_ctx_obj_list)}, + {"gpu-api", + OPT_STRING_VALIDATE(context_type, ra_ctx_validate_api), + .help = ra_ctx_api_help}, + {"gpu-debug", OPT_BOOL(debug)}, + {"gpu-sw", OPT_BOOL(allow_sw)}, + {0} + }, + .size = sizeof(struct ra_ctx_opts), +}; + +static struct ra_ctx *create_in_contexts(struct vo *vo, const char *name, bool api_auto, + const struct ra_ctx_fns *ctxs[], + size_t size, struct ra_ctx_opts opts) +{ + for (int i = 0; i < size; i++) { + if (strcmp(name, ctxs[i]->name) != 0) + continue; + if (!api_auto && strcmp(ctxs[i]->type, opts.context_type) != 0) + continue; + struct ra_ctx *ctx = talloc_ptrtype(NULL, ctx); + *ctx = (struct ra_ctx) { + .vo = vo, + .global = vo->global, + .log = mp_log_new(ctx, vo->log, ctxs[i]->type), + .opts = opts, + .fns = ctxs[i], + }; + + MP_VERBOSE(ctx, "Initializing GPU context '%s'\n", ctx->fns->name); + if (ctxs[i]->init(ctx)) + return ctx; + talloc_free(ctx); + } + return NULL; +} + +struct ra_ctx *ra_ctx_create_by_name(struct vo *vo, const char *name) +{ + struct ra_ctx_opts dummy = {0}; + struct ra_ctx *ctx = create_in_contexts(vo, name, true, contexts, + MP_ARRAY_SIZE(contexts), dummy); + if (ctx) + return ctx; + return create_in_contexts(vo, name, true, no_api_contexts, + MP_ARRAY_SIZE(no_api_contexts), dummy); +} + // Create a VO window and create a RA context on it. // vo_flags: passed to the backend's create window function -struct ra_ctx *ra_ctx_create(struct vo *vo, const char *context_type, - const char *context_name, struct ra_ctx_opts opts) +struct ra_ctx *ra_ctx_create(struct vo *vo, struct ra_ctx_opts opts) { - bool api_auto = !context_type || strcmp(context_type, "auto") == 0; - bool ctx_auto = !context_name || strcmp(context_name, "auto") == 0; + bool api_auto = !opts.context_type || strcmp(opts.context_type, "auto") == 0; + bool ctx_auto = !opts.context_list || + (opts.context_list[0].name && + strcmp(opts.context_list[0].name, "auto") == 0); if (ctx_auto) { MP_VERBOSE(vo, "Probing for best GPU context.\n"); @@ -166,28 +262,27 @@ struct ra_ctx *ra_ctx_create(struct vo *vo, const char *context_type, bool old_probing = vo->probing; vo->probing = opts.probing; - for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { - if (!opts.probing && strcmp(contexts[i]->name, context_name) != 0) - continue; - if (!api_auto && strcmp(contexts[i]->type, context_type) != 0) - continue; - - struct ra_ctx *ctx = talloc_ptrtype(NULL, ctx); - *ctx = (struct ra_ctx) { - .vo = vo, - .global = vo->global, - .log = mp_log_new(ctx, vo->log, contexts[i]->type), - .opts = opts, - .fns = contexts[i], - }; - - MP_VERBOSE(ctx, "Initializing GPU context '%s'\n", ctx->fns->name); - if (contexts[i]->init(ctx)) { - vo->probing = old_probing; - return ctx; + struct ra_ctx *ctx = NULL; + if (opts.probing) { + for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) { + ctx = create_in_contexts(vo, contexts[i]->name, api_auto, + contexts, MP_ARRAY_SIZE(contexts), opts); + if (ctx) + goto done; } + } + for (int i = 0; opts.context_list && opts.context_list[i].name; i++) { + ctx = create_in_contexts(vo, opts.context_list[i].name, api_auto, + contexts, MP_ARRAY_SIZE(contexts), opts); + if (ctx) + goto done; + } - talloc_free(ctx); +done: + if (ctx) { + vo->probing = old_probing; + vo->context_name = ctx->fns->name; + return ctx; } vo->probing = old_probing; diff --git a/video/out/gpu/context.h b/video/out/gpu/context.h index 4cf2af9e3e..d2ab783bd7 100644 --- a/video/out/gpu/context.h +++ b/video/out/gpu/context.h @@ -3,16 +3,19 @@ #include "video/out/vo.h" #include "video/csputils.h" -#include "config.h" #include "ra.h" struct ra_ctx_opts { - int allow_sw; // allow software renderers - int want_alpha; // create an alpha framebuffer if possible - int debug; // enable debugging layers/callbacks etc. + bool allow_sw; // allow software renderers + bool want_alpha; // create an alpha framebuffer if possible + bool debug; // enable debugging layers/callbacks etc. bool probing; // the backend was auto-probed + struct m_obj_settings *context_list; // list of `ra_ctx_fns.name` to probe + char *context_type; // filter by `ra_ctx_fns.type` }; +extern const struct m_sub_options ra_ctx_conf; + struct ra_ctx { struct vo *vo; struct ra *ra; @@ -31,6 +34,7 @@ struct ra_ctx { struct ra_ctx_fns { const char *type; // API type (for --gpu-api) const char *name; // name (for --gpu-context) + const char *description; // description (for --gpu-context=help) // Resize the window, or create a new window if there isn't one yet. // Currently, there is an unfortunate interaction with ctx->vo, and @@ -43,7 +47,8 @@ struct ra_ctx_fns { // These behave exactly like vo_driver.wakeup/wait_events. They are // optional. void (*wakeup)(struct ra_ctx *ctx); - void (*wait_events)(struct ra_ctx *ctx, int64_t until_time_us); + void (*wait_events)(struct ra_ctx *ctx, int64_t until_time_ns); + void (*update_render_opts)(struct ra_ctx *ctx); // Initialize/destroy the 'struct ra' and possibly the underlying VO backend. // Not normally called by the user of the ra_ctx. @@ -66,7 +71,7 @@ struct ra_fbo { // Host system's colorspace that it will be interpreting // the frame buffer as. - struct mp_colorspace color_space; + struct pl_color_space color_space; }; struct ra_swapchain_fns { @@ -94,12 +99,8 @@ struct ra_swapchain_fns { // Create and destroy a ra_ctx. This also takes care of creating and destroying // the underlying `struct ra`, and perhaps the underlying VO backend. -struct ra_ctx *ra_ctx_create(struct vo *vo, const char *context_type, - const char *context_name, struct ra_ctx_opts opts); +struct ra_ctx *ra_ctx_create(struct vo *vo, struct ra_ctx_opts opts); void ra_ctx_destroy(struct ra_ctx **ctx); -struct m_option; -int ra_ctx_validate_api(struct mp_log *log, const struct m_option *opt, - struct bstr name, struct bstr param); -int ra_ctx_validate_context(struct mp_log *log, const struct m_option *opt, - struct bstr name, struct bstr param); +// Special case of creating a ra_ctx while specifying a specific context by name. +struct ra_ctx *ra_ctx_create_by_name(struct vo *vo, const char *name); diff --git a/video/out/gpu/d3d11_helpers.c b/video/out/gpu/d3d11_helpers.c index 33d01e0861..fa37d5ef30 100644 --- a/video/out/gpu/d3d11_helpers.c +++ b/video/out/gpu/d3d11_helpers.c @@ -19,12 +19,12 @@ #include <d3d11.h> #include <dxgi1_6.h> #include <versionhelpers.h> -#include <pthread.h> #include "common/common.h" #include "common/msg.h" #include "misc/bstr.h" #include "osdep/io.h" +#include "osdep/threads.h" #include "osdep/windows_utils.h" #include "d3d11_helpers.h" @@ -32,14 +32,17 @@ // Windows 8 enum value, not present in mingw-w64 headers #define DXGI_ADAPTER_FLAG_SOFTWARE (2) typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); +typedef HRESULT(WINAPI *PFN_DXGI_GET_DEBUG_INTERFACE)(REFIID riid, void **ppDebug); -static pthread_once_t d3d11_once = PTHREAD_ONCE_INIT; +static mp_once d3d11_once = MP_STATIC_ONCE_INITIALIZER; static PFN_D3D11_CREATE_DEVICE pD3D11CreateDevice = NULL; static PFN_CREATE_DXGI_FACTORY pCreateDXGIFactory1 = NULL; +static PFN_DXGI_GET_DEBUG_INTERFACE pDXGIGetDebugInterface = NULL; static void d3d11_load(void) { HMODULE d3d11 = LoadLibraryW(L"d3d11.dll"); HMODULE dxgilib = LoadLibraryW(L"dxgi.dll"); + HMODULE dxgidebuglib = LoadLibraryW(L"dxgidebug.dll"); if (!d3d11 || !dxgilib) return; @@ -47,11 +50,15 @@ static void d3d11_load(void) GetProcAddress(d3d11, "D3D11CreateDevice"); pCreateDXGIFactory1 = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory1"); + if (dxgidebuglib) { + pDXGIGetDebugInterface = (PFN_DXGI_GET_DEBUG_INTERFACE) + GetProcAddress(dxgidebuglib, "DXGIGetDebugInterface"); + } } static bool load_d3d11_functions(struct mp_log *log) { - pthread_once(&d3d11_once, d3d11_load); + mp_exec_once(&d3d11_once, d3d11_load); if (!pD3D11CreateDevice || !pCreateDXGIFactory1) { mp_fatal(log, "Failed to load base d3d11 functionality: " "CreateDevice: %s, CreateDXGIFactory1: %s\n", @@ -228,9 +235,9 @@ static const char *d3d11_get_csp_name(DXGI_COLOR_SPACE_TYPE csp) } static bool d3d11_get_mp_csp(DXGI_COLOR_SPACE_TYPE csp, - struct mp_colorspace *mp_csp) + struct pl_color_space *pl_color_system) { - if (!mp_csp) + if (!pl_color_system) return false; // Colorspaces utilizing gamma 2.2 (G22) are set to @@ -243,27 +250,27 @@ static bool d3d11_get_mp_csp(DXGI_COLOR_SPACE_TYPE csp, // regarding not doing conversion from BT.601 to BT.709. switch (csp) { case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709: - *mp_csp = (struct mp_colorspace){ - .gamma = MP_CSP_TRC_AUTO, - .primaries = MP_CSP_PRIM_AUTO, + *pl_color_system = (struct pl_color_space){ + .transfer = PL_COLOR_TRC_UNKNOWN, + .primaries = PL_COLOR_PRIM_UNKNOWN, }; break; case DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709: - *mp_csp = (struct mp_colorspace) { - .gamma = MP_CSP_TRC_LINEAR, - .primaries = MP_CSP_PRIM_AUTO, + *pl_color_system = (struct pl_color_space) { + .transfer = PL_COLOR_TRC_LINEAR, + .primaries = PL_COLOR_PRIM_UNKNOWN, }; break; case DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020: - *mp_csp = (struct mp_colorspace) { - .gamma = MP_CSP_TRC_PQ, - .primaries = MP_CSP_PRIM_BT_2020, + *pl_color_system = (struct pl_color_space) { + .transfer = PL_COLOR_TRC_PQ, + .primaries = PL_COLOR_PRIM_BT_2020, }; break; case DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020: - *mp_csp = (struct mp_colorspace) { - .gamma = MP_CSP_TRC_AUTO, - .primaries = MP_CSP_PRIM_BT_2020, + *pl_color_system = (struct pl_color_space) { + .transfer = PL_COLOR_TRC_UNKNOWN, + .primaries = PL_COLOR_PRIM_BT_2020, }; break; default: @@ -287,28 +294,8 @@ static bool query_output_format_and_colorspace(struct mp_log *log, 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)); + if (!mp_get_dxgi_output_desc(swapchain, &desc)) { + mp_err(log, "Failed to query swap chain's output information\n"); goto done; } @@ -371,9 +358,9 @@ static int get_feature_levels(int max_fl, int min_fl, return len; } -static IDXGIAdapter1 *get_d3d11_adapter(struct mp_log *log, - struct bstr requested_adapter_name, - struct bstr *listing) +IDXGIAdapter1 *mp_get_dxgi_adapter(struct mp_log *log, + bstr requested_adapter_name, + bstr *listing) { HRESULT hr = S_OK; IDXGIFactory1 *factory; @@ -437,6 +424,37 @@ static IDXGIAdapter1 *get_d3d11_adapter(struct mp_log *log, return picked_adapter; } +int mp_dxgi_validate_adapter(struct mp_log *log, + const struct m_option *opt, + struct bstr name, const char **value) +{ + struct bstr param = bstr0(*value); + bool help = bstr_equals0(param, "help"); + bool adapter_matched = false; + struct bstr listing = { 0 }; + + if (bstr_equals0(param, "")) { + return 0; + } + + adapter_matched = mp_dxgi_list_or_verify_adapters(log, + help ? bstr0(NULL) : param, + help ? &listing : NULL); + + if (help) { + mp_info(log, "Available DXGI adapters:\n%.*s", + BSTR_P(listing)); + talloc_free(listing.start); + return M_OPT_EXIT; + } + + if (!adapter_matched) { + mp_err(log, "No adapter matching '%.*s'!\n", BSTR_P(param)); + } + + return adapter_matched ? 0 : M_OPT_INVALID; +} + static HRESULT create_device(struct mp_log *log, IDXGIAdapter1 *adapter, bool warp, bool debug, int max_fl, int min_fl, ID3D11Device **dev) @@ -455,9 +473,9 @@ static HRESULT create_device(struct mp_log *log, IDXGIAdapter1 *adapter, NULL, flags, levels, levels_len, D3D11_SDK_VERSION, dev, NULL, NULL); } -bool mp_d3d11_list_or_verify_adapters(struct mp_log *log, - bstr adapter_name, - bstr *listing) +bool mp_dxgi_list_or_verify_adapters(struct mp_log *log, + bstr adapter_name, + bstr *listing) { IDXGIAdapter1 *picked_adapter = NULL; @@ -465,7 +483,7 @@ bool mp_d3d11_list_or_verify_adapters(struct mp_log *log, return false; } - if ((picked_adapter = get_d3d11_adapter(log, adapter_name, listing))) { + if ((picked_adapter = mp_get_dxgi_adapter(log, adapter_name, listing))) { SAFE_RELEASE(picked_adapter); return true; } @@ -480,6 +498,7 @@ bool mp_d3d11_create_present_device(struct mp_log *log, struct d3d11_device_opts *opts, ID3D11Device **dev_out) { + bool debug = opts->debug; bool warp = opts->force_warp; int max_fl = opts->max_feature_level; int min_fl = opts->min_feature_level; @@ -496,7 +515,7 @@ bool mp_d3d11_create_present_device(struct mp_log *log, goto done; } - adapter = get_d3d11_adapter(log, bstr0(adapter_name), NULL); + adapter = mp_get_dxgi_adapter(log, bstr0(adapter_name), NULL); if (adapter_name && !adapter) { mp_warn(log, "Adapter matching '%s' was not found in the system! " @@ -510,7 +529,15 @@ bool mp_d3d11_create_present_device(struct mp_log *log, max_fl = max_fl ? max_fl : D3D_FEATURE_LEVEL_11_0; min_fl = min_fl ? min_fl : D3D_FEATURE_LEVEL_9_1; - hr = create_device(log, adapter, warp, opts->debug, max_fl, min_fl, &dev); + hr = create_device(log, adapter, warp, debug, max_fl, min_fl, &dev); + + // Retry without debug, if SDK is not available + if (debug && hr == DXGI_ERROR_SDK_COMPONENT_MISSING) { + mp_warn(log, "gpu-debug disabled due to error: %s\n", mp_HRESULT_to_str(hr)); + debug = false; + continue; + } + if (SUCCEEDED(hr)) break; @@ -630,7 +657,21 @@ static HRESULT create_swapchain_1_2(ID3D11Device *dev, IDXGIFactory2 *factory, }; if (flip) { - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + // UNORDERED_ACCESS with FLIP_SEQUENTIAL seems to be buggy with + // Windows 7 drivers + if ((desc.BufferUsage & DXGI_USAGE_UNORDERED_ACCESS) && + !IsWindows8OrGreater()) + { + mp_verbose(log, "Disabling UNORDERED_ACCESS for flip-model " + "swapchain backbuffers in Windows 7\n"); + desc.BufferUsage &= ~DXGI_USAGE_UNORDERED_ACCESS; + } + + if (IsWindows10OrGreater()) { + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + } else { + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + } desc.BufferCount = opts->length; } else { desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; @@ -770,7 +811,7 @@ static bool configure_created_swapchain(struct mp_log *log, IDXGISwapChain *swapchain, DXGI_FORMAT requested_format, DXGI_COLOR_SPACE_TYPE requested_csp, - struct mp_colorspace *configured_csp) + struct pl_color_space *configured_csp) { DXGI_FORMAT probed_format = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT selected_format = DXGI_FORMAT_UNKNOWN; @@ -778,7 +819,7 @@ static bool configure_created_swapchain(struct mp_log *log, DXGI_COLOR_SPACE_TYPE selected_colorspace; const char *format_name = NULL; const char *csp_name = NULL; - struct mp_colorspace mp_csp = { 0 }; + struct pl_color_space pl_color_system = { 0 }; bool mp_csp_mapped = false; query_output_format_and_colorspace(log, swapchain, @@ -794,7 +835,7 @@ static bool configure_created_swapchain(struct mp_log *log, requested_csp : probed_colorspace; format_name = d3d11_get_format_name(selected_format); csp_name = d3d11_get_csp_name(selected_colorspace); - mp_csp_mapped = d3d11_get_mp_csp(selected_colorspace, &mp_csp); + mp_csp_mapped = d3d11_get_mp_csp(selected_colorspace, &pl_color_system); mp_verbose(log, "Selected swapchain format %s (%d), attempting " "to utilize it.\n", @@ -825,7 +866,7 @@ static bool configure_created_swapchain(struct mp_log *log, "mapping! Overriding to standard sRGB!\n", csp_name, selected_colorspace); selected_colorspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; - d3d11_get_mp_csp(selected_colorspace, &mp_csp); + d3d11_get_mp_csp(selected_colorspace, &pl_color_system); } mp_verbose(log, "Selected swapchain color space %s (%d), attempting to " @@ -837,7 +878,7 @@ static bool configure_created_swapchain(struct mp_log *log, } if (configured_csp) { - *configured_csp = mp_csp; + *configured_csp = pl_color_system; } return true; @@ -921,7 +962,9 @@ bool mp_d3d11_create_swapchain(ID3D11Device *dev, struct mp_log *log, DXGI_SWAP_CHAIN_DESC scd = {0}; IDXGISwapChain_GetDesc(swapchain, &scd); - if (scd.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) { + if (scd.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL || + scd.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD) + { mp_verbose(log, "Using flip-model presentation\n"); } else { mp_verbose(log, "Using bitblt-model presentation\n"); @@ -939,3 +982,60 @@ done: SAFE_RELEASE(dxgi_dev); return success; } + +bool mp_get_dxgi_output_desc(IDXGISwapChain *swapchain, DXGI_OUTPUT_DESC1 *desc) +{ + bool ret = false; + IDXGIOutput *output = NULL; + IDXGIOutput6 *output6 = NULL; + + if (FAILED(IDXGISwapChain_GetContainingOutput(swapchain, &output))) + goto done; + + if (FAILED(IDXGIOutput_QueryInterface(output, &IID_IDXGIOutput6, (void**)&output6))) + goto done; + + ret = SUCCEEDED(IDXGIOutput6_GetDesc1(output6, desc)); + +done: + SAFE_RELEASE(output); + SAFE_RELEASE(output6); + return ret; +} + +#if HAVE_DXGI_DEBUG +void mp_d3d11_get_debug_interfaces(struct mp_log *log, IDXGIDebug **debug, + IDXGIInfoQueue **iqueue) +{ + load_d3d11_functions(log); + + *iqueue = NULL; + *debug = NULL; + + if (!pDXGIGetDebugInterface) + return; + + HRESULT hr; + + hr = pDXGIGetDebugInterface(&IID_IDXGIInfoQueue, (void **) iqueue); + if (FAILED(hr)) { + mp_fatal(log, "Failed to get info queue: %s\n", mp_HRESULT_to_str(hr)); + return; + } + + // Store an unlimited amount of messages in the buffer. This is fine + // because we flush stored messages regularly (in debug_marker.) + IDXGIInfoQueue_SetMessageCountLimit(*iqueue, DXGI_DEBUG_D3D11, -1); + IDXGIInfoQueue_SetMessageCountLimit(*iqueue, DXGI_DEBUG_DXGI, -1); + + // Push empty filter to get everything + DXGI_INFO_QUEUE_FILTER filter = {0}; + IDXGIInfoQueue_PushStorageFilter(*iqueue, DXGI_DEBUG_ALL, &filter); + + hr = pDXGIGetDebugInterface(&IID_IDXGIDebug, (void **) debug); + if (FAILED(hr)) { + mp_fatal(log, "Failed to get debug device: %s\n", mp_HRESULT_to_str(hr)); + return; + } +} +#endif diff --git a/video/out/gpu/d3d11_helpers.h b/video/out/gpu/d3d11_helpers.h index c115d330d5..92322b9152 100644 --- a/video/out/gpu/d3d11_helpers.h +++ b/video/out/gpu/d3d11_helpers.h @@ -22,6 +22,11 @@ #include <windows.h> #include <d3d11.h> #include <dxgi1_2.h> +#include <dxgi1_6.h> + +#if HAVE_DXGI_DEBUG +#include <dxgidebug.h> +#endif #include "video/mp_image.h" @@ -34,6 +39,10 @@ #define DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020 ((DXGI_COLOR_SPACE_TYPE)23) #define DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020 ((DXGI_COLOR_SPACE_TYPE)24) +#if !HAVE_DXGI_DEBUG_D3D11 +DEFINE_GUID(DXGI_DEBUG_D3D11, 0x4b99317b, 0xac39, 0x4aa6, 0xbb, 0xb, 0xba, 0xa0, 0x47, 0x84, 0x79, 0x8f); +#endif + struct d3d11_device_opts { // Enable the debug layer (D3D11_CREATE_DEVICE_DEBUG) bool debug; @@ -65,9 +74,17 @@ struct d3d11_device_opts { char *adapter_name; }; -bool mp_d3d11_list_or_verify_adapters(struct mp_log *log, - bstr adapter_name, - bstr *listing); +IDXGIAdapter1 *mp_get_dxgi_adapter(struct mp_log *log, + bstr requested_adapter_name, + bstr *listing); + +bool mp_get_dxgi_output_desc(IDXGISwapChain *swapchain, DXGI_OUTPUT_DESC1 *desc); + +OPT_STRING_VALIDATE_FUNC(mp_dxgi_validate_adapter); + +bool mp_dxgi_list_or_verify_adapters(struct mp_log *log, + bstr adapter_name, + bstr *listing); bool mp_d3d11_create_present_device(struct mp_log *log, struct d3d11_device_opts *opts, @@ -80,10 +97,10 @@ struct d3d11_swapchain_opts { DXGI_FORMAT format; DXGI_COLOR_SPACE_TYPE color_space; - // mp_colorspace mapping of the configured swapchain colorspace + // pl_color_space mapping of the configured swapchain colorspace // shall be written into this memory location if configuration // succeeds. Will be ignored if NULL. - struct mp_colorspace *configured_csp; + struct pl_color_space *configured_csp; // Use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL if possible bool flip; @@ -100,4 +117,9 @@ bool mp_d3d11_create_swapchain(ID3D11Device *dev, struct mp_log *log, struct d3d11_swapchain_opts *opts, IDXGISwapChain **swapchain_out); + |