direct3d11.c 70 KB
Newer Older
Martell Malone's avatar
Martell Malone committed
1 2 3 4 5 6
/*****************************************************************************
 * direct3d11.c: Windows Direct3D11 video output module
 *****************************************************************************
 * Copyright (C) 2014-2015 VLC authors and VideoLAN
 *
 * Authors: Martell Malone <martellmalone@gmail.com>
7
 *          Steve Lhomme <robux4@gmail.com>
Martell Malone's avatar
Martell Malone committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

24 25 26 27 28
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x601
# undef _WIN32_WINNT
# define _WIN32_WINNT 0x601
#endif

Martell Malone's avatar
Martell Malone committed
29 30 31 32 33 34 35 36
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout_display.h>

37 38
#include <assert.h>

Martell Malone's avatar
Martell Malone committed
39
#define COBJMACROS
40
#define INITGUID
Martell Malone's avatar
Martell Malone committed
41 42 43 44 45 46 47
#include <d3d11.h>

/* avoided until we can pass ISwapchainPanel without c++/cx mode
# include <windows.ui.xaml.media.dxinterop.h> */

#include "common.h"

48 49
#include "../../video_chroma/dxgi_fmt.h"

Martell Malone's avatar
Martell Malone committed
50
#if !VLC_WINSTORE_APP
51 52 53 54 55
# if USE_DXGI
#  define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
# else
#  define D3D11CreateDevice(args...)             sys->OurD3D11CreateDevice(args)
# endif
Martell Malone's avatar
Martell Malone committed
56 57 58
# define D3DCompile(args...)                    sys->OurD3DCompile(args)
#endif

59 60
DEFINE_GUID(GUID_SWAPCHAIN_WIDTH,  0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
61
DEFINE_GUID(GUID_CONTEXT_MUTEX,    0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
62

Martell Malone's avatar
Martell Malone committed
63 64 65 66
static int  Open(vlc_object_t *);
static void Close(vlc_object_t *);

#define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
67 68 69
#define HW_BLENDING_TEXT N_("Use hardware blending support")
#define HW_BLENDING_LONGTEXT N_(\
    "Try to use hardware acceleration for subtitle/OSD blending.")
Martell Malone's avatar
Martell Malone committed
70 71 72 73 74 75 76

vlc_module_begin ()
    set_shortname("Direct3D11")
    set_description(N_("Direct3D11 video output"))
    set_help(D3D11_HELP)
    set_category(CAT_VIDEO)
    set_subcategory(SUBCAT_VIDEO_VOUT)
77 78 79

    add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT, true)

80
#if VLC_WINSTORE_APP
81 82 83
    add_integer("winrt-d3ddevice",     0x0, NULL, NULL, true); /* ID3D11Device*        */
    add_integer("winrt-d3dcontext",    0x0, NULL, NULL, true); /* ID3D11DeviceContext* */
    add_integer("winrt-swapchain",     0x0, NULL, NULL, true); /* IDXGISwapChain1*     */
84 85
#endif

Martell Malone's avatar
Martell Malone committed
86 87 88 89 90
    set_capability("vout display", 240)
    add_shortcut("direct3d11")
    set_callbacks(Open, Close)
vlc_module_end ()

91
#ifdef HAVE_ID3D11VIDEODECODER
92
/* VLC_CODEC_D3D11_OPAQUE */
Martell Malone's avatar
Martell Malone committed
93 94
struct picture_sys_t
{
95 96 97
    ID3D11VideoDecoderOutputView  *decoder; /* may be NULL for pictures from the pool */
    ID3D11Texture2D               *texture;
    ID3D11DeviceContext           *context;
98
    unsigned                      slice_index;
Martell Malone's avatar
Martell Malone committed
99
};
100
#endif
Martell Malone's avatar
Martell Malone committed
101

102 103 104 105 106 107 108
/* internal picture_t pool  */
typedef struct
{
    ID3D11Texture2D               *texture;
    vout_display_t                *vd;
} picture_sys_pool_t;

109 110
/* matches the D3D11_INPUT_ELEMENT_DESC we setup */
typedef struct d3d_vertex_t {
111
    struct {
112 113 114 115 116 117 118
        FLOAT x;
        FLOAT y;
        FLOAT z;
    } position;
    struct {
        FLOAT x;
        FLOAT y;
119
    } texture;
120
    FLOAT       opacity;
121 122
} d3d_vertex_t;

123 124
#define RECTWidth(r)   (int)((r).right - (r).left)
#define RECTHeight(r)  (int)((r).bottom - (r).top)
125

126 127
static picture_pool_t *Pool(vout_display_t *vd, unsigned count);

Martell Malone's avatar
Martell Malone committed
128 129 130
static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);

131
static HINSTANCE Direct3D11LoadShaderLibrary(void);
Martell Malone's avatar
Martell Malone committed
132 133 134 135 136 137 138 139
static void Direct3D11Destroy(vout_display_t *);

static int  Direct3D11Open (vout_display_t *, video_format_t *);
static void Direct3D11Close(vout_display_t *);

static int  Direct3D11CreateResources (vout_display_t *, video_format_t *);
static void Direct3D11DestroyResources(vout_display_t *);

140 141 142 143 144
static int  Direct3D11CreatePool (vout_display_t *, video_format_t *);
static void Direct3D11DestroyPool(vout_display_t *);

static void DestroyDisplayPicture(picture_t *);
static void DestroyDisplayPoolPicture(picture_t *);
Martell Malone's avatar
Martell Malone committed
145
static int  Direct3D11MapTexture(picture_t *);
146
static int  Direct3D11UnmapTexture(picture_t *);
147 148
static void Direct3D11DeleteRegions(int, picture_t **);
static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
Martell Malone's avatar
Martell Malone committed
149

150
static int AllocQuad(vout_display_t *, const video_format_t *, d3d_quad_t *,
151
                     d3d_quad_cfg_t *, ID3D11PixelShader *, bool b_visible);
152
static void ReleaseQuad(d3d_quad_t *);
153
static void UpdatePicQuadPosition(vout_display_t *);
154
static void UpdateQuadOpacity(vout_display_t *, const d3d_quad_t *, float);
155

156
static int Control(vout_display_t *vd, int query, va_list args);
157 158
static void Manage(vout_display_t *vd);

159
/* All the #if USE_DXGI contain an alternative method to setup dx11
Martell Malone's avatar
Martell Malone committed
160
   They both need to be benchmarked to see which performs better */
161
#if USE_DXGI
Martell Malone's avatar
Martell Malone committed
162 163 164 165 166 167 168 169 170 171 172
/* I have no idea why MS decided dxgi headers do not define this
   As they do have prototypes for d3d11 functions */
typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
#endif

/* TODO: Move to a direct3d11_shaders header */
static const char* globVertexShaderDefault = "\
  struct VS_INPUT\
  {\
    float4 Position   : POSITION;\
    float2 Texture    : TEXCOORD0;\
173
    float  Opacity    : OPACITY;\
Martell Malone's avatar
Martell Malone committed
174 175 176 177 178 179
  };\
  \
  struct VS_OUTPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
180
    float  Opacity    : OPACITY;\
Martell Malone's avatar
Martell Malone committed
181 182 183 184 185
  };\
  \
  VS_OUTPUT VS( VS_INPUT In )\
  {\
    VS_OUTPUT Output;\
186
    Output.Position = In.Position;\
Martell Malone's avatar
Martell Malone committed
187
    Output.Texture = In.Texture;\
188
    Output.Opacity = In.Opacity;\
Martell Malone's avatar
Martell Malone committed
189 190 191 192 193 194 195 196 197 198 199 200
    return Output;\
  }\
";

static const char* globPixelShaderDefault = "\
  Texture2D shaderTexture;\
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
201
    float  Opacity    : OPACITY;\
Martell Malone's avatar
Martell Malone committed
202 203 204 205
  };\
  \
  float4 PS( PS_INPUT In ) : SV_TARGET\
  {\
206 207 208 209 210
    float4 rgba; \
    \
    rgba = shaderTexture.Sample(SampleType, In.Texture);\
    rgba.a = rgba.a * In.Opacity;\
    return rgba; \
Martell Malone's avatar
Martell Malone committed
211 212 213
  }\
";

214
static const char *globPixelShaderBiplanarYUV_BT601_2RGB = "\
Martell Malone's avatar
Martell Malone committed
215 216 217 218 219 220 221 222
  Texture2D shaderTextureY;\
  Texture2D shaderTextureUV;\
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
223
    float  Opacity    : OPACITY;\
Martell Malone's avatar
Martell Malone committed
224 225 226 227 228 229 230 231
  };\
  \
  float4 PS( PS_INPUT In ) : SV_TARGET\
  {\
    float3 yuv;\
    float4 rgba;\
    yuv.x  = shaderTextureY.Sample(SampleType, In.Texture).x;\
    yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
232
    yuv.x  = 1.164383561643836 * (yuv.x-0.0625);\
Martell Malone's avatar
Martell Malone committed
233 234
    yuv.y  = yuv.y - 0.5;\
    yuv.z  = yuv.z - 0.5;\
235 236 237
    rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
    rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
    rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
238
    rgba.a = In.Opacity;\
Martell Malone's avatar
Martell Malone committed
239 240 241 242
    return rgba;\
  }\
";

243 244 245 246 247 248 249 250 251
static const char *globPixelShaderBiplanarYUV_BT709_2RGB = "\
  Texture2D shaderTextureY;\
  Texture2D shaderTextureUV;\
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
252
    float  Opacity    : OPACITY;\
253 254 255 256 257 258 259 260 261 262 263 264 265 266
  };\
  \
  float4 PS( PS_INPUT In ) : SV_TARGET\
  {\
    float3 yuv;\
    float4 rgba;\
    yuv.x  = shaderTextureY.Sample(SampleType, In.Texture).x;\
    yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
    yuv.x  = 1.164383561643836 * (yuv.x-0.0625);\
    yuv.y  = yuv.y - 0.5;\
    yuv.z  = yuv.z - 0.5;\
    rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
    rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
    rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
267
    rgba.a = In.Opacity;\
268 269 270
    return rgba;\
  }\
";
271

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
/* RGB-709 to RGB-2020 based on https://www.researchgate.net/publication/258434326_Beyond_BT709 */
static const char *globPixelShaderBiplanarYUV_BT2020_2RGB = "\
  Texture2D shaderTextureY;\
  Texture2D shaderTextureUV;\
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
    float  Opacity    : OPACITY;\
  };\
  \
  float4 PS( PS_INPUT In ) : SV_TARGET\
  {\
    float3 yuv;\
    float4 rgba;\
    yuv.x  = shaderTextureY.Sample(SampleType, In.Texture).x;\
    yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
    yuv.x  = 1.164383561643836 * (yuv.x-0.0625);\
    yuv.y  = yuv.y - 0.5;\
    yuv.z  = yuv.z - 0.5;\
294 295 296
    rgba.x = yuv.x + 1.792741071428571 * yuv.z;\
    rgba.y = yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y;\
    rgba.z = yuv.x + 2.112401785714286 * yuv.y;\
297 298 299 300 301 302 303 304
    rgba.x = saturate( 1.661 * rgba.x - 0.588 * rgba.y - 0.073 * rgba.z);\
    rgba.y = saturate(-0.125 * rgba.x + 1.133 * rgba.y - 0.008 * rgba.z);\
    rgba.z = saturate(-0.018 * rgba.x - 0.101 * rgba.y + 1.119 * rgba.z);\
    rgba.a = In.Opacity;\
    return rgba;\
  }\
";

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
static const char *globPixelShaderBiplanarYUYV_BT709_2RGB = "\
  Texture2D shaderTextureYUYV;\
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
    float  Opacity    : OPACITY;\
  };\
  \
  float4 PS( PS_INPUT In ) : SV_TARGET\
  {\
    float3 yuv;\
    float4 rgba;\
    yuv.x  = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
    yuv.y  = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
    yuv.z  = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
    yuv.x  = 1.164383561643836 * (yuv.x-0.0625);\
    yuv.y  = yuv.y - 0.5;\
    yuv.z  = yuv.z - 0.5;\
    rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
    rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
    rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
    rgba.a = In.Opacity;\
    return rgba;\
  }\
";

static const char *globPixelShaderBiplanarYUYV_BT601_2RGB = "\
  Texture2D shaderTextureYUYV;\
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
    float2 Texture    : TEXCOORD0;\
    float  Opacity    : OPACITY;\
  };\
  \
  float4 PS( PS_INPUT In ) : SV_TARGET\
  {\
    float3 yuv;\
    float4 rgba;\
    yuv.x  = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
    yuv.y  = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
    yuv.z  = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
    yuv.x  = 1.164383561643836 * (yuv.x-0.0625);\
    yuv.y  = yuv.y - 0.5;\
    yuv.z  = yuv.z - 0.5;\
    rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
    rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
    rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
    rgba.a = In.Opacity;\
    return rgba;\
  }\
";

363
#if !VLC_WINSTORE_APP
364 365
static int OpenHwnd(vout_display_t *vd)
{
366 367 368 369 370 371 372 373 374
    HINSTANCE hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
    if (!hd3d11_dll) {
        msg_Warn(vd, "cannot load d3d11.dll, aborting");
        return VLC_EGENERIC;
    }

    HINSTANCE hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
    if (!hd3dcompiler_dll) {
        msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
375
        Direct3D11Destroy(vd);
376 377 378
        return VLC_EGENERIC;
    }

379
# if USE_DXGI
380 381 382
    HINSTANCE hdxgi_dll = LoadLibrary(TEXT("DXGI.DLL"));
    if (!hdxgi_dll) {
        msg_Warn(vd, "cannot load dxgi.dll, aborting");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
383
        Direct3D11Destroy(vd);
384 385 386 387 388 389 390 391 392 393 394 395 396 397
        return VLC_EGENERIC;
    }
# endif

    vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
    if (!sys)
        return VLC_ENOMEM;

    sys->hd3d11_dll       = hd3d11_dll;
    sys->hd3dcompiler_dll = hd3dcompiler_dll;

    sys->OurD3DCompile = (void *)GetProcAddress(sys->hd3dcompiler_dll, "D3DCompile");
    if (!sys->OurD3DCompile) {
        msg_Err(vd, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
Martell Malone's avatar
Martell Malone committed
398 399 400 401
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }

402
# if USE_DXGI
403 404 405 406
    sys->hdxgi_dll = hdxgi_dll;

    /* TODO : enable all dxgi versions from 1.3 -> 1.1 */
    PFN_CREATE_DXGI_FACTORY OurCreateDXGIFactory =
407
        (void *)GetProcAddress(hdxgi_dll, "CreateDXGIFactory");
408 409 410 411 412 413
    if (!OurCreateDXGIFactory) {
        msg_Err(vd, "Cannot locate reference to CreateDXGIFactory in dxgi DLL");
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }

414 415 416 417 418
    UINT i_factory_flags = 0;
#ifndef NDEBUG
    i_factory_flags |= DXGI_CREATE_FACTORY_DEBUG;
#endif

419
    /* TODO : detect the directx version supported and use IID_IDXGIFactory3 or 2 */
420
    HRESULT hr = OurCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&sys->dxgifactory);
421 422 423 424 425 426 427
    if (FAILED(hr)) {
        msg_Err(vd, "Could not create dxgi factory. (hr=0x%lX)", hr);
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }

    sys->OurD3D11CreateDeviceAndSwapChain =
428
        (void *)GetProcAddress(hd3d11_dll, "D3D11CreateDeviceAndSwapChain");
429 430 431 432 433 434 435 436
    if (!sys->OurD3D11CreateDeviceAndSwapChain) {
        msg_Err(vd, "Cannot locate reference to D3D11CreateDeviceAndSwapChain in d3d11 DLL");
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }

# else
    sys->OurD3D11CreateDevice =
437
        (void *)GetProcAddress(hd3d11_dll, "D3D11CreateDevice");
438 439 440 441 442 443
    if (!sys->OurD3D11CreateDevice) {
        msg_Err(vd, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }
# endif
444 445
    return VLC_SUCCESS;
}
446
#else
447 448
static int OpenCoreW(vout_display_t *vd)
{
449 450 451 452 453 454 455 456 457 458 459 460 461 462
    IDXGISwapChain1* dxgiswapChain  = var_InheritInteger(vd, "winrt-swapchain");
    if (!dxgiswapChain)
        return VLC_EGENERIC;
    ID3D11Device* d3ddevice         = var_InheritInteger(vd, "winrt-d3ddevice");
    if (!d3ddevice)
        return VLC_EGENERIC;
    ID3D11DeviceContext* d3dcontext = var_InheritInteger(vd, "winrt-d3dcontext");
    if (!d3dcontext)
        return VLC_EGENERIC;

    vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
    if (!sys)
        return VLC_ENOMEM;

463 464 465
    sys->dxgiswapChain = dxgiswapChain;
    sys->d3ddevice     = d3ddevice;
    sys->d3dcontext    = d3dcontext;
466 467 468
    IDXGISwapChain_AddRef     (sys->dxgiswapChain);
    ID3D11Device_AddRef       (sys->d3ddevice);
    ID3D11DeviceContext_AddRef(sys->d3dcontext);
469 470 471

    return VLC_SUCCESS;
}
472 473
#endif

474 475 476 477 478 479 480 481 482 483 484 485
static bool is_d3d11_opaque(vlc_fourcc_t chroma)
{
    switch (chroma)
    {
    case VLC_CODEC_D3D11_OPAQUE:
    case VLC_CODEC_D3D11_OPAQUE_10B:
        return true;
    default:
        return false;
    }
}

486 487 488 489 490 491 492 493 494 495 496 497 498
static int Open(vlc_object_t *object)
{
    vout_display_t *vd = (vout_display_t *)object;

#if !VLC_WINSTORE_APP
    int ret = OpenHwnd(vd);
#else
    int ret = OpenCoreW(vd);
#endif

    if (ret != VLC_SUCCESS)
        return ret;

Martell Malone's avatar
Martell Malone committed
499 500 501 502 503 504 505 506 507 508
    if (CommonInit(vd))
        goto error;

    video_format_t fmt;
    if (Direct3D11Open(vd, &fmt)) {
        msg_Err(vd, "Direct3D11 could not be opened");
        goto error;
    }

    vout_display_info_t info  = vd->info;
509
    info.is_slow              = !is_d3d11_opaque(fmt.i_chroma);
Martell Malone's avatar
Martell Malone committed
510 511 512
    info.has_double_click     = true;
    info.has_hide_mouse       = false;
    info.has_event_thread     = true;
513
    info.has_pictures_invalid = !is_d3d11_opaque(fmt.i_chroma);
Martell Malone's avatar
Martell Malone committed
514

515
    if (var_InheritBool(vd, "direct3d11-hw-blending") &&
516 517
        vd->sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
        info.subpicture_chromas = vd->sys->pSubpictureChromas;
518 519
    else
        info.subpicture_chromas = NULL;
Martell Malone's avatar
Martell Malone committed
520 521 522 523 524

    video_format_Clean(&vd->fmt);
    video_format_Copy(&vd->fmt, &fmt);
    vd->info = info;

525
    vd->pool    = Pool;
Martell Malone's avatar
Martell Malone committed
526 527
    vd->prepare = Prepare;
    vd->display = Display;
528
    vd->control = Control;
529
    vd->manage  = Manage;
Martell Malone's avatar
Martell Malone committed
530 531 532 533

    msg_Dbg(vd, "Direct3D11 Open Succeeded");

    return VLC_SUCCESS;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
534

Martell Malone's avatar
Martell Malone committed
535
error:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
536
    Close(object);
Martell Malone's avatar
Martell Malone committed
537 538 539 540 541 542 543 544 545 546 547 548 549
    return VLC_EGENERIC;
}

static void Close(vlc_object_t *object)
{
    vout_display_t * vd = (vout_display_t *)object;

    Direct3D11Close(vd);
    CommonClean(vd);
    Direct3D11Destroy(vd);
    free(vd->sys);
}

550 551 552 553 554
static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
{
    if ( vd->sys->pool != NULL )
        return vd->sys->pool;

555
#ifdef HAVE_ID3D11VIDEODECODER
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
    picture_t**       pictures = NULL;
    unsigned          picture_count = 0;
    HRESULT           hr;

    ID3D10Multithread *pMultithread;
    hr = ID3D11Device_QueryInterface( vd->sys->d3ddevice, &IID_ID3D10Multithread, (void **)&pMultithread);
    if (SUCCEEDED(hr)) {
        ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
        ID3D10Multithread_Release(pMultithread);
    }

    pictures = calloc(pool_size, sizeof(*pictures));
    if (!pictures)
        goto error;

    D3D11_TEXTURE2D_DESC texDesc;
    ZeroMemory(&texDesc, sizeof(texDesc));
    texDesc.Width = vd->fmt.i_width;
    texDesc.Height = vd->fmt.i_height;
    texDesc.MipLevels = 1;
    texDesc.Format = vd->sys->picQuadConfig.textureFormat;
    texDesc.SampleDesc.Count = 1;
    texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
579 580 581
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_DECODER;
    texDesc.CPUAccessFlags = 0;
582

583 584 585 586 587 588 589 590 591
    texDesc.ArraySize = pool_size;

    ID3D11Texture2D *texture;
    hr = ID3D11Device_CreateTexture2D( vd->sys->d3ddevice, &texDesc, NULL, &texture );
    if (FAILED(hr)) {
        msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
        goto error;
    }

592
    for (picture_count = 0; picture_count < pool_size; picture_count++) {
593 594 595 596
        picture_sys_t *picsys = calloc(1, sizeof(*picsys));
        if (unlikely(picsys == NULL))
            goto error;

597 598 599
        ID3D11Texture2D_AddRef(texture);
        picsys->texture = texture;
        picsys->slice_index = picture_count;
600 601 602 603 604 605 606 607 608 609
        picsys->context = vd->sys->d3dcontext;

        picture_resource_t resource = {
            .p_sys = picsys,
            .pf_destroy = DestroyDisplayPoolPicture,
        };

        picture_t *picture = picture_NewFromResource(&vd->fmt, &resource);
        if (unlikely(picture == NULL)) {
            free(picsys);
610
            msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
611 612 613
            goto error;
        }

614
        pictures[picture_count] = picture;
615 616 617
        /* each picture_t holds a ref to the context and release it on Destroy */
        ID3D11DeviceContext_AddRef(picsys->context);
    }
618 619 620 621
    ID3D11Texture2D_Release(texture);

    msg_Dbg(vd, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d) texture 0x%p context 0x%p",
            pool_size, vd->fmt.i_width, vd->fmt.i_height, texture, vd->sys->d3dcontext);
622 623 624 625 626 627 628 629 630 631

    picture_pool_configuration_t pool_cfg;
    memset(&pool_cfg, 0, sizeof(pool_cfg));
    pool_cfg.picture_count = pool_size;
    pool_cfg.picture       = pictures;

    vd->sys->pool = picture_pool_NewExtended( &pool_cfg );

error:
    if (vd->sys->pool ==NULL && pictures) {
632
        msg_Dbg(vd, "Failed to create the picture d3d11 pool");
633 634 635
        for (unsigned i=0;i<picture_count; ++i)
            DestroyDisplayPoolPicture(pictures[i]);
        free(pictures);
636 637 638 639 640 641 642

        /* create an empty pool to avoid crashing */
        picture_pool_configuration_t pool_cfg;
        memset( &pool_cfg, 0, sizeof( pool_cfg ) );
        pool_cfg.picture_count = 0;

        vd->sys->pool = picture_pool_NewExtended( &pool_cfg );
643
    }
644
#endif
645 646 647
    return vd->sys->pool;
}

648
#ifdef HAVE_ID3D11VIDEODECODER
649 650 651 652 653 654
static void DestroyDisplayPoolPicture(picture_t *picture)
{
    picture_sys_t *p_sys = (picture_sys_t*) picture->p_sys;

    if (p_sys->texture)
        ID3D11Texture2D_Release(p_sys->texture);
655 656
    if (p_sys->context)
        ID3D11DeviceContext_Release(p_sys->context);
657 658 659 660

    free(p_sys);
    free(picture);
}
661
#endif
662 663 664 665 666 667 668 669 670 671 672 673

static void DestroyDisplayPicture(picture_t *picture)
{
    picture_sys_pool_t *p_sys = (picture_sys_pool_t*) picture->p_sys;

    if (p_sys->texture)
        ID3D11Texture2D_Release(p_sys->texture);

    free(p_sys);
    free(picture);
}

674 675 676 677 678 679
static HRESULT UpdateBackBuffer(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;
    ID3D11Texture2D* pDepthStencil;
    ID3D11Texture2D* pBackBuffer;
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
    uint32_t i_width  = RECTWidth(sys->rect_dest_clipped);
    uint32_t i_height = RECTHeight(sys->rect_dest_clipped);
#if VLC_WINSTORE_APP
    UINT dataSize = sizeof(i_width);
    hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, &i_width);
    if (FAILED(hr)) {
        msg_Err(vd, "Can't get swapchain width, size %d. (hr=0x%lX)", hr, dataSize);
        return hr;
    }
    dataSize = sizeof(i_height);
    hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, &i_height);
    if (FAILED(hr)) {
        msg_Err(vd, "Can't get swapchain height, size %d. (hr=0x%lX)", hr, dataSize);
        return hr;
    }
#endif
696 697 698 699 700 701 702 703 704 705

    if (sys->d3drenderTargetView) {
        ID3D11RenderTargetView_Release(sys->d3drenderTargetView);
        sys->d3drenderTargetView = NULL;
    }
    if (sys->d3ddepthStencilView) {
        ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
        sys->d3ddepthStencilView = NULL;
    }

706 707
    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
        DXGI_FORMAT_UNKNOWN, 0);
708 709 710 711 712 713 714 715 716 717 718 719 720
    if (FAILED(hr)) {
       msg_Err(vd, "Failed to resize the backbuffer. (hr=0x%lX)", hr);
       return hr;
    }

    hr = IDXGISwapChain_GetBuffer(sys->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *)&pBackBuffer);
    if (FAILED(hr)) {
       msg_Err(vd, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr);
       return hr;
    }

    hr = ID3D11Device_CreateRenderTargetView(sys->d3ddevice, (ID3D11Resource *)pBackBuffer, NULL, &sys->d3drenderTargetView);
    ID3D11Texture2D_Release(pBackBuffer);
721 722 723 724
    if (FAILED(hr)) {
        msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
        return hr;
    }
725 726 727 728 729 730 731

    D3D11_TEXTURE2D_DESC deptTexDesc;
    memset(&deptTexDesc, 0,sizeof(deptTexDesc));
    deptTexDesc.ArraySize = 1;
    deptTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    deptTexDesc.CPUAccessFlags = 0;
    deptTexDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
732 733
    deptTexDesc.Width = i_width;
    deptTexDesc.Height = i_height;
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
    deptTexDesc.MipLevels = 1;
    deptTexDesc.MiscFlags = 0;
    deptTexDesc.SampleDesc.Count = 1;
    deptTexDesc.SampleDesc.Quality = 0;
    deptTexDesc.Usage = D3D11_USAGE_DEFAULT;

    hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &deptTexDesc, NULL, &pDepthStencil);
    if (FAILED(hr)) {
       msg_Err(vd, "Could not create the depth stencil texture. (hr=0x%lX)", hr);
       return hr;
    }

    D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc;
    memset(&depthViewDesc, 0, sizeof(depthViewDesc));

    depthViewDesc.Format = deptTexDesc.Format;
    depthViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    depthViewDesc.Texture2D.MipSlice = 0;

    hr = ID3D11Device_CreateDepthStencilView(sys->d3ddevice, (ID3D11Resource *)pDepthStencil, &depthViewDesc, &sys->d3ddepthStencilView);
    ID3D11Texture2D_Release(pDepthStencil);

    if (FAILED(hr)) {
       msg_Err(vd, "Could not create the depth stencil view. (hr=0x%lX)", hr);
       return hr;
    }

    return S_OK;
}

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
static void CropStagingFormat(vout_display_t *vd, video_format_t *backup_fmt)
{
    if ( vd->sys->stagingQuad.pTexture == NULL )
        return;

    video_format_Copy( backup_fmt, &vd->source );
    /* the texture we display is a cropped version of the source */
    vd->source.i_x_offset = 0;
    vd->source.i_y_offset = 0;
    vd->source.i_width  = vd->source.i_visible_width;
    vd->source.i_height = vd->source.i_visible_height;
}

static void UncropStagingFormat(vout_display_t *vd, video_format_t *backup_fmt)
{
    if ( vd->sys->stagingQuad.pTexture == NULL )
        return;
    video_format_Copy( &vd->source, backup_fmt );
}

static int Control(vout_display_t *vd, int query, va_list args)
{
    video_format_t core_source;
    CropStagingFormat( vd, &core_source );
    int res = CommonControl( vd, query, args );
    UncropStagingFormat( vd, &core_source );
    return res;
}

793 794 795 796 797
static void Manage(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    RECT size_before = sys->rect_dest_clipped;

798 799
    video_format_t core_source;
    CropStagingFormat( vd, &core_source );
800 801 802 803 804
    CommonManage(vd);

    if (RECTWidth(size_before)  != RECTWidth(sys->rect_dest_clipped) ||
        RECTHeight(size_before) != RECTHeight(sys->rect_dest_clipped))
    {
805
#if defined(HAVE_ID3D11VIDEODECODER)
806
        if( sys->context_lock != INVALID_HANDLE_VALUE )
807 808 809 810
        {
            WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
        }
#endif
811 812 813 814
        msg_Dbg(vd, "Manage detected size change %dx%d", RECTWidth(sys->rect_dest_clipped),
                RECTHeight(sys->rect_dest_clipped));

        UpdateBackBuffer(vd);
815 816

        UpdatePicQuadPosition(vd);
817
#if defined(HAVE_ID3D11VIDEODECODER)
818
        if( sys->context_lock != INVALID_HANDLE_VALUE )
819 820 821 822
        {
            ReleaseMutex( sys->context_lock );
        }
#endif
823
    }
824
    UncropStagingFormat( vd, &core_source );
825 826
}

Martell Malone's avatar
Martell Malone committed
827 828 829
static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;
830

831
    if ( !is_d3d11_opaque(picture->format.i_chroma) &&
832 833 834 835 836 837
         sys->stagingQuad.pTexture != NULL )
    {
        Direct3D11UnmapTexture(picture);

        D3D11_BOX box;
        box.left   = picture->format.i_x_offset;
838
        /* box.right  = picture->format.i_x_offset + picture->format.i_visible_width; */
839
        box.top    = picture->format.i_y_offset;
840
        /* box.bottom = picture->format.i_y_offset + picture->format.i_visible_height; */
841 842 843
        box.back = 1;
        box.front = 0;

844 845 846 847 848
        D3D11_TEXTURE2D_DESC dstDesc;
        ID3D11Texture2D_GetDesc(sys->picQuad.pTexture, &dstDesc);
        box.bottom = box.top  + dstDesc.Height;
        box.right  = box.left + dstDesc.Width;

849 850 851 852 853 854 855
        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
                                                  (ID3D11Resource*) sys->picQuad.pTexture,
                                                  0, 0, 0, 0,
                                                  (ID3D11Resource*) sys->stagingQuad.pTexture,
                                                  0, &box);
    }

856
#ifdef HAVE_ID3D11VIDEODECODER
857
    if (is_d3d11_opaque(picture->format.i_chroma)) {
858
        if( sys->context_lock != INVALID_HANDLE_VALUE )
859 860 861
        {
            WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
        }
862
        D3D11_BOX box;
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
        picture_sys_t *p_sys = picture->p_sys;
        D3D11_TEXTURE2D_DESC texDesc;
        ID3D11Texture2D_GetDesc( p_sys->texture, &texDesc );
        if (texDesc.Format == DXGI_FORMAT_NV12 || texDesc.Format == DXGI_FORMAT_P010)
        {
            box.left   = (picture->format.i_x_offset + 1) & ~1;
            box.right  = (picture->format.i_x_offset + picture->format.i_visible_width) & ~1;
            box.top    = (picture->format.i_y_offset + 1) & ~1;
            box.bottom = (picture->format.i_y_offset + picture->format.i_visible_height) & ~1;
        }
        else
        {
            box.left   = picture->format.i_x_offset;
            box.right  = picture->format.i_x_offset + picture->format.i_visible_width;
            box.top    = picture->format.i_y_offset;
            box.bottom = picture->format.i_y_offset + picture->format.i_visible_height;
        }
880 881 882 883 884 885 886
        box.back = 1;
        box.front = 0;

        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
                                                  (ID3D11Resource*) sys->picQuad.pTexture,
                                                  0, 0, 0, 0,
                                                  (ID3D11Resource*) p_sys->texture,
887
                                                  p_sys->slice_index, &box);
888
    }
889
#endif
Martell Malone's avatar
Martell Malone committed
890

891 892 893 894 895 896 897 898
    if (subpicture) {
        int subpicture_region_count    = 0;
        picture_t **subpicture_regions = NULL;
        Direct3D11MapSubpicture(vd, &subpicture_region_count, &subpicture_regions, subpicture);
        Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
        sys->d3dregion_count = subpicture_region_count;
        sys->d3dregions      = subpicture_regions;
    }
899 900 901 902 903 904
}

static void DisplayD3DPicture(vout_display_sys_t *sys, d3d_quad_t *quad)
{
    UINT stride = sizeof(d3d_vertex_t);
    UINT offset = 0;
Martell Malone's avatar
Martell Malone committed
905 906

    /* Render the quad */
907
    ID3D11DeviceContext_RSSetViewports(sys->d3dcontext, 1, &quad->cropViewport);
908 909
    ID3D11DeviceContext_PSSetShader(sys->d3dcontext, quad->d3dpixelShader, NULL, 0);
    ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 0, 1, &quad->d3dresViewY);
Martell Malone's avatar
Martell Malone committed
910

911 912
    if( quad->d3dresViewUV )
        ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 1, 1, &quad->d3dresViewUV);
Martell Malone's avatar
Martell Malone committed
913

914
    ID3D11DeviceContext_IASetVertexBuffers(sys->d3dcontext, 0, 1, &quad->pVertexBuffer, &stride, &offset);
Martell Malone's avatar
Martell Malone committed
915 916 917 918 919 920 921
    ID3D11DeviceContext_DrawIndexed(sys->d3dcontext, 6, 0, 0);
}

static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;

922 923 924
    FLOAT blackRGBA[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext, sys->d3drenderTargetView, blackRGBA);

925 926
    /* no ID3D11Device operations should come here */

Steve Lhomme's avatar
Steve Lhomme committed
927 928 929 930
    ID3D11DeviceContext_OMSetRenderTargets(sys->d3dcontext, 1, &sys->d3drenderTargetView, sys->d3ddepthStencilView);

    ID3D11DeviceContext_ClearDepthStencilView(sys->d3dcontext, sys->d3ddepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

931
    if ( !is_d3d11_opaque(picture->format.i_chroma) &&
932
         sys->stagingQuad.pTexture == NULL )
933 934
        Direct3D11UnmapTexture(picture);

935 936 937
    /* Render the quad */
    DisplayD3DPicture(sys, &sys->picQuad);

938 939 940
    if (subpicture) {
        // draw the additional vertices
        for (int i = 0; i < sys->d3dregion_count; ++i) {
941 942
            if (sys->d3dregions[i])
                DisplayD3DPicture(sys, (d3d_quad_t *) sys->d3dregions[i]->p_sys);
943 944 945
        }
    }

946 947 948
    DXGI_PRESENT_PARAMETERS presentParams;
    memset(&presentParams, 0, sizeof(presentParams));
    HRESULT hr = IDXGISwapChain1_Present1(sys->dxgiswapChain, 0, 0, &presentParams);
949 950 951
    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
    {
        /* TODO device lost */
952
        msg_Dbg(vd, "SwapChain Present failed. (hr=0x%lX)", hr);
953
    }
954
#if defined(HAVE_ID3D11VIDEODECODER)
955
    if( is_d3d11_opaque(picture->format.i_chroma) && sys->context_lock != INVALID_HANDLE_VALUE) {
956 957 958
        ReleaseMutex( sys->context_lock );
    }
#endif
Martell Malone's avatar
Martell Malone committed
959 960 961 962 963 964 965 966 967 968 969 970 971

    picture_Release(picture);
    if (subpicture)
        subpicture_Delete(subpicture);

    CommonDisplay(vd);
}

static void Direct3D11Destroy(vout_display_t *vd)
{
#if !VLC_WINSTORE_APP
    vout_display_sys_t *sys = vd->sys;

972
# if USE_DXGI
Martell Malone's avatar
Martell Malone committed
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
    if (sys->hdxgi_dll)
        FreeLibrary(sys->hdxgi_dll);
# endif

    if (sys->hd3d11_dll)
        FreeLibrary(sys->hd3d11_dll);
    if (sys->hd3dcompiler_dll)
        FreeLibrary(sys->hd3dcompiler_dll);

    sys->OurD3D11CreateDevice = NULL;
    sys->OurD3D11CreateDeviceAndSwapChain = NULL;
    sys->OurD3DCompile = NULL;
    sys->hdxgi_dll = NULL;
    sys->hd3d11_dll = NULL;
    sys->hd3dcompiler_dll = NULL;
#else
    VLC_UNUSED(vd);
#endif
991
}
Martell Malone's avatar
Martell Malone committed
992

993 994 995 996 997 998 999 1000 1001 1002 1003 1004
#if !VLC_WINSTORE_APP
static HINSTANCE Direct3D11LoadShaderLibrary(void)
{
    HINSTANCE instance = NULL;
    /* d3dcompiler_47 is the latest on windows 8.1 */
    for (int i = 47; i > 41; --i) {
        TCHAR filename[19];
        _sntprintf(filename, 19, TEXT("D3DCOMPILER_%d.dll"), i);
        instance = LoadLibrary(filename);
        if (instance) break;
    }
    return instance;
Martell Malone's avatar
Martell Malone committed
1005
}
1006 1007
#endif

Martell Malone's avatar
Martell Malone committed
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018

static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
{
    vout_display_sys_t *sys = vd->sys;
    *fmt = vd->source;

#if !VLC_WINSTORE_APP

    UINT creationFlags = 0;
    HRESULT hr = S_OK;

1019
# if !defined(NDEBUG) && defined(_MSC_VER)
Martell Malone's avatar
Martell Malone committed
1020 1021 1022
    creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
# endif

1023
    DXGI_SWAP_CHAIN_DESC1 scd;
Martell Malone's avatar
Martell Malone committed
1024
    memset(&scd, 0, sizeof(scd));
1025
    scd.BufferCount = 2;
Martell Malone's avatar
Martell Malone committed
1026 1027 1028
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scd.SampleDesc.Count = 1;
    scd.SampleDesc.Quality = 0;
1029 1030
    scd.Width = fmt->i_visible_width;
    scd.Height = fmt->i_visible_height;
1031 1032 1033 1034 1035 1036 1037 1038 1039
    switch(fmt->i_chroma)
    {
    case VLC_CODEC_D3D11_OPAQUE_10B:
        scd.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
        break;
    default:
        scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; /* TODO: use DXGI_FORMAT_NV12 */
        break;
    }
1040 1041
    //scd.Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
    scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
Martell Malone's avatar
Martell Malone committed
1042

1043 1044 1045
    IDXGIAdapter *dxgiadapter;
    static const D3D_FEATURE_LEVEL featureLevels[] =
    {
1046 1047
        0xc000 /* D3D_FEATURE_LEVEL_12_1 */,
        0xc100 /* D3D_FEATURE_LEVEL_12_0 */,
1048 1049 1050 1051 1052 1053
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
1054
        D3D_FEATURE_LEVEL_9_1,
1055
    };
Martell Malone's avatar
Martell Malone committed
1056

1057
# if USE_DXGI
Martell Malone's avatar
Martell Malone committed
1058
    /* TODO : list adapters for the user to choose from */
1059
    hr = IDXGIFactory2_EnumAdapters(sys->dxgifactory, 0, &dxgiadapter);
Martell Malone's avatar
Martell Malone committed
1060 1061 1062 1063 1064 1065
    if (FAILED(hr)) {
       msg_Err(vd, "Could not create find factory. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

    IDXGIOutput* output;
1066
    hr = IDXGIAdapter_EnumOutputs(dxgiadapter, 0, &output);
Martell Malone's avatar
Martell Malone committed
1067 1068
    if (FAILED(hr)) {
       msg_Err(vd, "Could not Enumerate DXGI Outputs. (hr=0x%lX)", hr);
Steve Lhomme's avatar
Steve Lhomme committed
1069
       IDXGIAdapter_Release(dxgiadapter);
Martell Malone's avatar
Martell Malone committed
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
       return VLC_EGENERIC;
    }

    DXGI_MODE_DESC md;
    memset(&md, 0, sizeof(md));
    md.Width  = fmt->i_visible_width;
    md.Height = fmt->i_visible_height;
    md.Format = scd.BufferDesc.Format;
    md.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

    hr = IDXGIOutput_FindClosestMatchingMode(output, &md, &scd.BufferDesc, NULL);
    if (FAILED(hr)) {
       msg_Err(vd, "Failed to find a supported video mode. (hr=0x%lX)", hr);
Steve Lhomme's avatar
Steve Lhomme committed
1083
       IDXGIAdapter_Release(dxgiadapter);
Martell Malone's avatar
Martell Malone committed
1084 1085 1086 1087 1088 1089 1090
       return VLC_EGENERIC;
    }

    /* mode desc doesn't carry over the width and height*/
    scd.BufferDesc.Width = fmt->i_visible_width;
    scd.BufferDesc.Height = fmt->i_visible_height;

1091
    hr = D3D11CreateDeviceAndSwapChain(dxgiadapter,
Martell Malone's avatar
Martell Malone committed
1092 1093 1094
                    D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags,
                    featureLevels, ARRAYSIZE(featureLevels),
                    D3D11_SDK_VERSION, &scd, &sys->dxgiswapChain,
1095
                    &sys->d3ddevice, NULL, &sys->d3dcontext);
Steve Lhomme's avatar
Steve Lhomme committed
1096
    IDXGIAdapter_Release(dxgiadapter);
Martell Malone's avatar
Martell Malone committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
    if (FAILED(hr)) {
       msg_Err(vd, "Could not Create the D3D11 device and SwapChain. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

# else

    static const D3D_DRIVER_TYPE driverAttempts[] = {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
1107
#ifndef NDEBUG
Martell Malone's avatar
Martell Malone committed
1108
        D3D_DRIVER_TYPE_REFERENCE,
1109
#endif
Martell Malone's avatar
Martell Malone committed
1110 1111 1112
    };

    for (UINT driver = 0; driver < ARRAYSIZE(driverAttempts); driver++) {
1113
        D3D_FEATURE_LEVEL i_feature_level;
Martell Malone's avatar
Martell Malone committed
1114
        hr = D3D11CreateDevice(NULL, driverAttempts[driver], NULL, creationFlags,
1115 1116
                    featureLevels, 9, D3D11_SDK_VERSION,
                    &sys->d3ddevice, &i_feature_level, &sys->d3dcontext);
1117 1118
        if (SUCCEEDED(hr)) {
#ifndef NDEBUG
1119
            msg_Dbg(vd, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
1120
                    (void *)sys->d3ddevice, (void *)sys->d3dcontext,
1121
                    driverAttempts[driver], i_feature_level);
1122 1123 1124
#endif
            break;
        }
Martell Malone's avatar
Martell Malone committed
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
    }

    if (FAILED(hr)) {
       msg_Err(vd, "Could not Create the D3D11 device. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

    IDXGIDevice *pDXGIDevice = NULL;
    hr = ID3D11Device_QueryInterface(sys->d3ddevice, &IID_IDXGIDevice, (void **)&pDXGIDevice);
    if (FAILED(hr)) {
       msg_Err(vd, "Could not Query DXGI Interface. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

1139
    hr = IDXGIDevice_GetAdapter(pDXGIDevice, &dxgiadapter);
Steve Lhomme's avatar
Steve Lhomme committed
1140
    IDXGIAdapter_Release(pDXGIDevice);
Martell Malone's avatar
Martell Malone committed
1141 1142 1143 1144 1145
    if (FAILED(hr)) {
       msg_Err(vd, "Could not get the DXGI Adapter. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

1146
    hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&sys->dxgifactory);
Steve Lhomme's avatar
Steve Lhomme committed
1147
    IDXGIAdapter_Release(dxgiadapter);
Martell Malone's avatar
Martell Malone committed
1148 1149 1150 1151 1152
    if (FAILED(hr)) {
       msg_Err(vd, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

1153 1154 1155
    hr = IDXGIFactory2_CreateSwapChainForHwnd(sys->dxgifactory, (IUnknown *)sys->d3ddevice,
                                              sys->hvideownd, &scd, NULL, NULL, &sys->dxgiswapChain);
    IDXGIFactory2_Release(sys->dxgifactory);
Martell Malone's avatar
Martell Malone committed
1156 1157 1158 1159 1160 1161 1162 1163
    if (FAILED(hr)) {
       msg_Err(vd, "Could not create the SwapChain. (hr=0x%lX)", hr);
       return VLC_EGENERIC;
    }

# endif
#endif

1164 1165 1166
    vlc_fourcc_t i_src_chroma = fmt->i_chroma;
    fmt->i_chroma = 0;

1167
    // look for the requested pixel format first
1168 1169
    UINT i_quadSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_LOAD;
    UINT i_formatSupport;
1170 1171
    for (const d3d_format_t *output_format = GetRenderFormatList();
         output_format->name != NULL; ++output_format)
1172
    {
1173
        if( i_src_chroma == output_format->fourcc )
1174
        {
1175
            if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1176
                                                           output_format->formatTexture,
1177
                                                           &i_formatSupport)) &&
1178
                    ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
1179
            {
1180 1181