direct3d11.c 95.9 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
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_WIN7
25
# undef _WIN32_WINNT
26
# define _WIN32_WINNT _WIN32_WINNT_WIN7
27 28
#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
#include <assert.h>
38
#include <math.h>
39

Martell Malone's avatar
Martell Malone committed
40
#define COBJMACROS
41
#include <initguid.h>
Martell Malone's avatar
Martell Malone committed
42
#include <d3d11.h>
43
#include <dxgi1_5.h>
44
#include <d3dcompiler.h>
Martell Malone's avatar
Martell Malone committed
45 46 47 48

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

49
#include "../../video_chroma/d3d11_fmt.h"
50

51 52
#include "common.h"

Martell Malone's avatar
Martell Malone committed
53
#if !VLC_WINSTORE_APP
54
# define D3D11CreateDevice(args...)             sys->OurD3D11CreateDevice(args)
Martell Malone's avatar
Martell Malone committed
55 56 57
# define D3DCompile(args...)                    sys->OurD3DCompile(args)
#endif

58 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);

Martell Malone's avatar
Martell Malone committed
61 62 63 64
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")
65 66 67
#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
68 69 70 71 72 73 74

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)
75 76 77

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

78
#if VLC_WINSTORE_APP
79 80
    add_integer("winrt-d3dcontext",    0x0, NULL, NULL, true); /* ID3D11DeviceContext* */
    add_integer("winrt-swapchain",     0x0, NULL, NULL, true); /* IDXGISwapChain1*     */
81 82
#endif

Martell Malone's avatar
Martell Malone committed
83 84 85 86 87
    set_capability("vout display", 240)
    add_shortcut("direct3d11")
    set_callbacks(Open, Close)
vlc_module_end ()

88 89 90
/* A Quad is texture that can be displayed in a rectangle */
typedef struct
{
91
    picture_sys_t             picSys;
92 93 94 95 96 97 98 99 100 101
    ID3D11Buffer              *pVertexBuffer;
    UINT                      vertexCount;
    ID3D11VertexShader        *d3dvertexShader;
    ID3D11Buffer              *pIndexBuffer;
    UINT                      indexCount;
    ID3D11Buffer              *pVertexShaderConstants;
    ID3D11Buffer              *pPixelShaderConstants[2];
    UINT                       PSConstantsCount;
    ID3D11PixelShader         *d3dpixelShader;
    D3D11_VIEWPORT            cropViewport;
102 103 104 105
    unsigned int              i_x_offset;
    unsigned int              i_y_offset;
    unsigned int              i_width;
    unsigned int              i_height;
106 107
} d3d_quad_t;

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
typedef enum video_color_axis {
    COLOR_AXIS_RGB,
    COLOR_AXIS_YCBCR,
} video_color_axis;

typedef struct {
    DXGI_COLOR_SPACE_TYPE   dxgi;
    const char              *name;
    video_color_axis        axis;
    video_color_primaries_t primaries;
    video_transfer_func_t   transfer;
    video_color_space_t     color;
    bool                    b_full_range;
} dxgi_color_space;

123 124 125 126
struct vout_display_sys_t
{
    vout_display_sys_win32_t sys;

127 128
    struct { /* TODO may go in vout_display_info_t without DXGI */
        const dxgi_color_space   *colorspace;
129
        unsigned                 luminance_peak;
130
    } display;
131

132 133 134 135 136 137 138 139 140 141 142 143 144 145
#if !VLC_WINSTORE_APP
    HINSTANCE                hdxgi_dll;        /* handle of the opened dxgi dll */
    HINSTANCE                hd3d11_dll;       /* handle of the opened d3d11 dll */
    HINSTANCE                hd3dcompiler_dll; /* handle of the opened d3dcompiler dll */
    /* We should find a better way to store this or atleast a shorter name */
    PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN OurD3D11CreateDeviceAndSwapChain;
    PFN_D3D11_CREATE_DEVICE                OurD3D11CreateDevice;
    pD3DCompile                            OurD3DCompile;
#endif
#if defined(HAVE_ID3D11VIDEODECODER)
    HANDLE                   context_lock;     /* D3D11 Context lock necessary
                                                  for hw decoding */
#endif
    IDXGISwapChain1          *dxgiswapChain;   /* DXGI 1.1 swap chain */
146
    IDXGISwapChain4          *dxgiswapChain4;  /* DXGI 1.5 for HDR */
147 148 149
    ID3D11Device             *d3ddevice;       /* D3D device */
    ID3D11DeviceContext      *d3dcontext;      /* D3D context */
    d3d_quad_t               picQuad;
150
    const d3d_format_t       *picQuadConfig;
151
    ID3D11PixelShader        *picQuadPixelShader;
152

153
    DXGI_FORMAT              decoderFormat;
154 155
    picture_sys_t            stagingSys;

156 157 158 159 160 161
    ID3D11RenderTargetView   *d3drenderTargetView;
    ID3D11DepthStencilView   *d3ddepthStencilView;

    ID3D11VertexShader        *flatVSShader;
    ID3D11VertexShader        *projectionVSShader;

162 163 164 165
    /* copy from the decoder pool into picSquad before display
     * Uses a Texture2D with slices rather than a Texture2DArray for the decoder */
    bool                     legacy_shader;

166 167 168
    // SPU
    vlc_fourcc_t             pSubpictureChromas[2];
    ID3D11PixelShader        *pSPUPixelShader;
169
    const d3d_format_t       *d3dregion_format;
170 171 172 173
    int                      d3dregion_count;
    picture_t                **d3dregions;
};

174 175
/* matches the D3D11_INPUT_ELEMENT_DESC we setup */
typedef struct d3d_vertex_t {
176
    struct {
177 178 179 180 181 182 183
        FLOAT x;
        FLOAT y;
        FLOAT z;
    } position;
    struct {
        FLOAT x;
        FLOAT y;
184
    } texture;
185 186
} d3d_vertex_t;

187 188
typedef struct {
    FLOAT Opacity;
Steve Lhomme's avatar
Steve Lhomme committed
189
    FLOAT opacityPadding[3];
190 191
} PS_CONSTANT_BUFFER;

192
typedef struct {
193
    FLOAT WhitePoint[4*4];
194 195 196
    FLOAT Colorspace[4*4];
} PS_COLOR_TRANSFORM;

197
typedef struct {
Steve Lhomme's avatar
Steve Lhomme committed
198 199 200 201 202
    FLOAT RotX[4*4];
    FLOAT RotY[4*4];
    FLOAT RotZ[4*4];
    FLOAT View[4*4];
    FLOAT Projection[4*4];
203 204 205 206
} VS_PROJECTION_CONST;

#define SPHERE_RADIUS 1.f

207 208
#define RECTWidth(r)   (int)((r).right - (r).left)
#define RECTHeight(r)  (int)((r).bottom - (r).top)
209

210 211
static picture_pool_t *Pool(vout_display_t *vd, unsigned count);

Martell Malone's avatar
Martell Malone committed
212 213 214
static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);

215
static HINSTANCE Direct3D11LoadShaderLibrary(void);
Martell Malone's avatar
Martell Malone committed
216 217 218 219 220 221 222 223
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 *);

224 225 226
static void Direct3D11DestroyPool(vout_display_t *);

static void DestroyDisplayPoolPicture(picture_t *);
227 228
static void Direct3D11DeleteRegions(int, picture_t **);
static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
Martell Malone's avatar
Martell Malone committed
229

230 231
static int SetupQuad(vout_display_t *, const video_format_t *, d3d_quad_t *,
                     const d3d_format_t *, ID3D11PixelShader *, video_projection_mode_t);
232
static void ReleaseQuad(d3d_quad_t *);
233
static void UpdatePicQuadPosition(vout_display_t *);
234

235
static int Control(vout_display_t *vd, int query, va_list args);
236 237
static void Manage(vout_display_t *vd);

Martell Malone's avatar
Martell Malone committed
238
/* TODO: Move to a direct3d11_shaders header */
239
static const char* globVertexShaderFlat = "\
240 241 242
  struct VS_INPUT\
  {\
    float4 Position   : POSITION;\
243
    float4 Texture    : TEXCOORD0;\
244 245 246 247 248
  };\
  \
  struct VS_OUTPUT\
  {\
    float4 Position   : SV_POSITION;\
249
    float4 Texture    : TEXCOORD0;\
250 251
  };\
  \
252
  VS_OUTPUT main( VS_INPUT In )\
253 254 255 256 257
  {\
    return In;\
  }\
";

258 259 260
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)

261 262 263 264 265 266 267 268 269
static const char* globVertexShaderProjection = "\
  cbuffer VS_PROJECTION_CONST : register(b0)\
  {\
     float4x4 RotX;\
     float4x4 RotY;\
     float4x4 RotZ;\
     float4x4 View;\
     float4x4 Projection;\
  };\
Martell Malone's avatar
Martell Malone committed
270 271 272
  struct VS_INPUT\
  {\
    float4 Position   : POSITION;\
273
    float4 Texture    : TEXCOORD0;\
Martell Malone's avatar
Martell Malone committed
274 275 276 277 278
  };\
  \
  struct VS_OUTPUT\
  {\
    float4 Position   : SV_POSITION;\
279
    float4 Texture    : TEXCOORD0;\
Martell Malone's avatar
Martell Malone committed
280 281
  };\
  \
282
  VS_OUTPUT main( VS_INPUT In )\
Martell Malone's avatar
Martell Malone committed
283 284
  {\
    VS_OUTPUT Output;\
285 286 287 288 289 290 291
    float4 pos = In.Position;\
    pos = mul(RotY, pos);\
    pos = mul(RotX, pos);\
    pos = mul(RotZ, pos);\
    pos = mul(View, pos);\
    pos = mul(Projection, pos);\
    Output.Position = pos;\
Martell Malone's avatar
Martell Malone committed
292 293 294 295 296 297
    Output.Texture = In.Texture;\
    return Output;\
  }\
";

static const char* globPixelShaderDefault = "\
298 299 300
  cbuffer PS_CONSTANT_BUFFER : register(b0)\
  {\
    float Opacity;\
Steve Lhomme's avatar
Steve Lhomme committed
301
    float opacityPadding[3];\
302
  };\
303 304
  cbuffer PS_COLOR_TRANSFORM : register(b1)\
  {\
305
    float4x4 WhitePoint;\
306
    float4x4 Colorspace;\
307
  };\
308
  Texture2D%s shaderTexture[" STRINGIZE(D3D11_MAX_SHADER_VIEW) "];\
Martell Malone's avatar
Martell Malone committed
309 310 311 312 313
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
314
    float4 Texture    : TEXCOORD0;\
Martell Malone's avatar
Martell Malone committed
315 316
  };\
  \
317 318 319 320 321 322 323 324 325 326 327 328 329
  /* see http://filmicworlds.com/blog/filmic-tonemapping-operators/ */\
  inline float hable(float x) {\
      const float A = 0.15, B = 0.50, C = 0.10, D = 0.20, E = 0.02, F = 0.30;\
      return ((x * (A*x + (C*B))+(D*E))/(x * (A*x + B) + (D*F))) - E/F;\
  }\
  \
  inline float3 hable(float3 x) {\
      x.r = hable(x.r);\
      x.g = hable(x.g);\
      x.b = hable(x.b);\
      return x;\
  }\
  \
330 331 332 333 334 335 336 337 338 339 340 341 342
  /* https://en.wikipedia.org/wiki/Hybrid_Log-Gamma#Technical_details */\
  inline float inverse_HLG(float x){\
      const float B67_a = 0.17883277;\
      const float B67_b = 0.28466892;\
      const float B67_c = 0.55991073;\
      const float B67_inv_r2 = 4.0; /* 1/0.5² */\
      if (x <= 0.5)\
          x = x * x * B67_inv_r2;\
      else\
          x = exp((x - B67_c) / B67_a) + B67_b;\
      return x;\
  }\
  \
343 344 345 346 347 348 349 350 351 352 353 354
  inline float3 sourceToLinear(float3 rgb) {\
      %s;\
  }\
  \
  inline float3 linearToDisplay(float3 rgb) {\
      %s;\
  }\
  \
  inline float3 toneMapping(float3 rgb) {\
      %s;\
  }\
  \
355 356 357 358
  inline float3 adjustPeakLuminance(float3 rgb) {\
      %s;\
  }\
  \
359 360 361 362
  inline float3 adjustRange(float3 rgb) {\
      %s;\
  }\
  \
363
  float4 main( PS_INPUT In ) : SV_TARGET\
Martell Malone's avatar
Martell Malone committed
364
  {\
365
    float4 sample;\
366
    \
367
    %s /* sampling routine in sample */\
368
    float4 rgba = mul(mul(sample, WhitePoint), Colorspace);\
369
    float opacity = rgba.a * Opacity;\
370
    float3 rgb = (float3)rgba;\
371 372
    rgb = sourceToLinear(rgb);\
    rgb = toneMapping(rgb);\
373
    rgb = adjustPeakLuminance(rgb);\
374
    rgb = linearToDisplay(rgb);\
375 376
    rgb = adjustRange(rgb);\
    return float4(rgb, saturate(opacity));\
377 378 379
  }\
";

380 381 382 383 384 385
#define ST2084_PQ_CONSTANTS  "const float ST2084_m1 = 2610.0 / (4096.0 * 4);\
const float ST2084_m2 = (2523.0 / 4096.0) * 128.0;\
const float ST2084_c1 = 3424.0 / 4096.0;\
const float ST2084_c2 = (2413.0 / 4096.0) * 32.0;\
const float ST2084_c3 = (2392.0 / 4096.0) * 32.0;"

386 387 388
#define DEFAULT_BRIGHTNESS 80


389 390
static int Direct3D11MapPoolTexture(picture_t *picture)
{
391
    picture_sys_t *p_sys = picture->p_sys;
392 393
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    HRESULT hr;
394
    hr = ID3D11DeviceContext_Map(p_sys->context, p_sys->resource[KNOWN_DXGI_INDEX], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
395 396 397 398 399 400 401 402 403
    if( FAILED(hr) )
    {
        return VLC_EGENERIC;
    }
    return CommonUpdatePicture(picture, NULL, mappedResource.pData, mappedResource.RowPitch);
}

static void Direct3D11UnmapPoolTexture(picture_t *picture)
{
404 405
    picture_sys_t *p_sys = picture->p_sys;
    ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[KNOWN_DXGI_INDEX], 0);
406 407
}

408
#if !VLC_WINSTORE_APP
409 410
static int OpenHwnd(vout_display_t *vd)
{
411 412 413 414 415 416
    vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
    if (!sys)
        return VLC_ENOMEM;

    sys->hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
    if (!sys->hd3d11_dll) {
417 418 419 420
        msg_Warn(vd, "cannot load d3d11.dll, aborting");
        return VLC_EGENERIC;
    }

421 422
    sys->hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
    if (!sys->hd3dcompiler_dll) {
423
        msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
424
        Direct3D11Destroy(vd);
425 426 427 428 429 430
        return VLC_EGENERIC;
    }

    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
431 432 433 434
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }

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

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

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

    return VLC_SUCCESS;
}
471 472
#endif

473 474 475 476 477 478 479 480 481 482 483 484
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;
    }
}

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
#if VLC_WINSTORE_APP
static bool GetRect(const vout_display_sys_win32_t *p_sys, RECT *out)
{
    const vout_display_sys_t *sys = (const vout_display_sys_t *)p_sys;
    out->left   = 0;
    out->top    = 0;
    uint32_t i_width;
    uint32_t i_height;
    UINT dataSize = sizeof(i_width);
    HRESULT hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, &i_width);
    if (FAILED(hr)) {
        return false;
    }
    dataSize = sizeof(i_height);
    hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, &i_height);
    if (FAILED(hr)) {
        return false;
    }
    out->right  = i_width;
    out->bottom = i_height;
    return true;
}
#endif

509 510 511 512 513 514 515 516 517 518 519 520 521
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
522 523 524
    if (CommonInit(vd))
        goto error;

525 526 527 528
#if VLC_WINSTORE_APP
    vd->sys->sys.pf_GetRect = GetRect;
#endif

Martell Malone's avatar
Martell Malone committed
529 530 531 532 533 534
    video_format_t fmt;
    if (Direct3D11Open(vd, &fmt)) {
        msg_Err(vd, "Direct3D11 could not be opened");
        goto error;
    }

535 536 537 538 539
    video_format_Clean(&vd->fmt);
    video_format_Copy(&vd->fmt, &fmt);

    vd->info.has_double_click     = true;
    vd->info.has_hide_mouse       = false;
540
    vd->info.has_pictures_invalid = vd->info.is_slow;
Martell Malone's avatar
Martell Malone committed
541

542
    if (var_InheritBool(vd, "direct3d11-hw-blending") &&
543 544 545 546
        vd->sys->d3dregion_format != NULL)
    {
        vd->sys->pSubpictureChromas[0] = vd->sys->d3dregion_format->fourcc;
        vd->sys->pSubpictureChromas[1] = 0;
547
        vd->info.subpicture_chromas = vd->sys->pSubpictureChromas;
548
    }
549
    else
550
        vd->info.subpicture_chromas = NULL;
Martell Malone's avatar
Martell Malone committed
551

552
    vd->pool    = Pool;
Martell Malone's avatar
Martell Malone committed
553 554
    vd->prepare = Prepare;
    vd->display = Display;
555
    vd->control = Control;
556
    vd->manage  = Manage;
Martell Malone's avatar
Martell Malone committed
557 558 559 560

    msg_Dbg(vd, "Direct3D11 Open Succeeded");

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

Martell Malone's avatar
Martell Malone committed
562
error:
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
563
    Close(object);
Martell Malone's avatar
Martell Malone committed
564 565 566 567 568 569 570 571 572 573 574 575 576
    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);
}

577
static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
578
                            video_format_t *fmt, unsigned pool_size,
579
                            ID3D11Texture2D *textures[],
580
                            bool pool_type_display)
581
{
582
    vout_display_sys_t *sys = vd->sys;
583 584 585 586 587 588 589 590 591
    int plane;
    HRESULT hr;
    ID3D11Texture2D *slicedTexture = NULL;
    D3D11_TEXTURE2D_DESC texDesc;
    ZeroMemory(&texDesc, sizeof(texDesc));
    texDesc.MipLevels = 1;
    texDesc.SampleDesc.Count = 1;
    texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
    texDesc.Format = cfg->formatTexture;
592 593
    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    if (is_d3d11_opaque(fmt->i_chroma)) {
594 595 596 597 598 599 600
        texDesc.BindFlags |= D3D11_BIND_DECODER;
        texDesc.Usage = D3D11_USAGE_DEFAULT;
        texDesc.CPUAccessFlags = 0;
    } else {
        texDesc.Usage = D3D11_USAGE_DYNAMIC;
        texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    }
601 602 603
    texDesc.ArraySize = pool_size;
    texDesc.Height = fmt->i_height;
    texDesc.Width = fmt->i_width;
604 605

    hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &slicedTexture );
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
    if (FAILED(hr)) {
        msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
        goto error;
    }

    for (unsigned picture_count = 0; picture_count < pool_size; picture_count++) {
        textures[picture_count * D3D11_MAX_SHADER_VIEW] = slicedTexture;
        ID3D11Texture2D_AddRef(slicedTexture);

        for (plane = 1; plane < D3D11_MAX_SHADER_VIEW; plane++) {
            if (!cfg->resourceFormat[plane])
                textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = NULL;
            else
            {
                textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = textures[picture_count * D3D11_MAX_SHADER_VIEW];
                ID3D11Texture2D_AddRef(textures[picture_count * D3D11_MAX_SHADER_VIEW + plane]);
            }
        }
    }

626 627
    if (!is_d3d11_opaque(fmt->i_chroma)) {
        D3D11_MAPPED_SUBRESOURCE mappedResource;
628
        const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
629 630 631 632 633 634 635 636 637 638 639 640 641 642

        hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource*)textures[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
        if( FAILED(hr) ) {
            msg_Err(vd, "The texture cannot be mapped. (hr=0x%lX)", hr);
            goto error;
        }
        ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource*)textures[0], 0);
        if (mappedResource.RowPitch < p_chroma_desc->pixel_size * texDesc.Width) {
            msg_Err( vd, "The texture row pitch is too small (%d instead of %d)", mappedResource.RowPitch,
                     p_chroma_desc->pixel_size * texDesc.Width );
            goto error;
        }
    }

643 644 645 646 647 648 649 650 651
    if (slicedTexture)
        ID3D11Texture2D_Release(slicedTexture);
    return VLC_SUCCESS;
error:
    if (slicedTexture)
        ID3D11Texture2D_Release(slicedTexture);
    return VLC_EGENERIC;
}

652 653
static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
{
654 655 656
    /* compensate for extra hardware decoding pulling extra pictures from our pool */
    pool_size += 2;

Steve Lhomme's avatar
Steve Lhomme committed
657
    vout_display_sys_t *sys = vd->sys;
658 659 660 661 662 663 664 665
    ID3D11Texture2D  *textures[pool_size * D3D11_MAX_SHADER_VIEW];
    picture_t **pictures = NULL;
    picture_t *picture;
    unsigned  plane;
    unsigned  picture_count = 0;
    picture_pool_configuration_t pool_cfg = {};

    if (sys->sys.pool)
Steve Lhomme's avatar
Steve Lhomme committed
666
        return sys->sys.pool;
667

668 669
    if (vd->info.is_slow)
        pool_size = 1;
670

671 672 673 674 675 676 677 678
    video_format_t surface_fmt = vd->fmt;
    if (is_d3d11_opaque(surface_fmt.i_chroma))
    {
        /* worst case scenario we need 128 alignment for HEVC */
        surface_fmt.i_width  = (surface_fmt.i_width  + 0x7F) & ~0x7F;
        surface_fmt.i_height = (surface_fmt.i_height + 0x7F) & ~0x7F;
    }

679
    if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, pool_size, textures,
680
                         true))
681 682
        goto error;

Steve Lhomme's avatar
Steve Lhomme committed
683
    if (!vd->info.is_slow) {
684 685 686 687 688 689 690
        HRESULT           hr;
        ID3D10Multithread *pMultithread;
        hr = ID3D11Device_QueryInterface( sys->d3ddevice, &IID_ID3D10Multithread, (void **)&pMultithread);
        if (SUCCEEDED(hr)) {
            ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
            ID3D10Multithread_Release(pMultithread);
        }
691 692 693 694 695 696
    }

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

697
    for (picture_count = 0; picture_count < pool_size; picture_count++) {
698 699 700 701
        picture_sys_t *picsys = calloc(1, sizeof(*picsys));
        if (unlikely(picsys == NULL))
            goto error;

702 703
        for (plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
            picsys->texture[plane] = textures[picture_count * D3D11_MAX_SHADER_VIEW + plane];
704

705
        picsys->slice_index = picture_count;
Steve Lhomme's avatar
Steve Lhomme committed
706
        picsys->formatTexture = sys->picQuadConfig->formatTexture;
707
        picsys->decoderFormat = sys->decoderFormat;
Steve Lhomme's avatar
Steve Lhomme committed
708
        picsys->context = sys->d3dcontext;
709 710 711 712 713 714

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

715
        picture = picture_NewFromResource(&surface_fmt, &resource);
716 717
        if (unlikely(picture == NULL)) {
            free(picsys);
718
            msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
719 720 721
            goto error;
        }

722
        pictures[picture_count] = picture;
723 724 725
        /* each picture_t holds a ref to the context and release it on Destroy */
        ID3D11DeviceContext_AddRef(picsys->context);
    }
726

727
#ifdef HAVE_ID3D11VIDEODECODER
728
    if (!is_d3d11_opaque(surface_fmt.i_chroma) || sys->legacy_shader)
729 730 731
    {
        /* we need a staging texture */
        video_format_t staging_fmt;
732
        video_format_Copy(&staging_fmt, &surface_fmt);
733 734
        staging_fmt.i_width = staging_fmt.i_visible_width;
        staging_fmt.i_height = staging_fmt.i_visible_height;
735
        if (AllocateTextures(vd, sys->picQuadConfig, &staging_fmt, 1, textures, true))
736
            goto error;
737

738 739 740 741 742
        sys->picQuad.i_x_offset = 0;
        sys->picQuad.i_y_offset = 0;
        sys->picQuad.i_width    = staging_fmt.i_width;
        sys->picQuad.i_height   = staging_fmt.i_height;

743 744 745
        for (unsigned plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
            sys->stagingSys.texture[plane] = textures[plane];

746
        if (AllocateShaderView(VLC_OBJECT(vd), sys->d3ddevice, sys->picQuadConfig,
747
                               textures, 0, sys->stagingSys.resourceView))
748 749 750
            goto error;
    } else
#endif
751
    {
752 753 754 755
        sys->picQuad.i_x_offset = surface_fmt.i_x_offset;
        sys->picQuad.i_y_offset = surface_fmt.i_y_offset;
        sys->picQuad.i_width    = surface_fmt.i_width;
        sys->picQuad.i_height   = surface_fmt.i_height;
756 757

        for (picture_count = 0; picture_count < pool_size; picture_count++) {
758
            if (AllocateShaderView(VLC_OBJECT(vd), sys->d3ddevice, sys->picQuadConfig,
759
                                   pictures[picture_count]->p_sys->texture, picture_count,
760
                                   pictures[picture_count]->p_sys->resourceView))
761 762 763 764
                goto error;
        }
    }

765 766
    if (SetupQuad( vd, &surface_fmt, &sys->picQuad, sys->picQuadConfig, sys->picQuadPixelShader,
                   surface_fmt.projection_mode) != VLC_SUCCESS) {
767 768
        msg_Err(vd, "Could not Create the main quad picture.");
        return NULL;
769 770 771 772 773 774 775
    }

    if (vd->info.is_slow) {
        pool_cfg.lock          = Direct3D11MapPoolTexture;
        //pool_cfg.unlock        = Direct3D11UnmapPoolTexture;
    }
    pool_cfg.picture       = pictures;
776
    pool_cfg.picture_count = pool_size;
Steve Lhomme's avatar
Steve Lhomme committed
777
    sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
778 779

error:
780 781 782 783 784 785 786
    if (sys->sys.pool == NULL) {
        if (pictures) {
            msg_Dbg(vd, "Failed to create the picture d3d11 pool");
            for (unsigned i=0;i<picture_count; ++i)
                picture_Release(pictures[i]);
            free(pictures);
        }
787 788 789

        /* create an empty pool to avoid crashing */
        pool_cfg.picture_count = 0;
Steve Lhomme's avatar
Steve Lhomme committed
790
        sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
791
    } else {
Steve Lhomme's avatar
Steve Lhomme committed
792
        msg_Dbg(vd, "D3D11 pool succeed with %d surfaces (%dx%d) context 0x%p",
793
                picture_count, surface_fmt.i_width, surface_fmt.i_height, sys->d3dcontext);
794
    }
Steve Lhomme's avatar
Steve Lhomme committed
795
    return sys->sys.pool;
796 797
}

798 799
static void DestroyDisplayPoolPicture(picture_t *picture)
{
800
    picture_sys_t *p_sys = picture->p_sys;
801
    ReleasePictureSys( p_sys );
802
    free(p_sys);
803 804 805
    free(picture);
}

806 807 808 809 810 811
static HRESULT UpdateBackBuffer(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;
    ID3D11Texture2D* pDepthStencil;
    ID3D11Texture2D* pBackBuffer;
812
    RECT rect;
813
#if VLC_WINSTORE_APP
814
    if (!GetRect(&sys->sys, &rect))
815
#endif
816 817 818
        rect = sys->sys.rect_dest_clipped;
    uint32_t i_width = RECTWidth(rect);
    uint32_t i_height = RECTHeight(rect);
819 820 821 822 823 824 825 826 827 828

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

829
    /* TODO detect is the size is the same as the output and switch to fullscreen mode */
830 831
    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
        DXGI_FORMAT_UNKNOWN, 0);
832 833 834 835 836 837 838 839 840 841 842 843 844
    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);
845 846 847 848
    if (FAILED(hr)) {
        msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
        return hr;
    }
849 850 851 852 853 854 855

    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;
856 857
    deptTexDesc.Width = i_width;
    deptTexDesc.Height = i_height;
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
    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;
}

888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
/* rotation around the Z axis */
static void getZRotMatrix(float theta, FLOAT matrix[static 16])
{
    float st, ct;

    sincosf(theta, &st, &ct);

    const FLOAT m[] = {
    /*  x    y    z    w */
        ct,  -st, 0.f, 0.f,
        st,  ct,  0.f, 0.f,
        0.f, 0.f, 1.f, 0.f,
        0.f, 0.f, 0.f, 1.f
    };

    memcpy(matrix, m, sizeof(m));
}

/* rotation around the Y axis */
static void getYRotMatrix(float theta, FLOAT matrix[static 16])
{
    float st, ct;

    sincosf(theta, &st, &ct);

    const FLOAT m[] = {
    /*  x    y    z    w */
        ct,  0.f, -st, 0.f,
        0.f, 1.f, 0.f, 0.f,
        st,  0.f, ct,  0.f,
        0.f, 0.f, 0.f, 1.f
    };

    memcpy(matrix, m, sizeof(m));
}

/* rotation around the X axis */
static void getXRotMatrix(float phi, FLOAT matrix[static 16])
{
    float sp, cp;

    sincosf(phi, &sp, &cp);

    const FLOAT m[] = {
    /*  x    y    z    w */
        1.f, 0.f, 0.f, 0.f,
        0.f, cp,  sp,  0.f,
        0.f, -sp, cp,  0.f,
        0.f, 0.f, 0.f, 1.f
    };

    memcpy(matrix, m, sizeof(m));
}

static void getZoomMatrix(float zoom, FLOAT matrix[static 16]) {

    const FLOAT m[] = {
        /* x   y     z     w */
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, zoom, 1.0f
    };

    memcpy(matrix, m, sizeof(m));
}

/* perspective matrix see https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml */
static void getProjectionMatrix(float sar, float fovy, FLOAT matrix[static 16]) {

    float zFar  = 1000;
    float zNear = 0.01;

    float f = 1.f / tanf(fovy / 2.f);

    const FLOAT m[] = {
        f / sar, 0.f,                   0.f,                0.f,
        0.f,     f,                     0.f,                0.f,
966
        0.f,     0.f,     (zNear + zFar) / (zNear - zFar), -1.f,
967 968 969 970 971
        0.f,     0.f, (2 * zNear * zFar) / (zNear - zFar),  0.f};

     memcpy(matrix, m, sizeof(m));
}

972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
static float UpdateFOVy(float f_fovx, float f_sar)
{
    return 2 * atanf(tanf(f_fovx / 2) / f_sar);
}

static float UpdateZ(float f_fovx, float f_fovy)
{
    /* Do trigonometry to calculate the minimal z value
     * that will allow us to zoom out without seeing the outside of the
     * sphere (black borders). */
    float tan_fovx_2 = tanf(f_fovx / 2);
    float tan_fovy_2 = tanf(f_fovy / 2);
    float z_min = - SPHERE_RADIUS / sinf(atanf(sqrtf(
                    tan_fovx_2 * tan_fovx_2 + tan_fovy_2 * tan_fovy_2)));

    /* The FOV value above which z is dynamically calculated. */
    const float z_thresh = 90.f;

    float f_z;
    if (f_fovx <= z_thresh * M_PI / 180)
        f_z = 0;
    else
    {
        float f = z_min / ((FIELD_OF_VIEW_DEGREES_MAX - z_thresh) * M_PI / 180);
        f_z = f * f_fovx - f * z_thresh * M_PI / 180;
        if (f_z < z_min)
            f_z = z_min;
    }
    return f_z;
}

1003 1004
static void SetQuadVSProjection(vout_display_t *vd, d3d_quad_t *quad, const vlc_viewpoint_t *p_vp)
{
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
    if (!quad->pVertexShaderConstants)
        return;

#define RAD(d) ((float) ((d) * M_PI / 180.f))
    float f_fovx = RAD(p_vp->fov);
    if ( f_fovx > FIELD_OF_VIEW_DEGREES_MAX * M_PI / 180 + 0.001f ||
         f_fovx < -0.001f )
        return;

    float f_sar = (float) vd->cfg->display.width / vd->cfg->display.height;
    float f_teta = RAD(p_vp->yaw) - (float) M_PI_2;
    float f_phi  = RAD(p_vp->pitch);
    float f_roll = RAD(p_vp->roll);
    float f_fovy = UpdateFOVy(f_fovx, f_sar);
    float f_z = UpdateZ(f_fovx, f_fovy);

1021 1022 1023 1024 1025 1026
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;
    D3D11_MAPPED_SUBRESOURCE mapped;
    hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pVertexShaderConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
    if (SUCCEEDED(hr)) {
        VS_PROJECTION_CONST *dst_data = mapped.pData;
1027 1028 1029 1030 1031
        getXRotMatrix(f_phi, dst_data->RotX);
        getYRotMatrix(f_teta,   dst_data->RotY);
        getZRotMatrix(f_roll,  dst_data->RotZ);
        getZoomMatrix(SPHERE_RADIUS * f_z, dst_data->View);
        getProjectionMatrix(f_sar, f_fovy, dst_data->Projection);
1032 1033
    }
    ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexShaderConstants, 0);
1034
#undef RAD
1035 1036
}

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
static void UpdateSize(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
#if defined(HAVE_ID3D11VIDEODECODER)
    if( sys->context_lock != INVALID_HANDLE_VALUE )
    {
        WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
    }
#endif
    msg_Dbg(vd, "Detected size change %dx%d", RECTWidth(sys->sys.rect_dest_clipped),
            RECTHeight(sys->sys.rect_dest_clipped));

    UpdateBackBuffer(vd);

    UpdatePicQuadPosition(vd);
#if defined(HAVE_ID3D11VIDEODECODER)
    if( sys->context_lock != INVALID_HANDLE_VALUE )
    {
        ReleaseMutex( sys->context_lock );
    }
#endif
}

1060 1061
static int Control(vout_display_t *vd, int query, va_list args)
{
1062 1063 1064
    vout_display_sys_t *sys = vd->sys;
    RECT size_before = sys->sys.rect_dest_clipped;

1065
    int res = CommonControl( vd, query, args );
1066 1067 1068 1069

    if (query == VOUT_DISPLAY_CHANGE_VIEWPOINT)
    {
        const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t*);
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
1070
        if ( sys->picQuad.pVertexShaderConstants )
1071
        {
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
1072
            SetQuadVSProjection( vd, &sys->picQuad, &cfg->viewpoint );
1073 1074 1075 1076
            res = VLC_SUCCESS;
        }
    }

1077 1078 1079 1080 1081 1082
    if (RECTWidth(size_before)  != RECTWidth(sys->sys.rect_dest_clipped) ||
        RECTHeight(size_before) != RECTHeight(sys->sys.rect_dest_clipped))
    {
        UpdateSize(vd);
    }

1083 1084 1085
    return res;
}

1086 1087 1088
static void Manage(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
1089
    RECT size_before = sys->sys.rect_dest_clipped;
1090 1091 1092

    CommonManage(vd);

1093 1094
    if (RECTWidth(size_before)  != RECTWidth(sys->sys.rect_dest_clipped) ||
        RECTHeight(size_before) != RECTHeight(sys->sys.rect_dest_clipped))
1095
    {
1096
        UpdateSize(vd);
1097 1098 1099
    }
}

Martell Malone's avatar
Martell Malone committed
1100 1101 1102
static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;
1103

1104 1105 1106 1107
#if defined(HAVE_ID3D11VIDEODECODER)
    if( sys->context_lock != INVALID_HANDLE_VALUE )
        WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
#endif
1108
    picture_sys_t *p_sys = ActivePictureSys(picture);
1109 1110 1111 1112 1113 1114
    if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader) {
        D3D11_TEXTURE2D_DESC texDesc;
        if (!is_d3d11_opaque(picture->format.i_chroma))
            Direct3D11UnmapPoolTexture(picture);
        ID3D11Texture2D_GetDesc(sys->stagingSys.texture[0], &texDesc);
        D3D11_BOX box = {
1115 1116 1117 1118
            .top = picture->format.i_y_offset,
            .bottom = picture->format.i_y_offset + texDesc.Height,
            .left = picture->format.i_x_offset,
            .right = picture->format.i_x_offset + texDesc.Width,
1119 1120
            .back = 1,
        };
1121
        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
1122
                                                  sys->stagingSys.resource[KNOWN_DXGI_INDEX],
1123
                                                  0, 0, 0, 0,
1124
                                                  p_sys->resource[KNOWN_DXGI_INDEX],
1125
                                                  p_sys->slice_index, &box);
1126
    }
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
    else
    {
        D3D11_TEXTURE2D_DESC texDesc;
        ID3D11Texture2D_GetDesc(p_sys->texture[0], &texDesc);
        if (texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
        {
            /* for performance reason we don't want to allocate this during
             * display, do it preferrably when creating the texture */
            assert(p_sys->resourceView[0]!=NULL);
        }
    }
Martell Malone's avatar
Martell Malone committed
1138

1139 1140 1141 1142 1143 1144 1145 1146
    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;
    }
1147 1148 1149 1150 1151 1152

    ID3D11DeviceContext_Flush(sys->d3dcontext);
#if defined(HAVE_ID3D11VIDEODECODER)
    if ( sys->context_lock != INVALID_HANDLE_VALUE)
        ReleaseMutex( sys->context_lock );
#endif
1153 1154
}

1155
static void DisplayD3DPicture(vout_display_sys_t *sys, d3d_quad_t *quad, ID3D11ShaderResourceView *resourceView[D3D11_MAX_SHADER_VIEW])
1156 1157 1158
{
    UINT stride = sizeof(d3d_vertex_t);
    UINT offset = 0;
Martell Malone's avatar
Martell Malone committed
1159 1160

    /* Render the quad */
1161 1162 1163
    /* vertex shader */
    ID3D11DeviceContext_IASetVertexBuffers(sys->d3dcontext, 0, 1, &quad->pVertexBuffer, &stride, &offset);
    ID3D11DeviceContext_IASetIndexBuffer(sys->d3dcontext, quad->pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
1164 1165
    if ( quad->pVertexShaderConstants )
        ID3D11DeviceContext_VSSetConstantBuffers(sys->d3dcontext, 0, 1, &quad->pVertexShaderConstants);
1166 1167 1168 1169

    ID3D11DeviceContext_VSSetShader(sys->d3dcontext, quad->d3dvertexShader, NULL, 0);

    /* pixel shader */
1170
    ID3D11DeviceContext_PSSetShader(sys->d3dcontext, quad->d3dpixelShader, NULL, 0);
1171

1172
    ID3D11DeviceContext_PSSetConstantBuffers(sys->d3dcontext, 0, quad->PSConstantsCount, quad->pPixelShaderConstants);
1173
    ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 0, D3D11_MAX_SHADER_VIEW, resourceView);
Martell Malone's avatar
Martell Malone committed
1174

1175 1176
    ID3D11DeviceContext_RSSetViewports(sys->d3dcontext, 1, &quad->cropViewport);

1177
    ID3D11DeviceContext_DrawIndexed(sys->d3dcontext, quad->indexCount, 0, 0);
Martell Malone's avatar
Martell Malone committed
1178 1179 1180 1181 1182
}

static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;
1183 1184 1185 1186 1187 1188
#ifdef HAVE_ID3D11VIDEODECODER
    if (sys->context_lock != INVALID_HANDLE_VALUE && is_d3d11_opaque(picture->format.i_chroma))
    {
        WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
    }
#endif
Martell Malone's avatar
Martell Malone committed
1189

1190 1191 1192
    FLOAT blackRGBA[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext, sys->d3drenderTargetView, blackRGBA);

1193 1194
    /* no ID3D11Device operations should come here */

Steve Lhomme's avatar
Steve Lhomme committed
1195 1196 1197 1198
    ID3D11DeviceContext_OMSetRenderTargets(sys->d3dcontext, 1, &sys->d3drenderTargetView, sys->d3ddepthStencilView);

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

1199
    /* Render the quad */
1200 1201
    if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader)
        DisplayD3DPicture(sys, &sys->picQuad, sys->stagingSys.resourceView);
1202
    else {
1203
        picture_sys_t *p_sys = ActivePictureSys(picture);
1204 1205
        DisplayD3DPicture(sys, &sys->picQuad, p_sys->resourceView);
    }
1206

1207 1208 1209
    if (subpicture) {
        // draw the additional vertices
        for (int i = 0; i < sys->d3dregion_count; ++i) {
1210
            if (sys->d3dregions[i])
1211 1212 1213 1214
            {
                d3d_quad_t *quad = (d3d_quad_t *) sys->d3dregions[i]->p_sys;
                DisplayD3DPicture(sys, quad, quad->picSys.resourceView);
            }
1215 1216 1217
        }
    }

1218 1219 1220 1221 1222 1223 1224
#if defined(HAVE_ID3D11VIDEODECODER)
    if (sys->context_lock != INVALID_HANDLE_VALUE && is_d3d11_opaque(picture->format.i_chroma))
    {
        ReleaseMutex( sys->context_lock );
    }
#endif

1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
    if (sys->dxgiswapChain4 && picture->format.mastering.max_luminance)
    {
        DXGI_HDR_METADATA_HDR10 hdr10 = {0};
        hdr10.GreenPrimary[0] = picture->format.mastering.primaries[0];
        hdr10.GreenPrimary[1] = picture->format.mastering.primaries[1];
        hdr10.BluePrimary[0]  = picture->format.mastering.primaries[2];
        hdr10.BluePrimary[1]  = picture->format.mastering.primaries[3];
        hdr10.RedPrimary[0]   = picture->format.mastering.primaries[4];
        hdr10.RedPrimary[1]   = picture->format.mastering.primaries[5];
        hdr10.WhitePoint[0] = picture->format.mastering.white_point[0];
        hdr10.WhitePoint[1] = picture->format.mastering.white_point[1];
        hdr10.MinMasteringLuminance = picture->format.mastering.min_luminance;
        hdr10.MaxMasteringLuminance = picture->format.mastering.max_luminance;
1238 1239
        hdr10.MaxContentLightLevel = picture->format.lighting.MaxCLL;
        hdr10.MaxFrameAverageLightLevel = picture->format.lighting.MaxFALL;
1240 1241 1242 1243
        IDXGISwapChain4_SetHDRMetaData(sys->dxgiswapChain4, DXGI_HDR_METADATA_TYPE_HDR10, sizeof(hdr10), &hdr10);
    }


1244 1245 1246
    DXGI_PRESENT_PARAMETERS presentParams;
    memset(&presentParams, 0, sizeof(presentParams));
    HRESULT hr = IDXGISwapChain1_Present1(sys->dxgiswapChain, 0, 0, &presentParams);
1247 1248 1249
    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
    {
        /* TODO device lost */
1250
        msg_Dbg(vd, "SwapChain Present failed. (hr=0x%lX)", hr);
1251
    }
Martell Malone's avatar
Martell Malone committed
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278

    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;

    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
1279
}
Martell Malone's avatar
Martell Malone committed
1280

1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
#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
1293
}
1294 1295
#endif

1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
#define COLOR_RANGE_FULL   1 /* 0-255 */
#define COLOR_RANGE_STUDIO 0 /* 16-235 */

#define TRANSFER_FUNC_10    TRANSFER_FUNC_LINEAR
#define TRANSFER_FUNC_22    TRANSFER_FUNC_SRGB
#define TRANSFER_FUNC_2084  TRANSFER_FUNC_SMPTE_ST2084

#define COLOR_PRIMARIES_BT601  COLOR_PRIMARIES_BT601_525

static const dxgi_color_space color_spaces[] = {
#define DXGIMAP(AXIS, RANGE, GAMMA, SITTING, PRIMARIES) \
    { DXGI_COLOR_SPACE_##AXIS##_##RANGE##_G##GAMMA##_##SITTING##_P##PRIMARIES, \
      #AXIS " Rec." #PRIMARIES " gamma:" #GAMMA " range:" #RANGE, \
      COLOR_AXIS_##AXIS, COLOR_PRIMARIES_BT##PRIMARIES, TRANSFER_FUNC_##GAMMA, \
      COLOR_SPACE_BT##PRIMARIES, COLOR_RANGE_##RANGE},

    DXGIMAP(RGB,   FULL,     22,    NONE,   709)
    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,   601)
    DXGIMAP(YCBCR, FULL,     22,    LEFT,   601)
    DXGIMAP(RGB,   FULL,     10,    NONE,   709)
    DXGIMAP(RGB,   STUDIO,   22,    NONE,   709)
    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,   709)
    DXGIMAP(YCBCR, FULL,     22,    LEFT,   709)
    DXGIMAP(RGB,   STUDIO,   22,    NONE,  2020)
    DXGIMAP(YCBCR, STUDIO,   22,    LEFT,  2020)
    DXGIMAP(YCBCR, FULL,     22,    LEFT,  2020)
    DXGIMAP(YCBCR, STUDIO,   22, TOPLEFT,  2020)
    DXGIMAP(RGB,   FULL,     22,    NONE,  2020)
    DXGIMAP(RGB,   FULL,   2084,    NONE,  2020)
    DXGIMAP(YCBCR, STUDIO, 2084,    LEFT,  2020)
    DXGIMAP(RGB,   STUDIO, 2084,    NONE,  2020)
    DXGIMAP(YCBCR, STUDIO, 2084, TOPLEFT,  2020)
    /*DXGIMAP(YCBCR, FULL,     22,    NONE,  2020, 601)*/
    {DXGI_COLOR_SPACE_RESERVED, NULL, 0, 0, 0, 0, 0},
#undef DXGIMAP
};

static void D3D11SetColorSpace(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;
1337 1338
    int best = -1;
    int score, best_score = 0;
1339 1340
    UINT support;
    IDXGISwapChain3 *dxgiswapChain3 = NULL;
1341
    sys->display.colorspace = &color_spaces