summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/context_angle.c
diff options
context:
space:
mode:
authorJames Ross-Gowan <rossy@jrg.systems>2017-08-15 23:39:55 +1000
committerJames Ross-Gowan <rossy@jrg.systems>2017-08-17 00:28:38 +1000
commit16e0a3948288e37034c572617cf47b0a4dc0e10e (patch)
tree8c01b2e13182a975dcb172c366a178d89a0a5d7c /video/out/opengl/context_angle.c
parentf24612db443999c8a7c020a9123b51b957d374e2 (diff)
downloadmpv-16e0a3948288e37034c572617cf47b0a4dc0e10e.tar.bz2
mpv-16e0a3948288e37034c572617cf47b0a4dc0e10e.tar.xz
vo_opengl: extract non-ANGLE specific D3D11 code
This extracts non-ANGLE specific code to d3d11_helpers.c, which is modeled after egl_helpers.c. Currently the only consumer is context_angle.c, but in future this may allow the D3D11 device and swapchain creation logic to be reused in other backends. Also includes small improvements to D3D11 device creation. It is now possible to create feature level 11_1 devices (though ANGLE does not support these,) and BGRA swapchains, which might be slightly more efficient than ARGB, since its the same format used by the compositor.
Diffstat (limited to 'video/out/opengl/context_angle.c')
-rw-r--r--video/out/opengl/context_angle.c265
1 files changed, 33 insertions, 232 deletions
diff --git a/video/out/opengl/context_angle.c b/video/out/opengl/context_angle.c
index 13e29c410e..e09945ba2d 100644
--- a/video/out/opengl/context_angle.c
+++ b/video/out/opengl/context_angle.c
@@ -24,6 +24,7 @@
#include "angle_dynamic.h"
#include "egl_helpers.h"
+#include "d3d11_helpers.h"
#include "common/common.h"
#include "options/m_config.h"
@@ -40,9 +41,6 @@
#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002
#endif
-// Windows 8 enum value, not present in mingw-w64 headers
-#define DXGI_ADAPTER_FLAG_SOFTWARE (2)
-
enum {
RENDERER_AUTO,
RENDERER_D3D9,
@@ -97,17 +95,11 @@ const struct m_sub_options angle_conf = {
};
struct priv {
- IDXGIFactory1 *dxgi_factory;
- IDXGIFactory2 *dxgi_factory2;
- IDXGIAdapter1 *dxgi_adapter;
- IDXGIDevice1 *dxgi_device;
IDXGISwapChain *dxgi_swapchain;
- IDXGISwapChain1 *dxgi_swapchain1;
ID3D11Device *d3d11_device;
ID3D11DeviceContext *d3d11_context;
ID3D11Texture2D *d3d11_backbuffer;
- D3D_FEATURE_LEVEL d3d11_level;
EGLConfig egl_config;
EGLDisplay egl_display;
@@ -223,19 +215,6 @@ static void d3d11_device_destroy(MPGLContext *ctx)
p->egl_device = 0;
SAFE_RELEASE(p->d3d11_device);
- SAFE_RELEASE(p->dxgi_device);
- SAFE_RELEASE(p->dxgi_adapter);
- SAFE_RELEASE(p->dxgi_factory);
- SAFE_RELEASE(p->dxgi_factory2);
-}
-
-static void show_sw_adapter_msg(MPGLContext *ctx)
-{
- struct priv *p = ctx->priv;
- if (p->sw_adapter_msg_shown)
- return;
- MP_WARN(ctx->vo, "Using a software adapter\n");
- p->sw_adapter_msg_shown = true;
}
static bool d3d11_device_create(MPGLContext *ctx, int flags)
@@ -243,96 +222,17 @@ static bool d3d11_device_create(MPGLContext *ctx, int flags)
struct priv *p = ctx->priv;
struct vo *vo = ctx->vo;
struct angle_opts *o = p->opts;
- HRESULT hr;
- HMODULE d3d11_dll = LoadLibraryW(L"d3d11.dll");
- if (!d3d11_dll) {
- MP_FATAL(vo, "Failed to load d3d11.dll\n");
- return false;
- }
-
- PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)
- GetProcAddress(d3d11_dll, "D3D11CreateDevice");
- if (!D3D11CreateDevice) {
- MP_FATAL(vo, "D3D11CreateDevice entry point not found\n");
- return false;
- }
-
- D3D_FEATURE_LEVEL *levels = (D3D_FEATURE_LEVEL[]) {
- D3D_FEATURE_LEVEL_11_0,
- D3D_FEATURE_LEVEL_10_1,
- D3D_FEATURE_LEVEL_10_0,
- D3D_FEATURE_LEVEL_9_3,
+ struct d3d11_device_opts device_opts = {
+ .allow_warp = o->d3d11_warp != 0,
+ .force_warp = o->d3d11_warp == 1,
+ .max_feature_level = o->d3d11_feature_level,
+ .min_feature_level = D3D_FEATURE_LEVEL_9_3,
+ .max_frame_latency = o->max_frame_latency,
};
- int level_count = 4;
-
- // Only try feature levels less than or equal to the user specified level
- while (level_count && levels[0] > o->d3d11_feature_level) {
- levels++;
- level_count--;
- }
-
- // Try a HW adapter first unless WARP is forced
- hr = E_FAIL;
- if ((FAILED(hr) && o->d3d11_warp == -1) || o->d3d11_warp == 0) {
- hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, levels,
- level_count, D3D11_SDK_VERSION, &p->d3d11_device, &p->d3d11_level,
- &p->d3d11_context);
- }
- // Try WARP if it is forced or if the HW adapter failed
- if ((FAILED(hr) && o->d3d11_warp == -1) || o->d3d11_warp == 1) {
- hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, levels,
- level_count, D3D11_SDK_VERSION, &p->d3d11_device, &p->d3d11_level,
- &p->d3d11_context);
- if (SUCCEEDED(hr))
- show_sw_adapter_msg(ctx);
- }
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't create Direct3D 11 device: %s\n",
- mp_HRESULT_to_str(hr));
+ if (!mp_d3d11_create_present_device(vo->log, &device_opts, &p->d3d11_device))
return false;
- }
-
- hr = ID3D11Device_QueryInterface(p->d3d11_device, &IID_IDXGIDevice1,
- (void**)&p->dxgi_device);
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't get DXGI device\n");
- return false;
- }
-
- IDXGIDevice1_SetMaximumFrameLatency(p->dxgi_device, o->max_frame_latency);
-
- hr = IDXGIDevice1_GetParent(p->dxgi_device, &IID_IDXGIAdapter1,
- (void**)&p->dxgi_adapter);
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't get DXGI adapter\n");
- return false;
- }
-
- // Query some properties of the adapter in order to warn the user if they
- // are using a software adapter
- DXGI_ADAPTER_DESC1 desc;
- hr = IDXGIAdapter1_GetDesc1(p->dxgi_adapter, &desc);
- if (SUCCEEDED(hr)) {
- if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
- show_sw_adapter_msg(ctx);
-
- // If the primary display adapter is a software adapter, the
- // DXGI_ADAPTER_FLAG_SOFTWARE won't be set, but the device IDs
- // should still match the Microsoft Basic Render Driver
- if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c)
- show_sw_adapter_msg(ctx);
- }
-
- hr = IDXGIAdapter1_GetParent(p->dxgi_adapter, &IID_IDXGIFactory1,
- (void**)&p->dxgi_factory);
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't get DXGI factory\n");
- return false;
- }
-
- IDXGIFactory1_QueryInterface(p->dxgi_factory, &IID_IDXGIFactory2,
- (void**)&p->dxgi_factory2);
+ ID3D11Device_GetImmediateContext(p->d3d11_device, &p->d3d11_context);
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
(PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
@@ -367,119 +267,39 @@ static bool d3d11_device_create(MPGLContext *ctx, int flags)
static void d3d11_swapchain_surface_destroy(MPGLContext *ctx)
{
struct priv *p = ctx->priv;
+
+ bool had_swapchain = p->dxgi_swapchain;
SAFE_RELEASE(p->dxgi_swapchain);
- SAFE_RELEASE(p->dxgi_swapchain1);
d3d11_backbuffer_release(ctx);
-}
-
-static bool d3d11_swapchain_create_1_2(MPGLContext *ctx, int flags)
-{
- struct priv *p = ctx->priv;
- struct vo *vo = ctx->vo;
- HRESULT hr;
-
- update_sizes(ctx);
- DXGI_SWAP_CHAIN_DESC1 desc1 = {
- .Width = p->sc_width,
- .Height = p->sc_height,
- .Format = DXGI_FORMAT_R8G8B8A8_UNORM,
- .SampleDesc = { .Count = 1 },
- .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT |
- DXGI_USAGE_SHADER_INPUT,
- };
- if (p->opts->flip) {
- desc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
- desc1.BufferCount = p->opts->swapchain_length;
- } else {
- desc1.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
- desc1.BufferCount = 1;
- }
-
- hr = IDXGIFactory2_CreateSwapChainForHwnd(p->dxgi_factory2,
- (IUnknown*)p->d3d11_device, vo_w32_hwnd(vo), &desc1, NULL, NULL,
- &p->dxgi_swapchain1);
- if (FAILED(hr) && p->opts->flip) {
- // Try again without DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
- desc1.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
- desc1.BufferCount = 1;
-
- hr = IDXGIFactory2_CreateSwapChainForHwnd(p->dxgi_factory2,
- (IUnknown*)p->d3d11_device, vo_w32_hwnd(vo), &desc1, NULL, NULL,
- &p->dxgi_swapchain1);
- }
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't create DXGI 1.2+ swap chain: %s\n",
- mp_HRESULT_to_str(hr));
- return false;
- }
-
- hr = IDXGISwapChain1_QueryInterface(p->dxgi_swapchain1,
- &IID_IDXGISwapChain, (void**)&p->dxgi_swapchain);
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't create DXGI 1.2+ swap chain\n");
- return false;
- }
-
- return true;
-}
-
-static bool d3d11_swapchain_create_1_1(MPGLContext *ctx, int flags)
-{
- struct priv *p = ctx->priv;
- struct vo *vo = ctx->vo;
- HRESULT hr;
-
- update_sizes(ctx);
- DXGI_SWAP_CHAIN_DESC desc = {
- .BufferDesc = {
- .Width = p->sc_width,
- .Height = p->sc_height,
- .Format = DXGI_FORMAT_R8G8B8A8_UNORM
- },
- .SampleDesc = { .Count = 1 },
- .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT |
- DXGI_USAGE_SHADER_INPUT,
- .BufferCount = 1,
- .OutputWindow = vo_w32_hwnd(vo),
- .Windowed = TRUE,
- .SwapEffect = DXGI_SWAP_EFFECT_DISCARD,
- };
-
- hr = IDXGIFactory1_CreateSwapChain(p->dxgi_factory,
- (IUnknown*)p->d3d11_device, &desc, &p->dxgi_swapchain);
- if (FAILED(hr)) {
- MP_FATAL(vo, "Couldn't create DXGI 1.1 swap chain: %s\n",
- mp_HRESULT_to_str(hr));
- return false;
- }
-
- return true;
+ // Ensure the swapchain is destroyed by flushing the D3D11 immediate
+ // context. This is needed because the HWND may be reused. See:
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476425.aspx
+ if (had_swapchain && p->d3d11_context)
+ ID3D11DeviceContext_Flush(p->d3d11_context);
}
static bool d3d11_swapchain_surface_create(MPGLContext *ctx, int flags)
{
struct priv *p = ctx->priv;
struct vo *vo = ctx->vo;
+ struct angle_opts *o = p->opts;
- if (p->dxgi_factory2) {
- // Create a DXGI 1.2+ (Windows 8+) swap chain if possible
- if (!d3d11_swapchain_create_1_2(ctx, flags))
- goto fail;
- } else if (p->dxgi_factory) {
- // Fall back to DXGI 1.1 (Windows 7)
- if (!d3d11_swapchain_create_1_1(ctx, flags))
- goto fail;
- } else {
+ if (!p->d3d11_device)
goto fail;
- }
- // Prevent DXGI from making changes to the VO window, otherwise it will
- // hook the Alt+Enter keystroke and make it trigger an ugly transition to
- // exclusive fullscreen mode instead of running the user-set command.
- IDXGIFactory_MakeWindowAssociation(p->dxgi_factory, vo_w32_hwnd(vo),
- DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER |
- DXGI_MWA_NO_PRINT_SCREEN);
+ update_sizes(ctx);
+ struct d3d11_swapchain_opts swapchain_opts = {
+ .window = vo_w32_hwnd(vo),
+ .width = p->sc_width,
+ .height = p->sc_height,
+ .flip = o->flip,
+ .length = o->swapchain_length,
+ .usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT,
+ };
+ if (!mp_d3d11_create_swapchain(p->d3d11_device, vo->log, &swapchain_opts,
+ &p->dxgi_swapchain))
+ goto fail;
if (!d3d11_backbuffer_get(ctx))
goto fail;
@@ -677,10 +497,6 @@ static int angle_init(struct MPGLContext *ctx, int flags)
if ((!context_ok && !o->renderer) || o->renderer == RENDERER_D3D11) {
context_ok = d3d11_device_create(ctx, flags);
if (context_ok) {
- MP_VERBOSE(vo, "Using Direct3D 11 feature level %u_%u\n",
- ((unsigned)p->d3d11_level) >> 12,
- (((unsigned)p->d3d11_level) >> 8) & 0xf);
-
context_ok = context_init(ctx, flags);
if (!context_ok)
d3d11_device_destroy(ctx);
@@ -706,21 +522,6 @@ static int angle_init(struct MPGLContext *ctx, int flags)
bool surface_ok = false;
if ((!surface_ok && o->egl_windowing == -1) || o->egl_windowing == 0) {
surface_ok = d3d11_swapchain_surface_create(ctx, flags);
- if (surface_ok) {
- if (p->dxgi_swapchain1) {
- MP_VERBOSE(vo, "Using DXGI 1.2+\n");
-
- DXGI_SWAP_CHAIN_DESC1 scd = {0};
- IDXGISwapChain1_GetDesc1(p->dxgi_swapchain1, &scd);
- if (scd.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) {
- MP_VERBOSE(vo, "Using flip-model presentation\n");
- } else {
- MP_VERBOSE(vo, "Using bitblt-model presentation\n");
- }
- } else {
- MP_VERBOSE(vo, "Using DXGI 1.1\n");
- }
- }
}
if ((!surface_ok && o->egl_windowing == -1) || o->egl_windowing == 1) {
surface_ok = egl_window_surface_create(ctx, flags);
@@ -755,15 +556,15 @@ static struct mp_image *d3d11_screenshot(MPGLContext *ctx)
struct mp_image *img = NULL;
HRESULT hr;
- if (!p->dxgi_swapchain1)
+ if (!p->dxgi_swapchain)
goto done;
// Validate the swap chain. This screenshot method will only work on DXGI
// 1.2+ flip/sequential swap chains. It's probably not possible at all with
// discard swap chains, since by definition, the backbuffer contents is
// discarded on Present().
- DXGI_SWAP_CHAIN_DESC1 scd;
- hr = IDXGISwapChain1_GetDesc1(p->dxgi_swapchain1, &scd);
+ DXGI_SWAP_CHAIN_DESC scd;
+ hr = IDXGISwapChain_GetDesc(p->dxgi_swapchain, &scd);
if (FAILED(hr))
goto done;
if (scd.SwapEffect != DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL)