summaryrefslogtreecommitdiffstats
path: root/video/out/d3d11/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/d3d11/context.c')
-rw-r--r--video/out/d3d11/context.c190
1 files changed, 110 insertions, 80 deletions
diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c
index b77e328b70..c563b5fa15 100644
--- a/video/out/d3d11/context.c
+++ b/video/out/d3d11/context.c
@@ -24,21 +24,18 @@
#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;
- int exclusive_fs;
+ bool exclusive_fs;
};
#define OPT_BASE_STRUCT struct d3d11_opts
@@ -58,10 +55,10 @@ const struct m_sub_options d3d11_conf = {
{"9_3", D3D_FEATURE_LEVEL_9_3},
{"9_2", D3D_FEATURE_LEVEL_9_2},
{"9_1", D3D_FEATURE_LEVEL_9_1})},
- {"d3d11-flip", OPT_FLAG(flip)},
+ {"d3d11-flip", OPT_BOOL(flip)},
{"d3d11-sync-interval", OPT_INT(sync_interval), M_RANGE(0, 4)},
{"d3d11-adapter", OPT_STRING_VALIDATE(adapter_name,
- d3d11_validate_adapter)},
+ mp_dxgi_validate_adapter)},
{"d3d11-output-format", OPT_CHOICE(output_format,
{"auto", DXGI_FORMAT_UNKNOWN},
{"rgba8", DXGI_FORMAT_R8G8B8A8_UNORM},
@@ -74,18 +71,17 @@ const struct m_sub_options d3d11_conf = {
{"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_FLAG(exclusive_fs)},
+ {"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,
.color_space = -1,
- .exclusive_fs = 0,
},
.size = sizeof(struct d3d11_opts)
};
@@ -100,45 +96,15 @@ struct priv {
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;
@@ -164,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);
@@ -173,8 +142,6 @@ static bool resize(struct ra_ctx *ctx)
return false;
}
- p->backbuffer = get_backbuffer(ctx);
-
return true;
}
@@ -188,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;
@@ -212,26 +200,29 @@ 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)
@@ -282,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
@@ -332,8 +328,8 @@ 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));
}
}
}
@@ -436,7 +432,7 @@ static void d3d11_uninit(struct ra_ctx *ctx)
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);
@@ -488,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,
@@ -499,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:
@@ -515,11 +517,39 @@ 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",
+ .reconfig = d3d11_reconfig,
+ .control = d3d11_control,
+ .update_render_opts = d3d11_update_render_opts,
+ .init = d3d11_init,
+ .uninit = d3d11_uninit,
};