direct3d11.c 101 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
    unsigned int              i_width;
    unsigned int              i_height;
104 105
} d3d_quad_t;

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
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;

121 122 123 124
struct vout_display_sys_t
{
    vout_display_sys_win32_t sys;

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

130 131 132 133 134 135 136 137 138 139 140 141 142 143
#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 */
144
    IDXGISwapChain4          *dxgiswapChain4;  /* DXGI 1.5 for HDR */
145 146 147
    ID3D11Device             *d3ddevice;       /* D3D device */
    ID3D11DeviceContext      *d3dcontext;      /* D3D context */
    d3d_quad_t               picQuad;
148
    const d3d_format_t       *picQuadConfig;
149
    ID3D11PixelShader        *picQuadPixelShader;
150

151
    DXGI_FORMAT              decoderFormat;
152 153
    picture_sys_t            stagingSys;

154 155 156 157 158 159
    ID3D11RenderTargetView   *d3drenderTargetView;
    ID3D11DepthStencilView   *d3ddepthStencilView;

    ID3D11VertexShader        *flatVSShader;
    ID3D11VertexShader        *projectionVSShader;

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

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

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

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

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

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

#define SPHERE_RADIUS 1.f

205 206
#define RECTWidth(r)   (int)((r).right - (r).left)
#define RECTHeight(r)  (int)((r).bottom - (r).top)
207

208 209
static picture_pool_t *Pool(vout_display_t *vd, unsigned count);

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

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

222 223 224
static void Direct3D11DestroyPool(vout_display_t *);

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

228
static int SetupQuad(vout_display_t *, const video_format_t *, d3d_quad_t *, const RECT *,
229 230
                     const d3d_format_t *, ID3D11PixelShader *, video_projection_mode_t,
                     video_orientation_t);
231
static bool UpdateQuadPosition( vout_display_t *vd, d3d_quad_t *quad,
232
                                const RECT *output,
233 234
                                video_projection_mode_t projection,
                                video_orientation_t orientation );
235
static void ReleaseQuad(d3d_quad_t *);
236
static void UpdatePicQuadPosition(vout_display_t *);
237

238
static int Control(vout_display_t *vd, int query, va_list args);
239 240
static void Manage(vout_display_t *vd);

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

261 262 263
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)

264 265 266 267 268 269 270 271 272
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
273 274 275
  struct VS_INPUT\
  {\
    float4 Position   : POSITION;\
276
    float4 Texture    : TEXCOORD0;\
Martell Malone's avatar
Martell Malone committed
277 278 279 280 281
  };\
  \
  struct VS_OUTPUT\
  {\
    float4 Position   : SV_POSITION;\
282
    float4 Texture    : TEXCOORD0;\
Martell Malone's avatar
Martell Malone committed
283 284
  };\
  \
285
  VS_OUTPUT main( VS_INPUT In )\
Martell Malone's avatar
Martell Malone committed
286 287
  {\
    VS_OUTPUT Output;\
288 289 290 291 292 293 294
    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
295 296 297 298 299 300
    Output.Texture = In.Texture;\
    return Output;\
  }\
";

static const char* globPixelShaderDefault = "\
301 302 303
  cbuffer PS_CONSTANT_BUFFER : register(b0)\
  {\
    float Opacity;\
Steve Lhomme's avatar
Steve Lhomme committed
304
    float opacityPadding[3];\
305
  };\
306 307
  cbuffer PS_COLOR_TRANSFORM : register(b1)\
  {\
308
    float4x4 WhitePoint;\
309
    float4x4 Colorspace;\
310
  };\
311
  Texture2D%s shaderTexture[" STRINGIZE(D3D11_MAX_SHADER_VIEW) "];\
Martell Malone's avatar
Martell Malone committed
312 313 314 315 316
  SamplerState SampleType;\
  \
  struct PS_INPUT\
  {\
    float4 Position   : SV_POSITION;\
317
    float4 Texture    : TEXCOORD0;\
Martell Malone's avatar
Martell Malone committed
318 319
  };\
  \
320 321 322 323 324 325 326 327 328 329 330 331 332
  /* 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;\
  }\
  \
333 334 335 336 337 338 339 340 341 342 343 344 345
  /* 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;\
  }\
  \
346 347 348 349 350 351 352 353 354 355 356 357
  inline float3 sourceToLinear(float3 rgb) {\
      %s;\
  }\
  \
  inline float3 linearToDisplay(float3 rgb) {\
      %s;\
  }\
  \
  inline float3 toneMapping(float3 rgb) {\
      %s;\
  }\
  \
358 359 360 361
  inline float3 adjustPeakLuminance(float3 rgb) {\
      %s;\
  }\
  \
362 363 364 365
  inline float3 adjustRange(float3 rgb) {\
      %s;\
  }\
  \
366
  float4 main( PS_INPUT In ) : SV_TARGET\
Martell Malone's avatar
Martell Malone committed
367
  {\
368
    float4 sample;\
369
    \
370
    %s /* sampling routine in sample */\
371
    float4 rgba = mul(mul(sample, WhitePoint), Colorspace);\
372
    float opacity = rgba.a * Opacity;\
373
    float3 rgb = (float3)rgba;\
374 375
    rgb = sourceToLinear(rgb);\
    rgb = toneMapping(rgb);\
376
    rgb = adjustPeakLuminance(rgb);\
377
    rgb = linearToDisplay(rgb);\
378 379
    rgb = adjustRange(rgb);\
    return float4(rgb, saturate(opacity));\
380 381 382
  }\
";

383 384 385 386 387 388
#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;"

389 390 391
#define DEFAULT_BRIGHTNESS 80


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

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

411
#if !VLC_WINSTORE_APP
412 413
static int OpenHwnd(vout_display_t *vd)
{
414 415 416 417 418 419
    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) {
420 421 422 423
        msg_Warn(vd, "cannot load d3d11.dll, aborting");
        return VLC_EGENERIC;
    }

424 425
    sys->hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
    if (!sys->hd3dcompiler_dll) {
426
        msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
427
        Direct3D11Destroy(vd);
428 429 430 431 432 433
        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
434 435 436 437
        Direct3D11Destroy(vd);
        return VLC_EGENERIC;
    }

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

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

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

    return VLC_SUCCESS;
}
474 475
#endif

476 477 478 479 480 481 482 483 484 485 486 487
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;
    }
}

488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
#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

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

528 529 530 531
#if VLC_WINSTORE_APP
    vd->sys->sys.pf_GetRect = GetRect;
#endif

Martell Malone's avatar
Martell Malone committed
532
    video_format_t fmt;
533
    video_format_Copy(&fmt, &vd->source);
Martell Malone's avatar
Martell Malone committed
534 535 536 537 538
    if (Direct3D11Open(vd, &fmt)) {
        msg_Err(vd, "Direct3D11 could not be opened");
        goto error;
    }

539
    video_format_Clean(&vd->fmt);
540
    vd->fmt = fmt;
541 542

    vd->info.has_double_click     = true;
543
    vd->info.has_pictures_invalid = vd->info.is_slow;
Martell Malone's avatar
Martell Malone committed
544

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

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

    msg_Dbg(vd, "Direct3D11 Open Succeeded");

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

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

580
static int AllocateTextures(vout_display_t *vd, const d3d_format_t *cfg,
581
                            video_format_t *fmt, unsigned pool_size,
582
                            ID3D11Texture2D *textures[],
583
                            bool pool_type_display)
584
{
585
    vout_display_sys_t *sys = vd->sys;
586 587 588 589 590 591 592 593 594
    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;
595 596
    texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    if (is_d3d11_opaque(fmt->i_chroma)) {
597 598 599 600 601 602 603
        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;
    }
604 605 606
    texDesc.ArraySize = pool_size;
    texDesc.Height = fmt->i_height;
    texDesc.Width = fmt->i_width;
607 608

    hr = ID3D11Device_CreateTexture2D( sys->d3ddevice, &texDesc, NULL, &slicedTexture );
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
    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]);
            }
        }
    }

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

        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;
        }
    }

646 647 648 649 650 651 652 653 654
    if (slicedTexture)
        ID3D11Texture2D_Release(slicedTexture);
    return VLC_SUCCESS;
error:
    if (slicedTexture)
        ID3D11Texture2D_Release(slicedTexture);
    return VLC_EGENERIC;
}

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

Steve Lhomme's avatar
Steve Lhomme committed
660
    vout_display_sys_t *sys = vd->sys;
661 662 663 664 665 666 667 668
    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
669
        return sys->sys.pool;
670

671 672
    if (vd->info.is_slow)
        pool_size = 1;
673

674
    video_format_t surface_fmt = vd->fmt;
675 676
    surface_fmt.i_width  = sys->picQuad.i_width;
    surface_fmt.i_height = sys->picQuad.i_height;
677

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

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

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

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

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

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

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

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

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

726
#ifdef HAVE_ID3D11VIDEODECODER
727
    if (!is_d3d11_opaque(surface_fmt.i_chroma) || sys->legacy_shader)
728 729
    {
        /* we need a staging texture */
730
        if (AllocateTextures(vd, sys->picQuadConfig, &surface_fmt, 1, textures, true))
731
            goto error;
732

733 734 735
        for (unsigned plane = 0; plane < D3D11_MAX_SHADER_VIEW; plane++)
            sys->stagingSys.texture[plane] = textures[plane];

736
        if (AllocateShaderView(VLC_OBJECT(vd), sys->d3ddevice, sys->picQuadConfig,
737
                               textures, 0, sys->stagingSys.resourceView))
738 739 740
            goto error;
    } else
#endif
741 742
    {
        for (picture_count = 0; picture_count < pool_size; picture_count++) {
743
            if (AllocateShaderView(VLC_OBJECT(vd), sys->d3ddevice, sys->picQuadConfig,
744
                                   pictures[picture_count]->p_sys->texture, picture_count,
745
                                   pictures[picture_count]->p_sys->resourceView))
746 747 748 749
                goto error;
        }
    }

750 751
    if (SetupQuad( vd, &surface_fmt, &sys->picQuad, &sys->sys.rect_src_clipped,
                   sys->picQuadConfig, sys->picQuadPixelShader,
752
                   surface_fmt.projection_mode, vd->fmt.orientation ) != VLC_SUCCESS) {
753 754
        msg_Err(vd, "Could not Create the main quad picture.");
        return NULL;
755 756 757 758 759 760 761
    }

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

error:
766 767 768 769 770 771 772
    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);
        }
773 774 775

        /* create an empty pool to avoid crashing */
        pool_cfg.picture_count = 0;
Steve Lhomme's avatar
Steve Lhomme committed
776
        sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
777
    } else {
Steve Lhomme's avatar
Steve Lhomme committed
778
        msg_Dbg(vd, "D3D11 pool succeed with %d surfaces (%dx%d) context 0x%p",
779
                picture_count, surface_fmt.i_width, surface_fmt.i_height, sys->d3dcontext);
780
    }
Steve Lhomme's avatar
Steve Lhomme committed
781
    return sys->sys.pool;
782 783
}

784 785
static void DestroyDisplayPoolPicture(picture_t *picture)
{
786
    picture_sys_t *p_sys = picture->p_sys;
787
    ReleasePictureSys( p_sys );
788
    free(p_sys);
789 790 791
    free(picture);
}

792 793 794 795 796 797
static HRESULT UpdateBackBuffer(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;
    ID3D11Texture2D* pDepthStencil;
    ID3D11Texture2D* pBackBuffer;
798
    RECT rect;
799
#if VLC_WINSTORE_APP
800
    if (!GetRect(&sys->sys, &rect))
801
#endif
802 803 804
        rect = sys->sys.rect_dest_clipped;
    uint32_t i_width = RECTWidth(rect);
    uint32_t i_height = RECTHeight(rect);
805 806 807 808 809 810 811 812 813 814

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

815
    /* TODO detect is the size is the same as the output and switch to fullscreen mode */
816 817
    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
        DXGI_FORMAT_UNKNOWN, 0);
818 819 820 821 822 823 824 825 826 827 828 829 830
    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);
831 832 833 834
    if (FAILED(hr)) {
        msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
        return hr;
    }
835 836 837 838 839 840 841

    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;
842 843
    deptTexDesc.Width = i_width;
    deptTexDesc.Height = i_height;
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
    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;
}

874 875 876 877 878 879 880 881 882 883 884 885 886 887 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
/* 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,
952
        0.f,     0.f,     (zNear + zFar) / (zNear - zFar), -1.f,
953 954 955 956 957
        0.f,     0.f, (2 * zNear * zFar) / (zNear - zFar),  0.f};

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

958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
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;
}

989 990
static void SetQuadVSProjection(vout_display_t *vd, d3d_quad_t *quad, const vlc_viewpoint_t *p_vp)
{
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    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);

1007 1008 1009 1010 1011 1012
    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;
1013 1014 1015 1016 1017
        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);
1018 1019
    }
    ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexShaderConstants, 0);
1020
#undef RAD
1021 1022
}

1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
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);
1038 1039 1040 1041

    UpdateQuadPosition(vd, &sys->picQuad, &sys->sys.rect_src_clipped,
                       vd->fmt.projection_mode, vd->fmt.orientation);

1042 1043 1044 1045 1046 1047 1048 1049
#if defined(HAVE_ID3D11VIDEODECODER)
    if( sys->context_lock != INVALID_HANDLE_VALUE )
    {
        ReleaseMutex( sys->context_lock );
    }
#endif
}

1050 1051 1052 1053 1054 1055
static inline bool RectEquals(const RECT *r1, const RECT *r2)
{
    return r1->bottom == r2->bottom && r1->top == r2->top &&
           r1->left == r2->left && r1->right == r2->right;
}

1056 1057 1058 1059 1060 1061 1062 1063 1064
#define BEFORE_UPDATE_RECTS \
    unsigned int i_outside_width  = vd->fmt.i_width; \
    unsigned int i_outside_height = vd->fmt.i_height; \
    vd->fmt.i_width  = vd->sys->picQuad.i_width; \
    vd->fmt.i_height = vd->sys->picQuad.i_height;
#define AFTER_UPDATE_RECTS \
    vd->fmt.i_width  = i_outside_width; \
    vd->fmt.i_height = i_outside_height;

1065 1066
static int Control(vout_display_t *vd, int query, va_list args)
{
1067
    vout_display_sys_t *sys = vd->sys;
1068 1069 1070
    RECT before_src_clipped  = sys->sys.rect_src_clipped;
    RECT before_dest_clipped = sys->sys.rect_dest_clipped;
    RECT before_dest         = sys->sys.rect_dest;
1071

1072
    BEFORE_UPDATE_RECTS;
1073
    int res = CommonControl( vd, query, args );
1074
    AFTER_UPDATE_RECTS;
1075 1076 1077 1078

    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
1079
        if ( sys->picQuad.pVertexShaderConstants )
1080
        {
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
1081
            SetQuadVSProjection( vd, &sys->picQuad, &cfg->viewpoint );
1082 1083 1084 1085
            res = VLC_SUCCESS;
        }
    }

1086 1087 1088
    if (!RectEquals(&before_src_clipped,  &sys->sys.rect_src_clipped) ||
        !RectEquals(&before_dest_clipped, &sys->sys.rect_dest_clipped) ||
        !RectEquals(&before_dest,         &sys->sys.rect_dest) )
1089 1090 1091 1092
    {
        UpdateSize(vd);
    }

1093 1094 1095
    return res;
}

1096 1097 1098
static void Manage(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
1099 1100 1101
    RECT before_src_clipped  = sys->sys.rect_src_clipped;
    RECT before_dest_clipped = sys->sys.rect_dest_clipped;
    RECT before_dest         = sys->sys.rect_dest;
1102

1103
    BEFORE_UPDATE_RECTS;
1104
    CommonManage(vd);
1105
    AFTER_UPDATE_RECTS;
1106

1107 1108 1109
    if (!RectEquals(&before_src_clipped, &sys->sys.rect_src_clipped) ||
        !RectEquals(&before_dest_clipped, &sys->sys.rect_dest_clipped) ||
        !RectEquals(&before_dest, &sys->sys.rect_dest))
1110
    {
1111
        UpdateSize(vd);
1112 1113 1114
    }
}

Martell Malone's avatar
Martell Malone committed
1115 1116 1117
static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;
1118

1119 1120 1121 1122
#if defined(HAVE_ID3D11VIDEODECODER)
    if( sys->context_lock != INVALID_HANDLE_VALUE )
        WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
#endif
1123
    picture_sys_t *p_sys = ActivePictureSys(picture);
1124 1125 1126 1127 1128 1129
    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 = {
1130 1131 1132 1133
            .top = 0,
            .bottom = picture->format.i_y_offset + picture->format.i_visible_height,
            .left = 0,
            .right = picture->format.i_x_offset + picture->format.i_visible_width,
1134 1135
            .back = 1,
        };
1136 1137 1138 1139 1140 1141 1142 1143
        if ( sys->picQuadConfig->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
             sys->picQuadConfig->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
        {
            box.bottom = (box.bottom + 0x01) & ~0x01;
            box.right  = (box.right  + 0x01) & ~0x01;
        }
        assert(box.right <= texDesc.Width);
        assert(box.bottom <= texDesc.Height);
1144
        ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
1145
                                                  sys->stagingSys.resource[KNOWN_DXGI_INDEX],
1146
                                                  0, 0, 0, 0,
1147
                                                  p_sys->resource[KNOWN_DXGI_INDEX],
1148
                                                  p_sys->slice_index, &box);
1149
    }
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
    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);
        }
1160

1161 1162
        if ( sys->picQuad.i_height != texDesc.Height ||
             sys->picQuad.i_width != texDesc.Width )
1163 1164 1165
        {
            /* the decoder produced different sizes than the vout, we need to
             * adjust the vertex */
1166 1167 1168 1169
            sys->picQuad.i_height = texDesc.Height;
            sys->picQuad.i_width = texDesc.Width;

            BEFORE_UPDATE_RECTS;
1170
            UpdateRects(vd, NULL, true);
1171
            AFTER_UPDATE_RECTS;
1172
            UpdateSize(vd);
1173
        }
1174
    }
Martell Malone's avatar
Martell Malone committed
1175

1176 1177 1178 1179 1180 1181 1182 1183
    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;
    }
1184 1185 1186 1187 1188 1189

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

1192
static void DisplayD3DPicture(vout_display_sys_t *sys, d3d_quad_t *quad, ID3D11ShaderResourceView *resourceView[D3D11_MAX_SHADER_VIEW])
1193 1194 1195
{
    UINT stride = sizeof(d3d_vertex_t);
    UINT offset = 0;
Martell Malone's avatar
Martell Malone committed
1196 1197

    /* Render the quad */
1198 1199 1200
    /* vertex shader */
    ID3D11DeviceContext_IASetVertexBuffers(sys->d3dcontext, 0, 1, &quad->pVertexBuffer, &stride, &offset);
    ID3D11DeviceContext_IASetIndexBuffer(sys->d3dcontext, quad->pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
1201 1202
    if ( quad->pVertexShaderConstants )
        ID3D11DeviceContext_VSSetConstantBuffers(sys->d3dcontext, 0, 1, &quad->pVertexShaderConstants);
1203 1204 1205 1206

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

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

1209
    ID3D11DeviceContext_PSSetConstantBuffers(sys->d3dcontext, 0, quad->PSConstantsCount, quad->pPixelShaderConstants);
1210
    ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 0, D3D11_MAX_SHADER_VIEW, resourceView);
Martell Malone's avatar
Martell Malone committed
1211

1212 1213
    ID3D11DeviceContext_RSSetViewports(sys->d3dcontext, 1, &quad->cropViewport);

1214
    ID3D11DeviceContext_DrawIndexed(sys->d3dcontext, quad->indexCount, 0, 0);
Martell Malone's avatar
Martell Malone committed
1215 1216 1217 1218 1219
}

static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
    vout_display_sys_t *sys = vd->sys;
1220 1221 1222 1223 1224 1225
#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
1226

1227 1228 1229
    FLOAT blackRGBA[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext, sys->d3drenderTargetView, blackRGBA);

1230 1231
    /* no ID3D11Device operations should come here */

1232 1233 1234 1235
    ID3D11DeviceContext_OMSetRenderTargets(sys->d3dcontext, 1, &sys->d3drenderTargetView, sys->d3ddepthStencilView);

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

1236
    /* Render the quad */
1237 1238
    if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader)
        DisplayD3DPicture(sys, &sys->picQuad, sys->stagingSys.resourceView);
1239
    else {
1240
        picture_sys_t *p_sys = ActivePictureSys(picture);
1241 1242
        DisplayD3DPicture(sys, &sys->picQuad, p_sys->resourceView);
    }
1243

1244 1245 1246
    if (subpicture) {
        // draw the additional vertices
        for (int i = 0; i < sys->d3dregion_count; ++i) {
1247
            if (sys->d3dregions[i])
1248 1249 1250 1251
            {
                d3d_quad_t *quad = (d3d_quad_t *) sys->d3dregions[i]->p_sys;
                DisplayD3DPicture(sys, quad, quad->picSys.resourceView);
            }
1252 1253 1254
        }
    }

1255 1256 1257 1258 1259 1260 1261
#if defined(HAVE_ID3D11VIDEODECODER)
    if (sys->context_lock != INVALID_HANDLE_VALUE && is_d3d11_opaque(picture->format.i_chroma))
    {
        ReleaseMutex( sys->context_lock );
    }
#endif

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
    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;
1275 1276
        hdr10.MaxContentLightLevel = picture->format.lighting.MaxCLL;
        hdr10.MaxFrameAverageLightLevel = picture->format.lighting.MaxFALL;