summaryrefslogtreecommitdiffstats
path: root/video/out/d3d11
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/d3d11')
-rw-r--r--video/out/d3d11/context.c354
-rw-r--r--video/out/d3d11/context.h13
-rw-r--r--video/out/d3d11/hwdec_d3d11va.c24
-rw-r--r--video/out/d3d11/hwdec_dxva2dxgi.c11
-rw-r--r--video/out/d3d11/ra_d3d11.c240
-rw-r--r--video/out/d3d11/ra_d3d11.h12
6 files changed, 446 insertions, 208 deletions
diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c
index bdfbacfe54..f183ae8be5 100644
--- a/video/out/d3d11/context.c
+++ b/video/out/d3d11/context.c
@@ -24,61 +24,60 @@
#include "video/out/gpu/d3d11_helpers.h"
#include "video/out/gpu/spirv.h"
#include "video/out/w32_common.h"
+#include "context.h"
#include "ra_d3d11.h"
-static int d3d11_validate_adapter(struct mp_log *log,
- const struct m_option *opt,
- struct bstr name, struct bstr param);
-
struct d3d11_opts {
int feature_level;
int warp;
- int flip;
+ bool flip;
int sync_interval;
char *adapter_name;
int output_format;
int color_space;
+ bool exclusive_fs;
};
#define OPT_BASE_STRUCT struct d3d11_opts
const struct m_sub_options d3d11_conf = {
.opts = (const struct m_option[]) {
- OPT_CHOICE("d3d11-warp", warp, 0,
- ({"auto", -1},
- {"no", 0},
- {"yes", 1})),
- OPT_CHOICE("d3d11-feature-level", feature_level, 0,
- ({"12_1", D3D_FEATURE_LEVEL_12_1},
- {"12_0", D3D_FEATURE_LEVEL_12_0},
- {"11_1", D3D_FEATURE_LEVEL_11_1},
- {"11_0", D3D_FEATURE_LEVEL_11_0},
- {"10_1", D3D_FEATURE_LEVEL_10_1},
- {"10_0", D3D_FEATURE_LEVEL_10_0},
- {"9_3", D3D_FEATURE_LEVEL_9_3},
- {"9_2", D3D_FEATURE_LEVEL_9_2},
- {"9_1", D3D_FEATURE_LEVEL_9_1})),
- OPT_FLAG("d3d11-flip", flip, 0),
- 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})),
- OPT_CHOICE("d3d11-output-csp", color_space, 0,
- ({"auto", -1},
- {"srgb", DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709},
- {"linear", DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709},
- {"pq", DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020},
- {"bt.2020", DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020})),
+ {"d3d11-warp", OPT_CHOICE(warp,
+ {"auto", -1},
+ {"no", 0},
+ {"yes", 1})},
+ {"d3d11-feature-level", OPT_CHOICE(feature_level,
+ {"12_1", D3D_FEATURE_LEVEL_12_1},
+ {"12_0", D3D_FEATURE_LEVEL_12_0},
+ {"11_1", D3D_FEATURE_LEVEL_11_1},
+ {"11_0", D3D_FEATURE_LEVEL_11_0},
+ {"10_1", D3D_FEATURE_LEVEL_10_1},
+ {"10_0", D3D_FEATURE_LEVEL_10_0},
+ {"9_3", D3D_FEATURE_LEVEL_9_3},
+ {"9_2", D3D_FEATURE_LEVEL_9_2},
+ {"9_1", D3D_FEATURE_LEVEL_9_1})},
+ {"d3d11-flip", OPT_BOOL(flip)},
+ {"d3d11-sync-interval", OPT_INT(sync_interval), M_RANGE(0, 4)},
+ {"d3d11-adapter", OPT_STRING_VALIDATE(adapter_name,
+ mp_dxgi_validate_adapter)},
+ {"d3d11-output-format", OPT_CHOICE(output_format,
+ {"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})},
+ {"d3d11-output-csp", OPT_CHOICE(color_space,
+ {"auto", -1},
+ {"srgb", DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709},
+ {"linear", DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709},
+ {"pq", DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020},
+ {"bt.2020", DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020})},
+ {"d3d11-exclusive-fs", OPT_BOOL(exclusive_fs)},
{0}
},
.defaults = &(const struct d3d11_opts) {
.feature_level = D3D_FEATURE_LEVEL_12_1,
.warp = -1,
- .flip = 1,
+ .flip = true,
.sync_interval = 1,
.adapter_name = NULL,
.output_format = DXGI_FORMAT_UNKNOWN,
@@ -89,49 +88,23 @@ const struct m_sub_options d3d11_conf = {
struct priv {
struct d3d11_opts *opts;
+ struct m_config_cache *opts_cache;
+
+ struct mp_vo_opts *vo_opts;
+ struct m_config_cache *vo_opts_cache;
struct ra_tex *backbuffer;
ID3D11Device *device;
IDXGISwapChain *swapchain;
- struct mp_colorspace swapchain_csp;
+ struct pl_color_space swapchain_csp;
int64_t perf_freq;
- unsigned last_sync_refresh_count;
- int64_t last_sync_qpc_time;
+ unsigned sync_refresh_count;
+ int64_t sync_qpc_time;
int64_t vsync_duration_qpc;
int64_t last_submit_qpc;
};
-static int d3d11_validate_adapter(struct mp_log *log,
- const struct m_option *opt,
- struct bstr name, struct bstr param)
-{
- bool help = bstr_equals0(param, "help");
- bool adapter_matched = false;
- struct bstr listing = { 0 };
-
- if (bstr_equals0(param, "")) {
- return 0;
- }
-
- adapter_matched = mp_d3d11_list_or_verify_adapters(log,
- help ? bstr0(NULL) : param,
- help ? &listing : NULL);
-
- if (help) {
- mp_info(log, "Available D3D11 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 struct ra_tex *get_backbuffer(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
@@ -157,7 +130,10 @@ static bool resize(struct ra_ctx *ctx)
struct priv *p = ctx->priv;
HRESULT hr;
- ra_tex_free(ctx->ra, &p->backbuffer);
+ if (p->backbuffer) {
+ MP_ERR(ctx, "Attempt at resizing while a frame was in progress!\n");
+ return false;
+ }
hr = IDXGISwapChain_ResizeBuffers(p->swapchain, 0, ctx->vo->dwidth,
ctx->vo->dheight, DXGI_FORMAT_UNKNOWN, 0);
@@ -166,8 +142,6 @@ static bool resize(struct ra_ctx *ctx)
return false;
}
- p->backbuffer = get_backbuffer(ctx);
-
return true;
}
@@ -181,16 +155,37 @@ static int d3d11_color_depth(struct ra_swapchain *sw)
{
struct priv *p = sw->priv;
- if (!p->backbuffer)
+ DXGI_OUTPUT_DESC1 desc1;
+ if (mp_get_dxgi_output_desc(p->swapchain, &desc1))
+ return desc1.BitsPerColor;
+
+ DXGI_SWAP_CHAIN_DESC desc;
+
+ HRESULT hr = IDXGISwapChain_GetDesc(p->swapchain, &desc);
+ if (FAILED(hr)) {
+ MP_ERR(sw->ctx, "Failed to query swap chain description: %s!\n",
+ mp_HRESULT_to_str(hr));
+ return 0;
+ }
+
+ const struct ra_format *ra_fmt =
+ ra_d3d11_get_ra_format(sw->ctx->ra, desc.BufferDesc.Format);
+ if (!ra_fmt)
return 0;
- return p->backbuffer->params.format->component_depth[0];
+ return ra_fmt->component_depth[0];
}
static bool d3d11_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
{
struct priv *p = sw->priv;
+ if (!out_fbo)
+ return true;
+
+ assert(!p->backbuffer);
+
+ p->backbuffer = get_backbuffer(sw->ctx);
if (!p->backbuffer)
return false;
@@ -205,32 +200,37 @@ static bool d3d11_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
static bool d3d11_submit_frame(struct ra_swapchain *sw,
const struct vo_frame *frame)
{
+ struct priv *p = sw->priv;
+
ra_d3d11_flush(sw->ctx->ra);
+ ra_tex_free(sw->ctx->ra, &p->backbuffer);
return true;
}
-static int64_t qpc_to_us(struct ra_swapchain *sw, int64_t qpc)
+static int64_t qpc_to_ns(struct ra_swapchain *sw, int64_t qpc)
{
struct priv *p = sw->priv;
- // Convert QPC units (1/perf_freq seconds) to microseconds. This will work
+ // Convert QPC units (1/perf_freq seconds) to nanoseconds. This will work
// without overflow because the QPC value is guaranteed not to roll-over
// within 100 years, so perf_freq must be less than 2.9*10^9.
- return qpc / p->perf_freq * 1000000 +
- qpc % p->perf_freq * 1000000 / p->perf_freq;
+ return qpc / p->perf_freq * INT64_C(1000000000) +
+ qpc % p->perf_freq * INT64_C(1000000000) / p->perf_freq;
}
-static int64_t qpc_us_now(struct ra_swapchain *sw)
+static int64_t qpc_ns_now(struct ra_swapchain *sw)
{
LARGE_INTEGER perf_count;
QueryPerformanceCounter(&perf_count);
- return qpc_to_us(sw, perf_count.QuadPart);
+ return qpc_to_ns(sw, perf_count.QuadPart);
}
static void d3d11_swap_buffers(struct ra_swapchain *sw)
{
struct priv *p = sw->priv;
+ m_config_cache_update(p->opts_cache);
+
LARGE_INTEGER perf_count;
QueryPerformanceCounter(&perf_count);
p->last_submit_qpc = perf_count.QuadPart;
@@ -243,10 +243,21 @@ static void d3d11_get_vsync(struct ra_swapchain *sw, struct vo_vsync_info *info)
struct priv *p = sw->priv;
HRESULT hr;
+ m_config_cache_update(p->opts_cache);
+
// The calculations below are only valid if mpv presents on every vsync
if (p->opts->sync_interval != 1)
return;
+ // They're also only valid for flip model swapchains
+ DXGI_SWAP_CHAIN_DESC desc;
+ hr = IDXGISwapChain_GetDesc(p->swapchain, &desc);
+ if (FAILED(hr) || (desc.SwapEffect != DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL &&
+ desc.SwapEffect != DXGI_SWAP_EFFECT_FLIP_DISCARD))
+ {
+ return;
+ }
+
// GetLastPresentCount returns a sequential ID for the frame submitted by
// the last call to IDXGISwapChain::Present()
UINT submit_count;
@@ -262,34 +273,39 @@ static void d3d11_get_vsync(struct ra_swapchain *sw, struct vo_vsync_info *info)
DXGI_FRAME_STATISTICS stats;
hr = IDXGISwapChain_GetFrameStatistics(p->swapchain, &stats);
if (hr == DXGI_ERROR_FRAME_STATISTICS_DISJOINT) {
- p->last_sync_refresh_count = 0;
- p->last_sync_qpc_time = 0;
+ p->sync_refresh_count = 0;
+ p->sync_qpc_time = 0;
}
if (FAILED(hr))
return;
+ info->last_queue_display_time = 0;
+ info->vsync_duration = 0;
// Detecting skipped vsyncs is possible but not supported yet
- info->skipped_vsyncs = 0;
+ info->skipped_vsyncs = -1;
- // Get the number of physical vsyncs that have passed since the last call.
+ // Get the number of physical vsyncs that have passed since the start of the
+ // playback or disjoint event.
// Check for 0 here, since sometimes GetFrameStatistics returns S_OK but
// with 0s in some (all?) members of DXGI_FRAME_STATISTICS.
unsigned src_passed = 0;
- if (stats.SyncRefreshCount && p->last_sync_refresh_count)
- src_passed = stats.SyncRefreshCount - p->last_sync_refresh_count;
- p->last_sync_refresh_count = stats.SyncRefreshCount;
+ if (stats.SyncRefreshCount && p->sync_refresh_count)
+ src_passed = stats.SyncRefreshCount - p->sync_refresh_count;
+ if (p->sync_refresh_count == 0)
+ p->sync_refresh_count = stats.SyncRefreshCount;
// Get the elapsed time passed between the above vsyncs
unsigned sqt_passed = 0;
- if (stats.SyncQPCTime.QuadPart && p->last_sync_qpc_time)
- sqt_passed = stats.SyncQPCTime.QuadPart - p->last_sync_qpc_time;
- p->last_sync_qpc_time = stats.SyncQPCTime.QuadPart;
+ if (stats.SyncQPCTime.QuadPart && p->sync_qpc_time)
+ sqt_passed = stats.SyncQPCTime.QuadPart - p->sync_qpc_time;
+ if (p->sync_qpc_time == 0)
+ p->sync_qpc_time = stats.SyncQPCTime.QuadPart;
// If any vsyncs have passed, estimate the physical frame rate
if (src_passed && sqt_passed)
p->vsync_duration_qpc = sqt_passed / src_passed;
if (p->vsync_duration_qpc)
- info->vsync_duration = qpc_to_us(sw, p->vsync_duration_qpc);
+ info->vsync_duration = qpc_to_ns(sw, p->vsync_duration_qpc);
// If the physical frame rate is known and the other members of
// DXGI_FRAME_STATISTICS are non-0, estimate the timing of the next frame
@@ -297,10 +313,9 @@ static void d3d11_get_vsync(struct ra_swapchain *sw, struct vo_vsync_info *info)
stats.PresentRefreshCount && stats.SyncRefreshCount &&
stats.SyncQPCTime.QuadPart)
{
- // PresentRefreshCount and SyncRefreshCount might refer to different
- // frames (this can definitely occur in bitblt-mode.) Assuming mpv
- // presents on every frame, guess the present count that relates to
- // SyncRefreshCount.
+ // It's not clear if PresentRefreshCount and SyncRefreshCount can refer
+ // to different frames, but in case they can, assuming mpv presents on
+ // every frame, guess the present count that relates to SyncRefreshCount.
unsigned expected_sync_pc = stats.PresentCount +
(stats.SyncRefreshCount - stats.PresentRefreshCount);
@@ -313,15 +328,90 @@ static void d3d11_get_vsync(struct ra_swapchain *sw, struct vo_vsync_info *info)
// Only set the estimated display time if it's after the last submission
// time. It could be before if mpv skips a lot of frames.
if (last_queue_display_time_qpc >= p->last_submit_qpc) {
- info->last_queue_display_time = mp_time_us() +
- (qpc_to_us(sw, last_queue_display_time_qpc) - qpc_us_now(sw));
+ info->last_queue_display_time = mp_time_ns() +
+ (qpc_to_ns(sw, last_queue_display_time_qpc) - qpc_ns_now(sw));
}
}
}
+static bool d3d11_set_fullscreen(struct ra_ctx *ctx)
+{
+ struct priv *p = ctx->priv;
+ HRESULT hr;
+
+ m_config_cache_update(p->opts_cache);
+
+ if (!p->swapchain) {
+ MP_ERR(ctx, "Full screen configuration was requested before D3D11 "
+ "swap chain was ready!");
+ return false;
+ }
+
+ // we only want exclusive FS if we are entering FS and
+ // exclusive FS is enabled. Otherwise disable exclusive FS.
+ bool enable_exclusive_fs = p->vo_opts->fullscreen &&
+ p->opts->exclusive_fs;
+
+ MP_VERBOSE(ctx, "%s full-screen exclusive mode while %s fullscreen\n",
+ enable_exclusive_fs ? "Enabling" : "Disabling",
+ ctx->vo->opts->fullscreen ? "entering" : "leaving");
+
+ hr = IDXGISwapChain_SetFullscreenState(p->swapchain,
+ enable_exclusive_fs, NULL);
+ if (FAILED(hr))
+ return false;
+
+ if (!resize(ctx))
+ return false;
+
+ return true;
+}
+
static int d3d11_control(struct ra_ctx *ctx, int *events, int request, void *arg)
{
- int ret = vo_w32_control(ctx->vo, events, request, arg);
+ struct priv *p = ctx->priv;
+ int ret = -1;
+ bool fullscreen_switch_needed = false;
+
+ switch (request) {
+ case VOCTRL_VO_OPTS_CHANGED: {
+ void *changed_option;
+
+ while (m_config_cache_get_next_changed(p->vo_opts_cache,
+ &changed_option))
+ {
+ struct mp_vo_opts *vo_opts = p->vo_opts_cache->opts;
+
+ if (changed_option == &vo_opts->fullscreen) {
+ fullscreen_switch_needed = true;
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ // if leaving full screen, handle d3d11 stuff first, then general
+ // windowing
+ if (fullscreen_switch_needed && !p->vo_opts->fullscreen) {
+ if (!d3d11_set_fullscreen(ctx))
+ return VO_FALSE;
+
+ fullscreen_switch_needed = false;
+ }
+
+ ret = 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) {
+ if (!d3d11_set_fullscreen(ctx))
+ return VO_FALSE;
+
+ fullscreen_switch_needed = false;
+ }
+
if (*events & VO_EVENT_RESIZE) {
if (!resize(ctx))
return VO_ERROR;
@@ -333,13 +423,16 @@ static void d3d11_uninit(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv;
+ if (p->swapchain)
+ IDXGISwapChain_SetFullscreenState(p->swapchain, FALSE, NULL);
+
if (ctx->ra)
ra_tex_free(ctx->ra, &p->backbuffer);
SAFE_RELEASE(p->swapchain);
vo_w32_uninit(ctx->vo);
SAFE_RELEASE(p->device);
- // Destory the RA last to prevent objects we hold from showing up in D3D's
+ // Destroy the RA last to prevent objects we hold from showing up in D3D's
// leak checker
if (ctx->ra)
ctx->ra->fns->destroy(ctx->ra);
@@ -356,7 +449,11 @@ static const struct ra_swapchain_fns d3d11_swapchain = {
static bool d3d11_init(struct ra_ctx *ctx)
{
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
- p->opts = mp_get_config_group(ctx, ctx->global, &d3d11_conf);
+ p->opts_cache = m_config_cache_alloc(ctx, ctx->global, &d3d11_conf);
+ p->opts = p->opts_cache->opts;
+
+ p->vo_opts_cache = m_config_cache_alloc(ctx, ctx->vo->global, &vo_sub_opts);
+ p->vo_opts = p->vo_opts_cache->opts;
LARGE_INTEGER perf_freq;
QueryPerformanceFrequency(&perf_freq);
@@ -387,6 +484,16 @@ static bool d3d11_init(struct ra_ctx *ctx)
if (!vo_w32_init(ctx->vo))
goto error;
+ if (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;
+ if (ID3D11Device_GetFeatureLevel(p->device) >= D3D_FEATURE_LEVEL_11_0 &&
+ p->opts->output_format != DXGI_FORMAT_B8G8R8A8_UNORM)
+ {
+ usage |= DXGI_USAGE_UNORDERED_ACCESS;
+ }
+
struct d3d11_swapchain_opts scopts = {
.window = vo_w32_hwnd(ctx->vo),
.width = ctx->vo->dwidth,
@@ -398,15 +505,11 @@ static bool d3d11_init(struct ra_ctx *ctx)
// Add one frame for the backbuffer and one frame of "slack" to reduce
// contention with the window manager when acquiring the backbuffer
.length = ctx->vo->opts->swapchain_depth + 2,
- .usage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
+ .usage = usage,
};
if (!mp_d3d11_create_swapchain(p->device, ctx->log, &scopts, &p->swapchain))
goto error;
- p->backbuffer = get_backbuffer(ctx);
- if (!p->backbuffer)
- goto error;
-
return true;
error:
@@ -414,11 +517,40 @@ error:
return false;
}
+static void d3d11_update_render_opts(struct ra_ctx *ctx)
+{
+ vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha);
+}
+
+IDXGISwapChain *ra_d3d11_ctx_get_swapchain(struct ra_ctx *ra)
+{
+ if (ra->swapchain->fns != &d3d11_swapchain)
+ return NULL;
+
+ struct priv *p = ra->priv;
+
+ IDXGISwapChain_AddRef(p->swapchain);
+
+ return p->swapchain;
+}
+
+bool ra_d3d11_ctx_prefer_8bit_output_format(struct ra_ctx *ra)
+{
+ if (ra->swapchain->fns != &d3d11_swapchain)
+ return false;
+
+ struct priv *p = ra->priv;
+
+ return p->opts->output_format == DXGI_FORMAT_R8G8B8A8_UNORM;
+}
+
const struct ra_ctx_fns ra_ctx_d3d11 = {
- .type = "d3d11",
- .name = "d3d11",
- .reconfig = d3d11_reconfig,
- .control = d3d11_control,
- .init = d3d11_init,
- .uninit = d3d11_uninit,
+ .type = "d3d11",
+ .name = "d3d11",
+ .description = "Direct3D 11",
+ .reconfig = d3d11_reconfig,
+ .control = d3d11_control,
+ .update_render_opts = d3d11_update_render_opts,
+ .init = d3d11_init,
+ .uninit = d3d11_uninit,
};
diff --git a/video/out/d3d11/context.h b/video/out/d3d11/context.h
new file mode 100644
index 0000000000..25488f2cbd
--- /dev/null
+++ b/video/out/d3d11/context.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <dxgi.h>
+
+#include "video/out/gpu/context.h"
+
+// Get the underlying D3D11 swap chain from an RA context. The returned swap chain is
+// refcounted and must be released by the caller.
+IDXGISwapChain *ra_d3d11_ctx_get_swapchain(struct ra_ctx *ra);
+
+// Returns true if an 8-bit output format is explicitly requested for
+// d3d11-output-format for an RA context.
+bool ra_d3d11_ctx_prefer_8bit_output_format(struct ra_ctx *ra);
diff --git a/video/out/d3d11/hwdec_d3d11va.c b/video/out/d3d11/hwdec_d3d11va.c
index 8d22fe3de5..6aaa12bc66 100644
--- a/video/out/d3d11/hwdec_d3d11va.c
+++ b/video/out/d3d11/hwdec_d3d11va.c
@@ -19,8 +19,6 @@
#include <d3d11.h>
#include <d3d11_1.h>
-#include "config.h"
-
#include "common/common.h"
#include "options/m_config.h"
#include "osdep/windows_utils.h"
@@ -30,18 +28,16 @@
#include "video/out/gpu/hwdec.h"
struct d3d11va_opts {
- int zero_copy;
+ bool zero_copy;
};
#define OPT_BASE_STRUCT struct d3d11va_opts
const struct m_sub_options d3d11va_conf = {
.opts = (const struct m_option[]) {
- OPT_FLAG("d3d11va-zero-copy", zero_copy, 0),
+ {"d3d11va-zero-copy", OPT_BOOL(zero_copy)},
{0}
},
- .defaults = &(const struct d3d11va_opts) {
- .zero_copy = 0,
- },
+ .defaults = &(const struct d3d11va_opts) {0},
.size = sizeof(struct d3d11va_opts)
};
@@ -67,6 +63,7 @@ static void uninit(struct ra_hwdec *hw)
{
struct priv_owner *p = hw->priv;
hwdec_devices_remove(hw->devs, &p->hwctx);
+ av_buffer_unref(&p->hwctx.av_device_ref);
SAFE_RELEASE(p->device);
SAFE_RELEASE(p->device1);
}
@@ -76,9 +73,9 @@ static int init(struct ra_hwdec *hw)
struct priv_owner *p = hw->priv;
HRESULT hr;
- if (!ra_is_d3d11(hw->ra))
+ if (!ra_is_d3d11(hw->ra_ctx->ra))
return -1;
- p->device = ra_d3d11_get_device(hw->ra);
+ p->device = ra_d3d11_get_device(hw->ra_ctx->ra);
if (!p->device)
return -1;
@@ -111,6 +108,12 @@ static int init(struct ra_hwdec *hw)
.supported_formats = subfmts,
.hw_imgfmt = IMGFMT_D3D11,
};
+
+ if (!p->hwctx.av_device_ref) {
+ MP_VERBOSE(hw, "Failed to create hwdevice_ctx\n");
+ return -1;
+ }
+
hwdec_devices_add(hw->devs, &p->hwctx);
return 0;
}
@@ -206,6 +209,9 @@ static int mapper_map(struct ra_hwdec_mapper *mapper)
.bottom = mapper->dst_params.h,
.back = 1,
}), D3D11_COPY_DISCARD);
+
+ // We no longer need the original texture after copying it.
+ mp_image_unrefp(&mapper->src);
} else {
D3D11_TEXTURE2D_DESC desc2d;
ID3D11Texture2D_GetDesc(tex, &desc2d);
diff --git a/video/out/d3d11/hwdec_dxva2dxgi.c b/video/out/d3d11/hwdec_dxva2dxgi.c
index 8dbb1cf65d..62158d467b 100644
--- a/video/out/d3d11/hwdec_dxva2dxgi.c
+++ b/video/out/d3d11/hwdec_dxva2dxgi.c
@@ -74,9 +74,9 @@ static int init(struct ra_hwdec *hw)
int ret = -1;
HRESULT hr;
- if (!ra_is_d3d11(hw->ra))
+ if (!ra_is_d3d11(hw->ra_ctx->ra))
goto done;
- p->dev11 = ra_d3d11_get_device(hw->ra);
+ p->dev11 = ra_d3d11_get_device(hw->ra_ctx->ra);
if (!p->dev11)
goto done;
@@ -134,7 +134,14 @@ static int init(struct ra_hwdec *hw)
p->hwctx = (struct mp_hwdec_ctx){
.driver_name = hw->driver->name,
.av_device_ref = d3d9_wrap_device_ref((IDirect3DDevice9 *)p->dev9),
+ .hw_imgfmt = IMGFMT_DXVA2,
};
+
+ if (!p->hwctx.av_device_ref) {
+ MP_VERBOSE(hw, "Failed to create hwdevice_ctx\n");
+ goto done;
+ }
+
hwdec_devices_add(hw->devs, &p->hwctx);
ret = 0;
diff --git a/video/out/d3d11/ra_d3d11.c b/video/out/d3d11/ra_d3d11.c
index 13a48a114c..4438b2083c 100644
--- a/video/out/d3d11/ra_d3d11.c
+++ b/video/out/d3d11/ra_d3d11.c
@@ -13,6 +13,7 @@
#include "osdep/windows_utils.h"
#include "video/out/gpu/spirv.h"
#include "video/out/gpu/utils.h"
+#include "video/out/gpu/d3d11_helpers.h"
#include "ra_d3d11.h"
@@ -21,6 +22,10 @@
#endif
#define D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE (0x80)
+// D3D11.3 message IDs, not present in mingw-w64 v9
+#define D3D11_MESSAGE_ID_CREATE_FENCE ((D3D11_MESSAGE_ID)0x300209)
+#define D3D11_MESSAGE_ID_DESTROY_FENCE ((D3D11_MESSAGE_ID)0x30020b)
+
struct dll_version {
uint16_t major;
uint16_t minor;
@@ -39,9 +44,11 @@ struct ra_d3d11 {
struct dll_version d3d_compiler_ver;
+#if HAVE_DXGI_DEBUG
// Debug interfaces (--gpu-debug)
- ID3D11Debug *debug;
- ID3D11InfoQueue *iqueue;
+ IDXGIDebug *debug;
+ IDXGIInfoQueue *iqueue;
+#endif
// Device capabilities
D3D_FEATURE_LEVEL fl;
@@ -196,12 +203,24 @@ static bool dll_version_equal(struct dll_version a, struct dll_version b)
a.revision == b.revision;
}
-static DXGI_FORMAT fmt_to_dxgi(const struct ra_format *fmt)
+DXGI_FORMAT ra_d3d11_get_format(const struct ra_format *fmt)
{
struct d3d_fmt *d3d = fmt->priv;
return d3d->fmt;
}
+const struct ra_format *ra_d3d11_get_ra_format(struct ra *ra, DXGI_FORMAT fmt)
+{
+ for (int i = 0; i < ra->num_formats; i++) {
+ struct ra_format *ra_fmt = ra->formats[i];
+
+ if (ra_d3d11_get_format(ra_fmt) == fmt)
+ return ra_fmt;
+ }
+
+ return NULL;
+}
+
static void setup_formats(struct ra *ra)
{
// All formats must be usable as a 2D texture
@@ -273,7 +292,7 @@ static bool tex_init(struct ra *ra, struct ra_tex *tex)
// texture format for textures created with tex_create, but it can be
// different for wrapped planar video textures.
D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc = {
- .Format = fmt_to_dxgi(params->format),
+ .Format = ra_d3d11_get_format(params->format),
};
switch (params->dimensions) {
case 1:
@@ -393,7 +412,7 @@ static struct ra_tex *tex_create(struct ra *ra,
tex->params.initial_data = NULL;
struct d3d_tex *tex_p = tex->priv = talloc_zero(tex, struct d3d_tex);
- DXGI_FORMAT fmt = fmt_to_dxgi(params->format);
+ DXGI_FORMAT fmt = ra_d3d11_get_format(params->format);
D3D11_SUBRESOURCE_DATA data;
D3D11_SUBRESOURCE_DATA *pdata = NULL;
@@ -494,7 +513,7 @@ static struct ra_tex *tex_create(struct ra *ra,
tex_p->res = (ID3D11Resource *)tex_p->tex3d;
break;
default:
- abort();
+ MP_ASSERT_UNREACHABLE();
}
tex_p->array_slice = -1;
@@ -564,7 +583,7 @@ struct ra_tex *ra_d3d11_wrap_tex(struct ra *ra, ID3D11Resource *res)
}
for (int i = 0; i < ra->num_formats; i++) {
- DXGI_FORMAT target_fmt = fmt_to_dxgi(ra->formats[i]);
+ DXGI_FORMAT target_fmt = ra_d3d11_get_format(ra->formats[i]);
if (fmt == target_fmt) {
params->format = ra->formats[i];
break;
@@ -643,6 +662,17 @@ error:
return NULL;
}
+ID3D11Resource *ra_d3d11_get_raw_tex(struct ra *ra, struct ra_tex *tex,
+ int *array_slice)
+{
+ struct d3d_tex *tex_p = tex->priv;
+
+ ID3D11Resource_AddRef(tex_p->res);
+ if (array_slice)
+ *array_slice = tex_p->array_slice;
+ return tex_p->res;
+}
+
static bool tex_upload(struct ra *ra, const struct ra_tex_upload_params *params)
{
struct ra_d3d11 *p = ra->priv;
@@ -1295,13 +1325,13 @@ static bool compile_glsl(struct ra *ra, enum glsl_shader type,
sc_shader_model = 40;
}
- int64_t start_us = mp_time_us();
+ int64_t start_ns = mp_time_ns();
bstr spv_module;
if (!spirv->fns->compile_glsl(spirv, ta_ctx, type, glsl, &spv_module))
goto done;
- int64_t shaderc_us = mp_time_us();
+ int64_t shaderc_ns = mp_time_ns();
sc_res = spvc_context_create(&sc_ctx);
if (sc_res != SPVC_SUCCESS)
@@ -1340,7 +1370,7 @@ static bool compile_glsl(struct ra *ra, enum glsl_shader type,
if (sc_res != SPVC_SUCCESS)
goto done;
- int64_t cross_us = mp_time_us();
+ int64_t cross_ns = mp_time_ns();
hr = p->D3DCompile(hlsl, strlen(hlsl), NULL, NULL, NULL, "main",
get_shader_target(ra, type), D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, out,
@@ -1352,14 +1382,14 @@ static bool compile_glsl(struct ra *ra, enum glsl_shader type,
goto done;
}
- int64_t d3dcompile_us = mp_time_us();
+ int64_t d3dcompile_ns = mp_time_ns();
- MP_VERBOSE(ra, "Compiled a %s shader in %lldus\n", shader_type_name(type),
- d3dcompile_us - start_us);
- MP_VERBOSE(ra, "shaderc: %lldus, SPIRV-Cross: %lldus, D3DCompile: %lldus\n",
- shaderc_us - start_us,
- cross_us - shaderc_us,
- d3dcompile_us - cross_us);
+ MP_VERBOSE(ra, "Compiled a %s shader in %lldns\n", shader_type_name(type),
+ d3dcompile_ns - start_ns);
+ MP_VERBOSE(ra, "shaderc: %lldns, SPIRV-Cross: %lldns, D3DCompile: %lldns\n",
+ shaderc_ns - start_ns,
+ cross_ns - shaderc_ns,
+ d3dcompile_ns - cross_ns);
success = true;
done:
@@ -1570,7 +1600,7 @@ static void save_cached_program(struct ra *ra, struct ra_renderpass *pass,
.frag_bytecode_len = frag_bc.len,
.comp_bytecode_len = comp_bc.len,
};
- strncpy(header.magic, cache_magic, sizeof(header.magic));
+ memcpy(header.magic, cache_magic, sizeof(header.magic));
strncpy(header.compiler, spirv->name, sizeof(header.compiler));
struct bstr *prog = &pass->params.cached_program;
@@ -1903,7 +1933,7 @@ static void renderpass_run(struct ra *ra,
int binding = pass->params.inputs[val->index].binding;
switch (pass->params.inputs[val->index].type) {
case RA_VARTYPE_BUF_RO:
- if (binding > MP_ARRAY_SIZE(ubos)) {
+ if (binding >= MP_ARRAY_SIZE(ubos)) {
MP_ERR(ra, "Too many constant buffers in pass\n");
return;
}
@@ -1925,7 +1955,7 @@ static void renderpass_run(struct ra *ra,
uavs_len = MPMAX(uavs_len, binding + 1);
break;
case RA_VARTYPE_TEX:
- if (binding > MP_ARRAY_SIZE(samplers)) {
+ if (binding >= MP_ARRAY_SIZE(samplers)) {
MP_ERR(ra, "Too many textures in pass\n");
return;
}
@@ -1994,7 +2024,7 @@ static ra_timer *timer_create(struct ra *ra)
// Measuring duration in D3D11 requires three queries: start and end
// timestamps, and a disjoint query containing a flag which says whether
- // the timestamps are usable or if a discontinuity occured between them,
+ // the timestamps are usable or if a discontinuity occurred between them,
// like a change in power state or clock speed. The disjoint query also
// contains the timer frequency, so the timestamps are useless without it.
hr = ID3D11Device_CreateQuery(p->dev,
@@ -2067,24 +2097,86 @@ static uint64_t timer_stop(struct ra *ra, ra_timer *ratimer)
return timer->result;
}
-static int map_msg_severity(D3D11_MESSAGE_SEVERITY sev)
+#if HAVE_DXGI_DEBUG
+static int map_msg_severity(DXGI_INFO_QUEUE_MESSAGE_SEVERITY sev)
{
switch (sev) {
- case D3D11_MESSAGE_SEVERITY_CORRUPTION:
+ case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION:
return MSGL_FATAL;
- case D3D11_MESSAGE_SEVERITY_ERROR:
+ case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR:
return MSGL_ERR;
- case D3D11_MESSAGE_SEVERITY_WARNING:
+ case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING:
return MSGL_WARN;
default:
- case D3D11_MESSAGE_SEVERITY_INFO:
- case D3D11_MESSAGE_SEVERITY_MESSAGE:
+ case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO:
+ case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_MESSAGE:
return MSGL_DEBUG;
}
}
+static int map_msg_severity_by_id(D3D11_MESSAGE_ID id,
+ DXGI_INFO_QUEUE_MESSAGE_SEVERITY sev)
+{
+ switch (id) {
+ // These are normal. The RA timer queue habitually reuses timer objects
+ // without retrieving the results.
+ case D3D11_MESSAGE_ID_QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS:
+ case D3D11_MESSAGE_ID_QUERY_END_ABANDONING_PREVIOUS_RESULTS:
+ return MSGL_TRACE;
+
+ // D3D11 writes log messages every time an object is created or
+ // destroyed. That results in a lot of log spam, so force MSGL_TRACE.
+#define OBJ_LIFETIME_MESSAGES(obj) \
+ case D3D11_MESSAGE_ID_CREATE_ ## obj: \
+ case D3D11_MESSAGE_ID_DESTROY_ ## obj
+
+ OBJ_LIFETIME_MESSAGES(CONTEXT):
+ OBJ_LIFETIME_MESSAGES(BUFFER):
+ OBJ_LIFETIME_MESSAGES(TEXTURE1D):
+ OBJ_LIFETIME_MESSAGES(TEXTURE2D):
+ OBJ_LIFETIME_MESSAGES(TEXTURE3D):
+ OBJ_LIFETIME_MESSAGES(SHADERRESOURCEVIEW):
+ OBJ_LIFETIME_MESSAGES(RENDERTARGETVIEW):
+ OBJ_LIFETIME_MESSAGES(DEPTHSTENCILVIEW):
+ OBJ_LIFETIME_MESSAGES(VERTEXSHADER):
+ OBJ_LIFETIME_MESSAGES(HULLSHADER):
+ OBJ_LIFETIME_MESSAGES(DOMAINSHADER):
+ OBJ_LIFETIME_MESSAGES(GEOMETRYSHADER):
+ OBJ_LIFETIME_MESSAGES(PIXELSHADER):
+ OBJ_LIFETIME_MESSAGES(INPUTLAYOUT):
+ OBJ_LIFETIME_MESSAGES(SAMPLER):
+ OBJ_LIFETIME_MESSAGES(BLENDSTATE):
+ OBJ_LIFETIME_MESSAGES(DEPTHSTENCILSTATE):
+ OBJ_LIFETIME_MESSAGES(RASTERIZERSTATE):
+ OBJ_LIFETIME_MESSAGES(QUERY):
+ OBJ_LIFETIME_MESSAGES(PREDICATE):
+ OBJ_LIFETIME_MESSAGES(COUNTER):
+ OBJ_LIFETIME_MESSAGES(COMMANDLIST):
+ OBJ_LIFETIME_MESSAGES(CLASSINSTANCE):
+ OBJ_LIFETIME_MESSAGES(CLASSLINKAGE):
+ OBJ_LIFETIME_MESSAGES(COMPUTESHADER):
+ OBJ_LIFETIME_MESSAGES(UNORDEREDACCESSVIEW):
+ OBJ_LIFETIME_MESSAGES(VIDEODECODER):
+ OBJ_LIFETIME_MESSAGES(VIDEOPROCESSORENUM):
+ OBJ_LIFETIME_MESSAGES(VIDEOPROCESSOR):
+