summaryrefslogtreecommitdiffstats
path: root/video/out/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/gpu')
-rw-r--r--video/out/gpu/context.c211
-rw-r--r--video/out/gpu/context.h26
-rw-r--r--video/out/gpu/d3d11_helpers.c210
-rw-r--r--video/out/gpu/d3d11_helpers.h32
-rw-r--r--video/out/gpu/error_diffusion.c7
-rw-r--r--video/out/gpu/hwdec.c246
-rw-r--r--video/out/gpu/hwdec.h42
-rw-r--r--video/out/gpu/lcms.c251
-rw-r--r--video/out/gpu/lcms.h28
-rw-r--r--video/out/gpu/libmpv_gpu.c12
-rw-r--r--video/out/gpu/libmpv_gpu.h2
-rw-r--r--video/out/gpu/osd.c12
-rw-r--r--video/out/gpu/osd.h2
-rw-r--r--video/out/gpu/ra.c10
-rw-r--r--video/out/gpu/ra.h17
-rw-r--r--video/out/gpu/shader_cache.c23
-rw-r--r--video/out/gpu/shader_cache.h2
-rw-r--r--video/out/gpu/spirv.c1
-rw-r--r--video/out/gpu/user_shaders.c8
-rw-r--r--video/out/gpu/user_shaders.h2
-rw-r--r--video/out/gpu/utils.c21
-rw-r--r--video/out/gpu/utils.h5
-rw-r--r--video/out/gpu/video.c798
-rw-r--r--video/out/gpu/video.h86
-rw-r--r--video/out/gpu/video_shaders.c216
-rw-r--r--video/out/gpu/video_shaders.h16
26 files changed, 1436 insertions, 850 deletions
diff --git a/video/out/gpu/context.c b/video/out/gpu/context.c
index 39696fbd83..3202729741 100644
--- a/video/out/gpu/context.c
+++ b/video/out/gpu/context.c
@@ -37,12 +37,10 @@
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 */
@@ -50,11 +48,36 @@ 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_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 8c35eb0fc0..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,7 @@ 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.
@@ -67,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 {
@@ -95,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);
+#if HAVE_DXGI_DEBUG
+void mp_d3d11_get_debug_interfaces(struct mp_log *log, IDXGIDebug **debug,