mirror of
https://github.com/mpv-player/mpv
synced 2025-03-11 08:37:59 +00:00
vo_gpu: d3d11: initial implementation
This is a new RA/vo_gpu backend that uses Direct3D 11. The GLSL generated by vo_gpu is cross-compiled to HLSL with SPIRV-Cross. What works: - All of mpv's internal shaders should work, including compute shaders. - Some external shaders have been tested and work, including RAVU and adaptive-sharpen. - Non-dumb mode works, even on very old hardware. Most features work at feature level 9_3 and all features work at feature level 10_0. Some features also work at feature level 9_1 and 9_2, but without high-bit- depth FBOs, it's not very useful. (Hardware this old is probably not fast enough for advanced features anyway.) Note: This is more compatible than ANGLE, which requires 9_3 to work at all (GLES 2.0,) and 10_1 for non-dumb-mode (GLES 3.0.) - Hardware decoding with D3D11VA, including decoding of 10-bit formats without truncation to 8-bit. What doesn't work / can be improved: - PBO upload and direct rendering does not work yet. Direct rendering requires persistent-mapped PBOs because the decoder needs to be able to read data from images that have already been decoded and uploaded. Unfortunately, it seems like persistent-mapped PBOs are fundamentally incompatible with D3D11, which requires all resources to use driver- managed memory and requires memory to be unmapped (and hence pointers to be invalidated) when a resource is used in a draw or copy operation. However it might be possible to use D3D11's limited multithreading capabilities to emulate some features of PBOs, like asynchronous texture uploading. - The blit() and clear() operations don't have equivalents in the D3D11 API that handle all cases, so in most cases, they have to be emulated with a shader. This is currently done inside ra_d3d11, but ideally it would be done in generic code, so it can take advantage of mpv's shader generation utilities. - SPIRV-Cross is used through a NIH C-compatible wrapper library, since it does not expose a C interface itself. The library is available here: https://github.com/rossy/crossc - The D3D11 context could be made to support more modern DXGI features in future. For example, it should be possible to add support for high-bit-depth and HDR output with DXGI 1.5/1.6.
This commit is contained in:
parent
8020a62953
commit
68eac1a1e7
@ -686,8 +686,8 @@ Video
|
||||
:dxva2: requires ``--vo=gpu`` with ``--gpu-context=angle`` or
|
||||
``--gpu-context=dxinterop`` (Windows only)
|
||||
:dxva2-copy: copies video back to system RAM (Windows only)
|
||||
:d3d11va: requires ``--vo=gpu`` with ``--gpu-context=angle``
|
||||
(Windows 8+ only)
|
||||
:d3d11va: requires ``--vo=gpu`` with ``--gpu-context=d3d11`` or
|
||||
``--gpu-context=angle`` (Windows 8+ only)
|
||||
:d3d11va-copy: copies video back to system RAM (Windows 8+ only)
|
||||
:mediacodec: requires ``--vo=mediacodec_embed`` (Android only)
|
||||
:mediacodec-copy: copies video back to system RAM (Android only)
|
||||
@ -775,10 +775,11 @@ Video
|
||||
BT.601 or BT.709, a forced, low-quality but correct RGB conversion is
|
||||
performed. Otherwise, the result will be totally incorrect.
|
||||
|
||||
``d3d11va`` is usually safe (if used with ANGLE builds that support
|
||||
``EGL_KHR_stream path`` - otherwise, it converts to RGB), except that
|
||||
10 bit input (HEVC main 10 profiles) will be rounded down to 8 bits,
|
||||
which results in reduced quality.
|
||||
``d3d11va`` is safe when used with the ``d3d11`` backend. If used with
|
||||
``angle`` is it usually safe, except that 10 bit input (HEVC main 10
|
||||
profiles) will be rounded down to 8 bits, which will result in reduced
|
||||
quality. Also note that with very old ANGLE builds (without
|
||||
``EGL_KHR_stream path``,) all input will be converted to RGB.
|
||||
|
||||
``dxva2`` is not safe. It appears to always use BT.601 for forced RGB
|
||||
conversion, but actual behavior depends on the GPU drivers. Some drivers
|
||||
@ -4272,6 +4273,30 @@ The following video options are currently all specific to ``--vo=gpu`` and
|
||||
as mpv's vulkan implementation currently does not try and protect textures
|
||||
against concurrent access.
|
||||
|
||||
``--d3d11-warp=<yes|no|auto>``
|
||||
Use WARP (Windows Advanced Rasterization Platform) with the D3D11 GPU
|
||||
backend (default: auto). This is a high performance software renderer. By
|
||||
default, it is only used when the system has no hardware adapters that
|
||||
support D3D11. While the extended GPU features will work with WARP, they
|
||||
can be very slow.
|
||||
|
||||
``--d3d11-feature-level=<12_1|12_0|11_1|11_0|10_1|10_0|9_3|9_2|9_1>``
|
||||
Select a specific feature level when using the D3D11 GPU backend. By
|
||||
default, the highest available feature level is used. This option can be
|
||||
used to select a lower feature level, which is mainly useful for debugging.
|
||||
Most extended GPU features will not work at 9_x feature levels.
|
||||
|
||||
``--d3d11-flip=<yes|no>``
|
||||
Enable flip-model presentation, which avoids unnecessarily copying the
|
||||
backbuffer by sharing surfaces with the DWM (default: yes). This may cause
|
||||
performance issues with older drivers. If flip-model presentation is not
|
||||
supported (for example, on Windows 7 without the platform update), mpv will
|
||||
automatically fall back to the older bitblt presentation model.
|
||||
|
||||
``--d3d11-sync-interval=<0..4>``
|
||||
Schedule each frame to be presented for this number of VBlank intervals.
|
||||
(default: 1) Setting to 1 will enable VSync, setting to 0 will disable it.
|
||||
|
||||
``--spirv-compiler=<compiler>``
|
||||
Controls which compiler is used to translate GLSL to SPIR-V. This is
|
||||
(currently) only relevant for ``--gpu-api=vulkan``. The possible choices
|
||||
@ -4694,6 +4719,8 @@ The following video options are currently all specific to ``--vo=gpu`` and
|
||||
Win32, using WGL for rendering and Direct3D 9Ex for presentation. Works
|
||||
on Nvidia and AMD. Newer Intel chips with the latest drivers may also
|
||||
work.
|
||||
d3d11
|
||||
Win32, with native Direct3D 11 rendering.
|
||||
x11
|
||||
X11/GLX
|
||||
x11vk
|
||||
@ -4728,6 +4755,8 @@ The following video options are currently all specific to ``--vo=gpu`` and
|
||||
Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)
|
||||
vulkan
|
||||
Allow only Vulkan (requires a valid/working ``--spirv-compiler``)
|
||||
d3d11
|
||||
Allow only ``--gpu-context=d3d11``
|
||||
|
||||
``--opengl-es=<mode>``
|
||||
Controls which type of OpenGL context will be accepted:
|
||||
|
@ -90,6 +90,7 @@ extern const struct m_obj_list ao_obj_list;
|
||||
extern const struct m_sub_options opengl_conf;
|
||||
extern const struct m_sub_options vulkan_conf;
|
||||
extern const struct m_sub_options spirv_conf;
|
||||
extern const struct m_sub_options d3d11_conf;
|
||||
extern const struct m_sub_options angle_conf;
|
||||
extern const struct m_sub_options cocoa_conf;
|
||||
|
||||
@ -699,6 +700,10 @@ const m_option_t mp_opts[] = {
|
||||
OPT_SUBSTRUCT("", vulkan_opts, vulkan_conf, 0),
|
||||
#endif
|
||||
|
||||
#if HAVE_D3D11
|
||||
OPT_SUBSTRUCT("", d3d11_opts, d3d11_conf, 0),
|
||||
#endif
|
||||
|
||||
#if HAVE_EGL_ANGLE_WIN32
|
||||
OPT_SUBSTRUCT("", angle_opts, angle_conf, 0),
|
||||
#endif
|
||||
|
@ -332,6 +332,7 @@ typedef struct MPOpts {
|
||||
struct opengl_opts *opengl_opts;
|
||||
struct vulkan_opts *vulkan_opts;
|
||||
struct spirv_opts *spirv_opts;
|
||||
struct d3d11_opts *d3d11_opts;
|
||||
struct cocoa_opts *cocoa_opts;
|
||||
struct dvd_opts *dvd_opts;
|
||||
|
||||
|
235
video/out/d3d11/context.c
Normal file
235
video/out/d3d11/context.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common/msg.h"
|
||||
#include "options/m_config.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
|
||||
#include "video/out/gpu/context.h"
|
||||
#include "video/out/gpu/d3d11_helpers.h"
|
||||
#include "video/out/gpu/spirv.h"
|
||||
#include "video/out/w32_common.h"
|
||||
#include "ra_d3d11.h"
|
||||
|
||||
struct d3d11_opts {
|
||||
int feature_level;
|
||||
int warp;
|
||||
int flip;
|
||||
int sync_interval;
|
||||
};
|
||||
|
||||
#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),
|
||||
{0}
|
||||
},
|
||||
.defaults = &(const struct d3d11_opts) {
|
||||
.feature_level = D3D_FEATURE_LEVEL_12_1,
|
||||
.warp = -1,
|
||||
.flip = 1,
|
||||
.sync_interval = 1,
|
||||
},
|
||||
.size = sizeof(struct d3d11_opts)
|
||||
};
|
||||
|
||||
struct priv {
|
||||
struct d3d11_opts *opts;
|
||||
|
||||
struct ra_tex *backbuffer;
|
||||
ID3D11Device *device;
|
||||
IDXGISwapChain *swapchain;
|
||||
};
|
||||
|
||||
static struct ra_tex *get_backbuffer(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
ID3D11Texture2D *backbuffer = NULL;
|
||||
struct ra_tex *tex = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
hr = IDXGISwapChain_GetBuffer(p->swapchain, 0, &IID_ID3D11Texture2D,
|
||||
(void**)&backbuffer);
|
||||
if (FAILED(hr)) {
|
||||
MP_ERR(ctx, "Couldn't get swapchain image\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
tex = ra_d3d11_wrap_tex(ctx->ra, (ID3D11Resource *)backbuffer);
|
||||
done:
|
||||
SAFE_RELEASE(backbuffer);
|
||||
return tex;
|
||||
}
|
||||
|
||||
static bool resize(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
HRESULT hr;
|
||||
|
||||
ra_tex_free(ctx->ra, &p->backbuffer);
|
||||
|
||||
hr = IDXGISwapChain_ResizeBuffers(p->swapchain, 0, ctx->vo->dwidth,
|
||||
ctx->vo->dheight, DXGI_FORMAT_UNKNOWN, 0);
|
||||
if (FAILED(hr)) {
|
||||
MP_FATAL(ctx, "Couldn't resize swapchain: %s\n", mp_HRESULT_to_str(hr));
|
||||
return false;
|
||||
}
|
||||
|
||||
p->backbuffer = get_backbuffer(ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d3d11_reconfig(struct ra_ctx *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
return resize(ctx);
|
||||
}
|
||||
|
||||
static int d3d11_color_depth(struct ra_swapchain *sw)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
static bool d3d11_start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
|
||||
{
|
||||
struct priv *p = sw->priv;
|
||||
*out_fbo = (struct ra_fbo) {
|
||||
.tex = p->backbuffer,
|
||||
.flip = false,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool d3d11_submit_frame(struct ra_swapchain *sw,
|
||||
const struct vo_frame *frame)
|
||||
{
|
||||
ra_d3d11_flush(sw->ctx->ra);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void d3d11_swap_buffers(struct ra_swapchain *sw)
|
||||
{
|
||||
struct priv *p = sw->priv;
|
||||
IDXGISwapChain_Present(p->swapchain, p->opts->sync_interval, 0);
|
||||
}
|
||||
|
||||
static int d3d11_control(struct ra_ctx *ctx, int *events, int request, void *arg)
|
||||
{
|
||||
int ret = vo_w32_control(ctx->vo, events, request, arg);
|
||||
if (*events & VO_EVENT_RESIZE) {
|
||||
if (!resize(ctx))
|
||||
return VO_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void d3d11_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
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
|
||||
// leak checker
|
||||
ctx->ra->fns->destroy(ctx->ra);
|
||||
}
|
||||
|
||||
static const struct ra_swapchain_fns d3d11_swapchain = {
|
||||
.color_depth = d3d11_color_depth,
|
||||
.start_frame = d3d11_start_frame,
|
||||
.submit_frame = d3d11_submit_frame,
|
||||
.swap_buffers = d3d11_swap_buffers,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
struct ra_swapchain *sw = ctx->swapchain = talloc_zero(ctx, struct ra_swapchain);
|
||||
sw->priv = p;
|
||||
sw->ctx = ctx;
|
||||
sw->fns = &d3d11_swapchain;
|
||||
|
||||
struct d3d11_device_opts dopts = {
|
||||
.debug = ctx->opts.debug,
|
||||
.allow_warp = p->opts->warp != 0,
|
||||
.force_warp = p->opts->warp == 1,
|
||||
.max_feature_level = p->opts->feature_level,
|
||||
.max_frame_latency = ctx->opts.swapchain_depth,
|
||||
};
|
||||
if (!mp_d3d11_create_present_device(ctx->log, &dopts, &p->device))
|
||||
goto error;
|
||||
|
||||
if (!spirv_compiler_init(ctx))
|
||||
goto error;
|
||||
ctx->ra = ra_d3d11_create(p->device, ctx->log, ctx->spirv);
|
||||
if (!ctx->ra)
|
||||
goto error;
|
||||
|
||||
if (!vo_w32_init(ctx->vo))
|
||||
goto error;
|
||||
|
||||
struct d3d11_swapchain_opts scopts = {
|
||||
.window = vo_w32_hwnd(ctx->vo),
|
||||
.width = ctx->vo->dwidth,
|
||||
.height = ctx->vo->dheight,
|
||||
.flip = p->opts->flip,
|
||||
// Add one frame for the backbuffer and one frame of "slack" to reduce
|
||||
// contention with the window manager when acquiring the backbuffer
|
||||
.length = ctx->opts.swapchain_depth + 2,
|
||||
.usage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
};
|
||||
if (!mp_d3d11_create_swapchain(p->device, ctx->log, &scopts, &p->swapchain))
|
||||
goto error;
|
||||
|
||||
p->backbuffer = get_backbuffer(ctx);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
d3d11_uninit(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct ra_ctx_fns ra_ctx_d3d11 = {
|
||||
.type = "d3d11",
|
||||
.name = "d3d11",
|
||||
.reconfig = d3d11_reconfig,
|
||||
.control = d3d11_control,
|
||||
.init = d3d11_init,
|
||||
.uninit = d3d11_uninit,
|
||||
};
|
195
video/out/d3d11/hwdec_d3d11va.c
Normal file
195
video/out/d3d11/hwdec_d3d11va.c
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/common.h"
|
||||
#include "osdep/windows_utils.h"
|
||||
#include "video/hwdec.h"
|
||||
#include "video/decode/d3d.h"
|
||||
#include "video/out/d3d11/ra_d3d11.h"
|
||||
#include "video/out/gpu/hwdec.h"
|
||||
|
||||
struct priv_owner {
|
||||
struct mp_hwdec_ctx hwctx;
|
||||
ID3D11Device *device;
|
||||
ID3D11Device1 *device1;
|
||||
};
|
||||
|
||||
struct priv {
|
||||
ID3D11DeviceContext1 *ctx;
|
||||
ID3D11Texture2D *copy_tex;
|
||||
};
|
||||
|
||||
static void uninit(struct ra_hwdec *hw)
|
||||
{
|
||||
struct priv_owner *p = hw->priv;
|
||||
if (p->hwctx.ctx)
|
||||
hwdec_devices_remove(hw->devs, &p->hwctx);
|
||||
SAFE_RELEASE(p->device);
|
||||
SAFE_RELEASE(p->device1);
|
||||
}
|
||||
|
||||
static int init(struct ra_hwdec *hw)
|
||||
{
|
||||
struct priv_owner *p = hw->priv;
|
||||
HRESULT hr;
|
||||
|
||||
if (!ra_is_d3d11(hw->ra))
|
||||
return -1;
|
||||
p->device = ra_d3d11_get_device(hw->ra);
|
||||
if (!p->device)
|
||||
return -1;
|
||||
|
||||
// D3D11VA requires Direct3D 11.1, so this should always succeed
|
||||
hr = ID3D11Device_QueryInterface(p->device, &IID_ID3D11Device1,
|
||||
(void**)&p->device1);
|
||||
if (FAILED(hr)) {
|
||||
MP_ERR(hw, "Failed to get D3D11.1 interface: %s\n",
|
||||
mp_HRESULT_to_str(hr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ID3D10Multithread *multithread;
|
||||
hr = ID3D11Device_QueryInterface(p->device, &IID_ID3D10Multithread,
|
||||
(void **)&multithread);
|
||||
if (FAILED(hr)) {
|
||||
MP_ERR(hw, "Failed to get Multithread interface: %s\n",
|
||||
mp_HRESULT_to_str(hr));
|
||||
return -1;
|
||||
}
|
||||
ID3D10Multithread_SetMultithreadProtected(multithread, TRUE);
|
||||
ID3D10Multithread_Release(multithread);
|
||||
|
||||
p->hwctx = (struct mp_hwdec_ctx){
|
||||
.type = HWDEC_D3D11VA,
|
||||
.driver_name = hw->driver->name,
|
||||
.ctx = p->device,
|
||||
.av_device_ref = d3d11_wrap_device_ref(p->device),
|
||||
};
|
||||
hwdec_devices_add(hw->devs, &p->hwctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mapper_uninit(struct ra_hwdec_mapper *mapper)
|
||||
{
|
||||
struct priv *p = mapper->priv;
|
||||
for (int i = 0; i < 4; i++)
|
||||
ra_tex_free(mapper->ra, &mapper->tex[i]);
|
||||
SAFE_RELEASE(p->copy_tex);
|
||||
SAFE_RELEASE(p->ctx);
|
||||
}
|
||||
|
||||
static int mapper_init(struct ra_hwdec_mapper *mapper)
|
||||
{
|
||||
struct priv_owner *o = mapper->owner->priv;
|
||||
struct priv *p = mapper->priv;
|
||||
HRESULT hr;
|
||||
|
||||
mapper->dst_params = mapper->src_params;
|
||||
mapper->dst_params.imgfmt = mapper->src_params.hw_subfmt;
|
||||
mapper->dst_params.hw_subfmt = 0;
|
||||
|
||||
struct ra_imgfmt_desc desc = {0};
|
||||
struct mp_image layout = {0};
|
||||
|
||||
if (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &desc))
|
||||
return -1;
|
||||
|
||||
mp_image_set_params(&layout, &mapper->dst_params);
|
||||
|
||||
DXGI_FORMAT copy_fmt;
|
||||
switch (mapper->dst_params.imgfmt) {
|
||||
case IMGFMT_NV12: copy_fmt = DXGI_FORMAT_NV12; break;
|
||||
case IMGFMT_P010: copy_fmt = DXGI_FORMAT_P010; break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
// We copy decoder images to an intermediate texture. This is slower than
|
||||
// the zero-copy path, but according to MSDN, decoder textures should not
|
||||
// be bound to SRVs, so it is technically correct, and it works around some
|
||||
// driver "bugs" that can happen with the zero-copy path. It also allows
|
||||
// samplers to work correctly when the decoder image includes padding.
|
||||
D3D11_TEXTURE2D_DESC copy_desc = {
|
||||
.Width = mapper->dst_params.w,
|
||||
.Height = mapper->dst_params.h,
|
||||
.MipLevels = 1,
|
||||
.ArraySize = 1,
|
||||
.SampleDesc.Count = 1,
|
||||
.Format = copy_fmt,
|
||||
.BindFlags = D3D11_BIND_SHADER_RESOURCE,
|
||||
};
|
||||
hr = ID3D11Device_CreateTexture2D(o->device, ©_desc, NULL, &p->copy_tex);
|
||||
if (FAILED(hr)) {
|
||||
MP_FATAL(mapper, "Could not create shader resource texture\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < desc.num_planes; i++) {
|
||||
mapper->tex[i] = ra_d3d11_wrap_tex_video(mapper->ra, p->copy_tex,
|
||||
mp_image_plane_w(&layout, i),
|
||||
mp_image_plane_h(&layout, i),
|
||||
desc.planes[i]);
|
||||
if (!mapper->tex[i]) {
|
||||
MP_FATAL(mapper, "Could not create RA texture view\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11Device1_GetImmediateContext1(o->device1, &p->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mapper_map(struct ra_hwdec_mapper *mapper)
|
||||
{
|
||||
struct priv *p = mapper->priv;
|
||||
ID3D11Texture2D *tex = (void *)mapper->src->planes[0];
|
||||
int subresource = (intptr_t)mapper->src->planes[1];
|
||||
|
||||
ID3D11DeviceContext1_CopySubresourceRegion1(p->ctx,
|
||||
(ID3D11Resource *)p->copy_tex, 0, 0, 0, 0,
|
||||
(ID3D11Resource *)tex, subresource, (&(D3D11_BOX) {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.front = 0,
|
||||
.right = mapper->dst_params.w,
|
||||
.bottom = mapper->dst_params.h,
|
||||
.back = 1,
|
||||
}), D3D11_COPY_DISCARD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ra_hwdec_driver ra_hwdec_d3d11va = {
|
||||
.name = "d3d11va",
|
||||
.priv_size = sizeof(struct priv_owner),
|
||||
.api = HWDEC_D3D11VA,
|
||||
.imgfmts = {IMGFMT_D3D11VA, IMGFMT_D3D11NV12, 0},
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.mapper = &(const struct ra_hwdec_mapper_driver){
|
||||
.priv_size = sizeof(struct priv),
|
||||
.init = mapper_init,
|
||||
.uninit = mapper_uninit,
|
||||
.map = mapper_map,
|
||||
},
|
||||
};
|
2235
video/out/d3d11/ra_d3d11.c
Normal file
2235
video/out/d3d11/ra_d3d11.c
Normal file
File diff suppressed because it is too large
Load Diff
34
video/out/d3d11/ra_d3d11.h
Normal file
34
video/out/d3d11/ra_d3d11.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#include "video/out/gpu/ra.h"
|
||||
#include "video/out/gpu/spirv.h"
|
||||
|
||||
// Create an RA instance from a D3D11 device. This takes a reference to the
|
||||
// device, which is released when the RA instance is destroyed.
|
||||
struct ra *ra_d3d11_create(ID3D11Device *device, struct mp_log *log,
|
||||
struct spirv_compiler *spirv);
|
||||
|
||||
// Flush the immediate context of the wrapped D3D11 device
|
||||
void ra_d3d11_flush(struct ra *ra);
|
||||
|
||||
// Create an RA texture from a D3D11 resource. This takes a reference to the
|
||||
// texture, which is released when the RA texture is destroyed.
|
||||
struct ra_tex *ra_d3d11_wrap_tex(struct ra *ra, ID3D11Resource *res);
|
||||
|
||||
// As above, but for a D3D11VA video resource. The fmt parameter selects which
|
||||
// plane of a planar format will be mapped when the RA texture is used.
|
||||
struct ra_tex *ra_d3d11_wrap_tex_video(struct ra *ra, ID3D11Texture2D *res,
|
||||
int w, int h,
|
||||
const struct ra_format *fmt);
|
||||
|
||||
// Get the underlying D3D11 device from an RA instance. The returned device is
|
||||
// refcounted and must be released by the caller.
|
||||
ID3D11Device *ra_d3d11_get_device(struct ra *ra);
|
||||
|
||||
// True if the RA instance was created with ra_d3d11_create()
|
||||
bool ra_is_d3d11(struct ra *ra);
|
@ -53,7 +53,14 @@ 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;
|
||||
|
||||
/* Direct3D 11 */
|
||||
extern const struct ra_ctx_fns ra_ctx_d3d11;
|
||||
|
||||
static const struct ra_ctx_fns *contexts[] = {
|
||||
#if HAVE_D3D11
|
||||
&ra_ctx_d3d11,
|
||||
#endif
|
||||
|
||||
// OpenGL contexts:
|
||||
#if HAVE_ANDROID
|
||||
&ra_ctx_android,
|
||||
|
@ -46,6 +46,8 @@ static int get_feature_levels(int max_fl, int min_fl,
|
||||
const D3D_FEATURE_LEVEL **out)
|
||||
{
|
||||
static const D3D_FEATURE_LEVEL levels[] = {
|
||||
D3D_FEATURE_LEVEL_12_1,
|
||||
D3D_FEATURE_LEVEL_12_0,
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_1,
|
||||
@ -71,7 +73,8 @@ static int get_feature_levels(int max_fl, int min_fl,
|
||||
}
|
||||
|
||||
static HRESULT create_device(struct mp_log *log, bool warp, bool bgra,
|
||||
int max_fl, int min_fl, ID3D11Device **dev)
|
||||
bool debug, int max_fl, int min_fl,
|
||||
ID3D11Device **dev)
|
||||
{
|
||||
const D3D_FEATURE_LEVEL *levels;
|
||||
int levels_len = get_feature_levels(max_fl, min_fl, &levels);
|
||||
@ -82,7 +85,11 @@ static HRESULT create_device(struct mp_log *log, bool warp, bool bgra,
|
||||
|
||||
D3D_DRIVER_TYPE type = warp ? D3D_DRIVER_TYPE_WARP
|
||||
: D3D_DRIVER_TYPE_HARDWARE;
|
||||
UINT flags = bgra ? D3D11_CREATE_DEVICE_BGRA_SUPPORT : 0;
|
||||
UINT flags = 0;
|
||||
if (bgra)
|
||||
flags |= D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
if (debug)
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
return pD3D11CreateDevice(NULL, type, NULL, flags, levels, levels_len,
|
||||
D3D11_SDK_VERSION, dev, NULL, NULL);
|
||||
}
|
||||
@ -116,7 +123,7 @@ 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, warp, bgra, max_fl, min_fl, &dev);
|
||||
hr = create_device(log, warp, bgra, opts->debug, max_fl, min_fl, &dev);
|
||||
if (SUCCEEDED(hr))
|
||||
break;
|
||||
|
||||
@ -127,8 +134,19 @@ bool mp_d3d11_create_present_device(struct mp_log *log,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Trying to create a D3D_FEATURE_LEVEL_12_0 device on Windows 8.1 or
|
||||
// below will not succeed. Try an 11_1 device.
|
||||
if (max_fl >= D3D_FEATURE_LEVEL_12_0 &&
|
||||
min_fl <= D3D_FEATURE_LEVEL_11_1)
|
||||
{
|
||||
mp_dbg(log, "Failed to create 12_0+ device, trying 11_1\n");
|
||||
max_fl = D3D_FEATURE_LEVEL_11_1;
|
||||
bgra = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Trying to create a D3D_FEATURE_LEVEL_11_1 device on Windows 7
|
||||
// without the platform update will not succeed. Try a 11_0 device.
|
||||
// without the platform update will not succeed. Try an 11_0 device.
|
||||
if (max_fl >= D3D_FEATURE_LEVEL_11_1 &&
|
||||
min_fl <= D3D_FEATURE_LEVEL_11_0)
|
||||
{
|
@ -23,7 +23,13 @@
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#define D3D_FEATURE_LEVEL_12_0 (0xc000)
|
||||
#define D3D_FEATURE_LEVEL_12_1 (0xc100)
|
||||
|
||||
struct d3d11_device_opts {
|
||||
// Enable the debug layer (D3D11_CREATE_DEVICE_DEBUG)
|
||||
bool debug;
|
||||
|
||||
// Allow a software (WARP) adapter. Note, sometimes a software adapter will
|
||||
// be used even when allow_warp is false. This is because, on Windows 8 and
|
||||
// up, if there are no hardware adapters, Windows will pretend the WARP
|
@ -34,6 +34,7 @@ extern const struct ra_hwdec_driver ra_hwdec_d3d11egl;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_d3d11eglrgb;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_dxva2gldx;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_dxva2;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_d3d11va;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_cuda;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_cuda_nvdec;
|
||||
extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay;
|
||||
@ -58,6 +59,9 @@ static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = {
|
||||
#if HAVE_D3D9_HWACCEL
|
||||
&ra_hwdec_dxva2egl,
|
||||
#endif
|
||||
#if HAVE_D3D11
|
||||
&ra_hwdec_d3d11va,
|
||||
#endif
|
||||
#endif
|
||||
#if HAVE_GL_DXINTEROP_D3D9
|
||||
&ra_hwdec_dxva2gldx,
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "angle_dynamic.h"
|
||||
#include "egl_helpers.h"
|
||||
#include "d3d11_helpers.h"
|
||||
#include "video/out/gpu/d3d11_helpers.h"
|
||||
|
||||
#include "common/common.h"
|
||||
#include "options/m_config.h"
|
||||
|
17
wscript
17
wscript
@ -753,6 +753,19 @@ video_output_features = [
|
||||
'desc': 'Direct3D support',
|
||||
'deps': 'win32-desktop && gpl',
|
||||
'func': check_cc(header_name='d3d9.h'),
|
||||
}, {
|
||||
'name': '--shaderc',
|
||||
'desc': 'libshaderc SPIR-V compiler',
|
||||
'func': check_cc(header_name='shaderc/shaderc.h', lib='shaderc_shared'),
|
||||
}, {
|
||||
'name': '--crossc',
|
||||
'desc': 'libcrossc SPIR-V translator',
|
||||
'func': check_pkg_config('crossc'),
|
||||
}, {
|
||||
'name': '--d3d11',
|
||||
'desc': 'Direct3D 11 video output',
|
||||
'deps': 'win32-desktop && shaderc && crossc',
|
||||
'func': check_cc(header_name=['d3d11_1.h', 'dxgi1_2.h']),
|
||||
}, {
|
||||
# We need MMAL/bcm_host/dispmanx APIs. Also, most RPI distros require
|
||||
# every project to hardcode the paths to the include directories. Also,
|
||||
@ -806,10 +819,6 @@ video_output_features = [
|
||||
'name': '--vulkan',
|
||||
'desc': 'Vulkan context support',
|
||||
'func': check_pkg_config('vulkan'),
|
||||
}, {
|
||||
'name': '--shaderc',
|
||||
'desc': 'libshaderc SPIR-V compiler',
|
||||
'func': check_cc(header_name='shaderc/shaderc.h', lib='shaderc_shared'),
|
||||
}, {
|
||||
'name': 'egl-helpers',
|
||||
'desc': 'EGL helper functions',
|
||||
|
@ -401,8 +401,12 @@ def build(ctx):
|
||||
( "video/out/cocoa_common.m", "cocoa" ),
|
||||
( "video/out/dither.c" ),
|
||||
( "video/out/filter_kernels.c" ),
|
||||
( "video/out/d3d11/context.c", "d3d11" ),
|
||||
( "video/out/d3d11/hwdec_d3d11va.c", "d3d11 && d3d-hwaccel" ),
|
||||
( "video/out/d3d11/ra_d3d11.c", "d3d11" ),
|
||||
( "video/out/opengl/angle_dynamic.c", "egl-angle" ),
|
||||
( "video/out/gpu/context.c" ),
|
||||
( "video/out/gpu/d3d11_helpers.c", "d3d11 || egl-angle-win32" ),
|
||||
( "video/out/gpu/hwdec.c" ),
|
||||
( "video/out/gpu/lcms.c" ),
|
||||
( "video/out/gpu/osd.c" ),
|
||||
@ -432,7 +436,6 @@ def build(ctx):
|
||||
( "video/out/opengl/context_glx.c", "gl-x11" ),
|
||||
( "video/out/opengl/context_x11egl.c", "egl-x11" ),
|
||||
( "video/out/opengl/cuda_dynamic.c", "cuda-hwaccel" ),
|
||||
( "video/out/opengl/d3d11_helpers.c", "egl-angle-win32" ),
|
||||
( "video/out/opengl/egl_helpers.c", "egl-helpers" ),
|
||||
( "video/out/opengl/hwdec_cuda.c", "cuda-hwaccel" ),
|
||||
( "video/out/opengl/hwdec_d3d11egl.c", "d3d-hwaccel" ),
|
||||
|
Loading…
Reference in New Issue
Block a user