diff options
Diffstat (limited to 'video/out/d3d11')
-rw-r--r-- | video/out/d3d11/context.c | 191 | ||||
-rw-r--r-- | video/out/d3d11/context.h | 13 | ||||
-rw-r--r-- | video/out/d3d11/hwdec_d3d11va.c | 24 | ||||
-rw-r--r-- | video/out/d3d11/hwdec_dxva2dxgi.c | 11 | ||||
-rw-r--r-- | video/out/d3d11/ra_d3d11.c | 240 | ||||
-rw-r--r-- | video/out/d3d11/ra_d3d11.h | 12 |
6 files changed, 314 insertions, 177 deletions
diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c index b77e328b70..f183ae8be5 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,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 02f796e003..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[]) { - {"d3d11va-zero-copy", OPT_FLAG(zero_copy)}, + {"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): + OBJ_LIFETIME_MESSAGES(DECODEROUTPUTVIEW): + OBJ_LIFETIME_MESSAGES(PROCESSORINPUTVIEW): + OBJ_LIFETIME_MESSAGES(PROCESSOROUTPUTVIEW): + OBJ_LIFETIME_MESSAGES(DEVICECONTEXTSTATE): + OBJ_LIFETIME_MESSAGES(FENCE): + return MSGL_TRACE; + +#undef OBJ_LIFETIME_MESSAGES + + default: + return map_msg_severity(sev); + } +} +#endif + static void debug_marker(struct ra *ra, const char *msg) { +#if HAVE_DXGI_DEBUG struct ra_d3d11 *p = ra->priv; void *talloc_ctx = talloc_new(NULL); HRESULT hr; @@ -2094,33 +2186,38 @@ static void debug_marker(struct ra *ra, const char *msg) // Copy debug-layer messages to mpv's log output bool printed_header = false; - uint64_t messages = ID3D11InfoQueue_GetNumStoredMessages(p->iqueue); + uint64_t messages = IDXGIInfoQueue_GetNumStoredMessages(p->iqueue, + DXGI_DEBUG_ALL); for (uint64_t i = 0; i < messages; i++) { - size_t len; - hr = ID3D11InfoQueue_GetMessage(p->iqueue, i, NULL, &len); + SIZE_T len; + hr = IDXGIInfoQueue_GetMessage(p->iqueue, DXGI_DEBUG_ALL, i, NULL, &len); if (FAILED(hr) || !len) goto done; - D3D11_MESSAGE *d3dmsg = talloc_size(talloc_ctx, len); - hr = ID3D11InfoQueue_GetMessage(p->iqueue, i, d3dmsg, &len); + DXGI_INFO_QUEUE_MESSAGE *dxgimsg = talloc_size(talloc_ctx, len); + hr = IDXGIInfoQueue_GetMessage(p->iqueue, DXGI_DEBUG_ALL, i, dxgimsg, &len); if (FAILED(hr)) goto done; - int msgl = map_msg_severity(d3dmsg->Severity); + int msgl = IsEqualGUID(&dxgimsg->Producer, &DXGI_DEBUG_D3D11) + ? map_msg_severity_by_id(dxgimsg->ID, dxgimsg->Severity) + : map_msg_severity(dxgimsg->Severity); + if (mp_msg_test(ra->log, msgl)) { if (!printed_header) MP_INFO(ra, "%s:\n", msg); printed_header = true; - MP_MSG(ra, msgl, "%d: %.*s\n", (int)d3dmsg->ID, - (int)d3dmsg->DescriptionByteLength, d3dmsg->pDescription); - talloc_free(d3dmsg); + MP_MSG(ra, msgl, "%d: %.*s\n", (int)dxgimsg->ID, + (int)dxgimsg->DescriptionByteLength, dxgimsg->pDescription); + talloc_free(dxgimsg); } } - ID3D11InfoQueue_ClearStoredMessages(p->iqueue); + IDXGIInfoQueue_ClearStoredMessages(p->iqueue, DXGI_DEBUG_ALL); done: talloc_free(talloc_ctx); +#endif } static void destroy(struct ra *ra) @@ -2143,7 +2240,7 @@ static void destroy(struct ra *ra) SAFE_RELEASE(p->dev1); SAFE_RELEASE(p->dev); - if (p->debug && p->ctx) { + if (p->ctx) { // Destroy the device context synchronously so referenced objects don't // show up in the leak check ID3D11DeviceContext_ClearState(p->ctx); @@ -2151,16 +2248,18 @@ static void destroy(struct ra *ra) } SAFE_RELEASE(p->ctx); +#if HAVE_DXGI_DEBUG if (p->debug) { // Report any leaked objects debug_marker(ra, "after destroy"); - ID3D11Debug_ReportLiveDeviceObjects(p->debug, D3D11_RLDO_DETAIL); + IDXGIDebug_ReportLiveObjects(p->debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_DETAIL); debug_marker(ra, "after leak check"); - ID3D11Debug_ReportLiveDeviceObjects(p->debug, D3D11_RLDO_SUMMARY); + IDXGIDebug_ReportLiveObjects(p->debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_SUMMARY); debug_marker(ra, "after leak summary"); } SAFE_RELEASE(p->debug); SAFE_RELEASE(p->iqueue); +#endif talloc_free(ra); } @@ -2194,57 +2293,13 @@ void ra_d3d11_flush(struct ra *ra) ID3D11DeviceContext_Flush(p->ctx); } -static void init_debug_layer(struct ra *ra) -{ - struct ra_d3d11 *p = ra->priv; - HRESULT hr; - - hr = ID3D11Device_QueryInterface(p->dev, &IID_ID3D11Debug, - (void**)&p->debug); - if (FAILED(hr)) { - MP_ERR(ra, "Failed to get debug device: %s\n", mp_HRESULT_to_str(hr)); - return; - } - - hr = ID3D11Device_QueryInterface(p->dev, &IID_ID3D11InfoQueue, - (void**)&p->iqueue); - if (FAILED(hr)) { - MP_ERR(ra, "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.) - ID3D11InfoQueue_SetMessageCountLimit(p->iqueue, -1); - - // Filter some annoying messages - D3D11_MESSAGE_ID deny_ids[] = { - // This error occurs during context creation when we try to figure out - // the real maximum texture size by attempting to create a texture - // larger than the current feature level allows. - D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDDIMENSIONS, - - // These are normal. The RA timer queue habitually reuses timer objects - // without retrieving the results. - D3D11_MESSAGE_ID_QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS, - D3D11_MESSAGE_ID_QUERY_END_ABANDONING_PREVIOUS_RESULTS, - }; - D3D11_INFO_QUEUE_FILTER filter = { - .DenyList = { - .NumIDs = MP_ARRAY_SIZE(deny_ids), - .pIDList = deny_ids, - }, - }; - ID3D11InfoQueue_PushStorageFilter(p->iqueue, &filter); -} - static struct dll_version get_dll_version(HMODULE dll) { void *ctx = talloc_new(NULL); struct dll_version ret = { 0 }; HRSRC rsrc = FindResourceW(dll, MAKEINTRESOURCEW(VS_VERSION_INFO), - MAKEINTRESOURCEW(VS_FILE_INFO)); + VS_FILE_INFO); if (!rsrc) goto done; DWORD size = SizeofResource(dll, rsrc); @@ -2386,6 +2441,8 @@ struct ra *ra_d3d11_create(ID3D11Device *dev, struct mp_log *log, if (p->fl >= D3D_FEATURE_LEVEL_11_0) { ra->caps |= RA_CAP_COMPUTE | RA_CAP_BUF_RW; ra->max_shmem = 32 * 1024; + ra->max_compute_group_threads = + D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; } if (p->fl >= D3D_FEATURE_LEVEL_11_1) { @@ -2394,18 +2451,29 @@ struct ra *ra_d3d11_create(ID3D11Device *dev, struct mp_log *log, p->max_uavs = D3D11_PS_CS_UAV_REGISTER_COUNT; } +#if HAVE_DXGI_DEBUG if (ID3D11Device_GetCreationFlags(p->dev) & D3D11_CREATE_DEVICE_DEBUG) - init_debug_layer(ra); + mp_d3d11_get_debug_interfaces(ra->log, &p->debug, &p->iqueue); +#endif // Some level 9_x devices don't have timestamp queries hr = ID3D11Device_CreateQuery(p->dev, &(D3D11_QUERY_DESC) { D3D11_QUERY_TIMESTAMP }, NULL); p->has_timestamp_queries = SUCCEEDED(hr); + debug_marker(ra, "before maximum Texture2D size lookup"); + // According to MSDN, the above texture sizes are just minimums and drivers // may support larger textures. See: // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476874.aspx find_max_texture_dimension(ra); + +#if HAVE_DXGI_DEBUG + // Ignore any messages during find_max_texture_dimension + if (p->iqueue) + IDXGIInfoQueue_ClearStoredMessages(p->iqueue, DXGI_DEBUG_ALL); +#endif + MP_VERBOSE(ra, "Maximum Texture2D size: %dx%d\n", ra->max_texture_wh, ra->max_texture_wh); diff - |