diff options
Diffstat (limited to 'video/out/d3d11/context.c')
-rw-r--r-- | video/out/d3d11/context.c | 190 |
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, }; |