1 /*****************************************************************************
2 * direct3d11.c: Windows Direct3D11 video output module
3 *****************************************************************************
4 * Copyright (C) 2014-2015 VLC authors and VideoLAN
6 * Authors: Martell Malone <martellmalone@gmail.com>
7 * Steve Lhomme <robux4@gmail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_WIN7
26 # define _WIN32_WINNT _WIN32_WINNT_WIN7
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout_display.h>
44 #include <d3dcompiler.h>
46 /* avoided until we can pass ISwapchainPanel without c++/cx mode
47 # include <windows.ui.xaml.media.dxinterop.h> */
49 #include "../../video_chroma/d3d11_fmt.h"
54 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
55 # define D3DCompile(args...) sys->OurD3DCompile(args)
58 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH
, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
59 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT
, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
61 static int Open(vlc_object_t
*);
62 static void Close(vlc_object_t
*);
64 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
65 #define HW_BLENDING_TEXT N_("Use hardware blending support")
66 #define HW_BLENDING_LONGTEXT N_(\
67 "Try to use hardware acceleration for subtitle/OSD blending.")
70 set_shortname("Direct3D11")
71 set_description(N_("Direct3D11 video output"))
73 set_category(CAT_VIDEO
)
74 set_subcategory(SUBCAT_VIDEO_VOUT
)
76 add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT
, HW_BLENDING_LONGTEXT
, true)
79 add_integer("winrt-d3dcontext", 0x0, NULL
, NULL
, true); /* ID3D11DeviceContext* */
80 add_integer("winrt-swapchain", 0x0, NULL
, NULL
, true); /* IDXGISwapChain1* */
83 set_capability("vout display", 300)
84 add_shortcut("direct3d11")
85 set_callbacks(Open
, Close
)
88 /* A Quad is texture that can be displayed in a rectangle */
92 ID3D11Buffer
*pVertexBuffer
;
94 ID3D11VertexShader
*d3dvertexShader
;
95 ID3D11Buffer
*pIndexBuffer
;
97 ID3D11Buffer
*pVertexShaderConstants
;
98 ID3D11Buffer
*pPixelShaderConstants
[2];
99 UINT PSConstantsCount
;
100 ID3D11PixelShader
*d3dpixelShader
;
101 D3D11_VIEWPORT cropViewport
;
102 const vlc_chroma_description_t
*p_chroma_sampling
;
103 unsigned int i_width
;
104 unsigned int i_height
;
107 typedef enum video_color_axis
{
113 DXGI_COLOR_SPACE_TYPE dxgi
;
115 video_color_axis axis
;
116 video_color_primaries_t primaries
;
117 video_transfer_func_t transfer
;
118 video_color_space_t color
;
122 struct vout_display_sys_t
124 vout_display_sys_win32_t sys
;
126 struct { /* TODO may go in vout_display_info_t without DXGI */
127 const dxgi_color_space
*colorspace
;
128 unsigned luminance_peak
;
131 #if !VLC_WINSTORE_APP
132 HINSTANCE hdxgi_dll
; /* handle of the opened dxgi dll */
133 HINSTANCE hd3d11_dll
; /* handle of the opened d3d11 dll */
134 HINSTANCE hd3dcompiler_dll
; /* handle of the opened d3dcompiler dll */
135 /* We should find a better way to store this or atleast a shorter name */
136 PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN OurD3D11CreateDeviceAndSwapChain
;
137 PFN_D3D11_CREATE_DEVICE OurD3D11CreateDevice
;
138 pD3DCompile OurD3DCompile
;
140 #if defined(HAVE_ID3D11VIDEODECODER)
141 HANDLE context_lock
; /* D3D11 Context lock necessary
144 IDXGISwapChain1
*dxgiswapChain
; /* DXGI 1.2 swap chain */
145 IDXGISwapChain4
*dxgiswapChain4
; /* DXGI 1.5 for HDR */
146 ID3D11Device
*d3ddevice
; /* D3D device */
147 ID3D11DeviceContext
*d3dcontext
; /* D3D context */
149 const d3d_format_t
*picQuadConfig
;
150 ID3D11PixelShader
*picQuadPixelShader
;
152 picture_sys_t stagingSys
;
154 ID3D11RenderTargetView
*d3drenderTargetView
;
155 ID3D11DepthStencilView
*d3ddepthStencilView
;
157 ID3D11VertexShader
*flatVSShader
;
158 ID3D11VertexShader
*projectionVSShader
;
160 /* copy from the decoder pool into picSquad before display
161 * Uses a Texture2D with slices rather than a Texture2DArray for the decoder */
165 vlc_fourcc_t pSubpictureChromas
[2];
166 ID3D11PixelShader
*pSPUPixelShader
;
167 const d3d_format_t
*d3dregion_format
;
169 picture_t
**d3dregions
;
172 /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
173 typedef struct d3d_vertex_t
{
187 FLOAT opacityPadding
[3];
188 } PS_CONSTANT_BUFFER
;
191 FLOAT WhitePoint
[4*4];
192 FLOAT Colorspace
[4*4];
193 } PS_COLOR_TRANSFORM
;
200 FLOAT Projection
[4*4];
201 } VS_PROJECTION_CONST
;
203 #define SPHERE_RADIUS 1.f
205 #define RECTWidth(r) (int)((r).right - (r).left)
206 #define RECTHeight(r) (int)((r).bottom - (r).top)
208 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
);
210 static void Prepare(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
211 static void Display(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
213 static HINSTANCE
Direct3D11LoadShaderLibrary(void);
214 static void Direct3D11Destroy(vout_display_t
*);
216 static int Direct3D11Open (vout_display_t
*, video_format_t
*);
217 static void Direct3D11Close(vout_display_t
*);
219 static int Direct3D11CreateResources (vout_display_t
*, video_format_t
*);
220 static void Direct3D11DestroyResources(vout_display_t
*);
222 static void Direct3D11DestroyPool(vout_display_t
*);
224 static void DestroyDisplayPoolPicture(picture_t
*);
225 static void Direct3D11DeleteRegions(int, picture_t
**);
226 static int Direct3D11MapSubpicture(vout_display_t
*, int *, picture_t
***, subpicture_t
*);
228 static int SetupQuad(vout_display_t
*, const video_format_t
*, d3d_quad_t
*, const RECT
*,
229 const d3d_format_t
*, ID3D11PixelShader
*, video_projection_mode_t
,
230 video_orientation_t
);
231 static bool UpdateQuadPosition( vout_display_t
*vd
, d3d_quad_t
*quad
,
233 video_projection_mode_t projection
,
234 video_orientation_t orientation
);
235 static void ReleaseQuad(d3d_quad_t
*);
236 static void UpdatePicQuadPosition(vout_display_t
*);
238 static int Control(vout_display_t
*vd
, int query
, va_list args
);
239 static void Manage(vout_display_t
*vd
);
241 /* TODO: Move to a direct3d11_shaders header */
242 static const char* globVertexShaderFlat
= "\
245 float4 Position : POSITION;\
246 float4 Texture : TEXCOORD0;\
251 float4 Position : SV_POSITION;\
252 float4 Texture : TEXCOORD0;\
255 VS_OUTPUT main( VS_INPUT In )\
261 #define STRINGIZE2(s) #s
262 #define STRINGIZE(s) STRINGIZE2(s)
264 static const char* globVertexShaderProjection
= "\
265 cbuffer VS_PROJECTION_CONST : register(b0)\
271 float4x4 Projection;\
275 float4 Position : POSITION;\
276 float4 Texture : TEXCOORD0;\
281 float4 Position : SV_POSITION;\
282 float4 Texture : TEXCOORD0;\
285 VS_OUTPUT main( VS_INPUT In )\
288 float4 pos = In.Position;\
289 pos = mul(RotY, pos);\
290 pos = mul(RotX, pos);\
291 pos = mul(RotZ, pos);\
292 pos = mul(View, pos);\
293 pos = mul(Projection, pos);\
294 Output.Position = pos;\
295 Output.Texture = In.Texture;\
300 static const char* globPixelShaderDefault
= "\
301 cbuffer PS_CONSTANT_BUFFER : register(b0)\
304 float opacityPadding[3];\
306 cbuffer PS_COLOR_TRANSFORM : register(b1)\
308 float4x4 WhitePoint;\
309 float4x4 Colorspace;\
311 Texture2D%s shaderTexture[" STRINGIZE(D3D11_MAX_SHADER_VIEW
) "];\
312 SamplerState SampleType;\
316 float4 Position : SV_POSITION;\
317 float4 Texture : TEXCOORD0;\
320 /* see http://filmicworlds.com/blog/filmic-tonemapping-operators/ */\
321 inline float hable(float x) {\
322 const float A = 0.15, B = 0.50, C = 0.10, D = 0.20, E = 0.02, F = 0.30;\
323 return ((x * (A*x + (C*B))+(D*E))/(x * (A*x + B) + (D*F))) - E/F;\
326 inline float3 hable(float3 x) {\
333 /* https://en.wikipedia.org/wiki/Hybrid_Log-Gamma#Technical_details */\
334 inline float inverse_HLG(float x){\
335 const float B67_a = 0.17883277;\
336 const float B67_b = 0.28466892;\
337 const float B67_c = 0.55991073;\
338 const float B67_inv_r2 = 4.0; /* 1/0.5² */\
340 x = x * x * B67_inv_r2;\
342 x = exp((x - B67_c) / B67_a) + B67_b;\
346 inline float3 sourceToLinear(float3 rgb) {\
350 inline float3 linearToDisplay(float3 rgb) {\
354 inline float3 toneMapping(float3 rgb) {\
358 inline float3 adjustPeakLuminance(float3 rgb) {\
362 inline float3 adjustRange(float3 rgb) {\
366 float4 main( PS_INPUT In ) : SV_TARGET\
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 rgb = sourceToLinear(rgb);\
375 rgb = toneMapping(rgb);\
376 rgb = adjustPeakLuminance(rgb);\
377 rgb = linearToDisplay(rgb);\
378 rgb = adjustRange(rgb);\
379 return float4(rgb, saturate(opacity));\
383 #define ST2084_PQ_CONSTANTS "const float ST2084_m1 = 2610.0 / (4096.0 * 4);\
384 const float ST2084_m2 = (2523.0 / 4096.0) * 128.0;\
385 const float ST2084_c1 = 3424.0 / 4096.0;\
386 const float ST2084_c2 = (2413.0 / 4096.0) * 32.0;\
387 const float ST2084_c3 = (2392.0 / 4096.0) * 32.0;"
389 #define DEFAULT_BRIGHTNESS 80
392 static int Direct3D11MapPoolTexture(picture_t
*picture
)
394 picture_sys_t
*p_sys
= picture
->p_sys
;
395 D3D11_MAPPED_SUBRESOURCE mappedResource
;
397 hr
= ID3D11DeviceContext_Map(p_sys
->context
, p_sys
->resource
[KNOWN_DXGI_INDEX
], 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
402 return CommonUpdatePicture(picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
405 static void Direct3D11UnmapPoolTexture(picture_t
*picture
)
407 picture_sys_t
*p_sys
= picture
->p_sys
;
408 ID3D11DeviceContext_Unmap(p_sys
->context
, p_sys
->resource
[KNOWN_DXGI_INDEX
], 0);
411 static int Direct3D11LockDirectTexture(picture_t
*picture
)
413 picture_sys_t
*p_sys
= picture
->p_sys
;
414 D3D11_MAPPED_SUBRESOURCE mappedResource
;
416 D3D11_TEXTURE2D_DESC texDesc
;
419 for (i
= 0; i
< picture
->i_planes
; i
++) {
420 hr
= ID3D11DeviceContext_Map(p_sys
->context
, p_sys
->resource
[i
], 0, D3D11_MAP_WRITE
, 0, &mappedResource
);
423 ID3D11Texture2D_GetDesc(p_sys
->texture
[i
], &texDesc
);
424 picture
->p
[i
].p_pixels
= mappedResource
.pData
;
425 picture
->p
[i
].i_pitch
= mappedResource
.RowPitch
;
426 picture
->p
[i
].i_lines
= texDesc
.Height
;
427 assert(picture
->p
[i
].i_visible_pitch
<= picture
->p
[i
].i_pitch
);
428 assert(picture
->p
[i
].i_visible_lines
<= picture
->p
[i
].i_lines
);
434 ID3D11DeviceContext_Unmap(p_sys
->context
, p_sys
->resource
[i
+1], 0);
438 p_sys
->mapped
= true;
442 static void Direct3D11UnlockDirectTexture(picture_t
*picture
)
444 picture_sys_t
*p_sys
= ActivePictureSys(picture
);
446 for (int i
= 0; i
< picture
->i_planes
; i
++)
447 ID3D11DeviceContext_Unmap(p_sys
->context
, p_sys
->resource
[i
], 0);
448 p_sys
->mapped
= false;
452 #if !VLC_WINSTORE_APP
453 static int OpenHwnd(vout_display_t
*vd
)
455 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
459 sys
->hd3d11_dll
= LoadLibrary(TEXT("D3D11.DLL"));
460 if (!sys
->hd3d11_dll
) {
461 msg_Warn(vd
, "cannot load d3d11.dll, aborting");
465 sys
->hd3dcompiler_dll
= Direct3D11LoadShaderLibrary();
466 if (!sys
->hd3dcompiler_dll
) {
467 msg_Err(vd
, "cannot load d3dcompiler.dll, aborting");
468 Direct3D11Destroy(vd
);
472 sys
->OurD3DCompile
= (void *)GetProcAddress(sys
->hd3dcompiler_dll
, "D3DCompile");
473 if (!sys
->OurD3DCompile
) {
474 msg_Err(vd
, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
475 Direct3D11Destroy(vd
);
479 sys
->OurD3D11CreateDevice
=
480 (void *)GetProcAddress(sys
->hd3d11_dll
, "D3D11CreateDevice");
481 if (!sys
->OurD3D11CreateDevice
) {
482 msg_Err(vd
, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
483 Direct3D11Destroy(vd
);
489 static int OpenCoreW(vout_display_t
*vd
)
491 IDXGISwapChain1
* dxgiswapChain
= var_InheritInteger(vd
, "winrt-swapchain");
494 ID3D11DeviceContext
* d3dcontext
= var_InheritInteger(vd
, "winrt-d3dcontext");
497 ID3D11Device
* d3ddevice
= NULL
;
498 ID3D11DeviceContext_GetDevice(d3dcontext
, &d3ddevice
);
502 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
506 sys
->dxgiswapChain
= dxgiswapChain
;
507 sys
->d3ddevice
= d3ddevice
;
508 sys
->d3dcontext
= d3dcontext
;
509 IDXGISwapChain_AddRef (sys
->dxgiswapChain
);
510 ID3D11Device_AddRef (sys
->d3ddevice
);
511 ID3D11DeviceContext_AddRef(sys
->d3dcontext
);
517 static bool is_d3d11_opaque(vlc_fourcc_t chroma
)
521 case VLC_CODEC_D3D11_OPAQUE
:
522 case VLC_CODEC_D3D11_OPAQUE_10B
:
530 static bool GetRect(const vout_display_sys_win32_t
*p_sys
, RECT
*out
)
532 const vout_display_sys_t
*sys
= (const vout_display_sys_t
*)p_sys
;
537 UINT dataSize
= sizeof(i_width
);
538 HRESULT hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_WIDTH
, &dataSize
, &i_width
);
542 dataSize
= sizeof(i_height
);
543 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_HEIGHT
, &dataSize
, &i_height
);
547 out
->right
= i_width
;
548 out
->bottom
= i_height
;
553 static int Open(vlc_object_t
*object
)
555 vout_display_t
*vd
= (vout_display_t
*)object
;
557 #if !VLC_WINSTORE_APP
558 int ret
= OpenHwnd(vd
);
560 int ret
= OpenCoreW(vd
);
563 if (ret
!= VLC_SUCCESS
)
570 vd
->sys
->sys
.pf_GetRect
= GetRect
;
574 video_format_Copy(&fmt
, &vd
->source
);
575 if (Direct3D11Open(vd
, &fmt
)) {
576 msg_Err(vd
, "Direct3D11 could not be opened");
580 video_format_Clean(&vd
->fmt
);
583 vd
->info
.has_double_click
= true;
584 vd
->info
.has_pictures_invalid
= vd
->info
.is_slow
;
586 if (var_InheritBool(vd
, "direct3d11-hw-blending") &&
587 vd
->sys
->d3dregion_format
!= NULL
)
589 vd
->sys
->pSubpictureChromas
[0] = vd
->sys
->d3dregion_format
->fourcc
;
590 vd
->sys
->pSubpictureChromas
[1] = 0;
591 vd
->info
.subpicture_chromas
= vd
->sys
->pSubpictureChromas
;
594 vd
->info
.subpicture_chromas
= NULL
;
597 vd
->prepare
= Prepare
;
598 vd
->display
= Display
;
599 vd
->control
= Control
;
602 msg_Dbg(vd
, "Direct3D11 Open Succeeded");
611 static void Close(vlc_object_t
*object
)
613 vout_display_t
* vd
= (vout_display_t
*)object
;
617 Direct3D11Destroy(vd
);
621 static int AllocateTextures(vout_display_t
*vd
, const d3d_format_t
*cfg
,
622 video_format_t
*fmt
, unsigned pool_size
,
623 ID3D11Texture2D
*textures
[],
624 bool pool_type_display
)
626 vout_display_sys_t
*sys
= vd
->sys
;
627 plane_t planes
[PICTURE_PLANE_MAX
];
628 int plane
, plane_count
;
630 ID3D11Texture2D
*slicedTexture
= NULL
;
631 D3D11_TEXTURE2D_DESC texDesc
;
632 ZeroMemory(&texDesc
, sizeof(texDesc
));
633 texDesc
.MipLevels
= 1;
634 texDesc
.SampleDesc
.Count
= 1;
635 texDesc
.MiscFlags
= 0; //D3D11_RESOURCE_MISC_SHARED;
636 const vlc_chroma_description_t
*p_chroma_desc
= vlc_fourcc_GetChromaDescription( fmt
->i_chroma
);
640 if (cfg
->formatTexture
== DXGI_FORMAT_UNKNOWN
) {
641 int i_width_aligned
= fmt
->i_width
;
642 int i_height_aligned
= fmt
->i_height
;
643 if (p_chroma_desc
->plane_count
== 0)
645 msg_Dbg(vd
, "failed to get the pixel format planes for %4.4s", (char *)&fmt
->i_chroma
);
648 assert(p_chroma_desc
->plane_count
<= D3D11_MAX_SHADER_VIEW
);
649 plane_count
= p_chroma_desc
->plane_count
;
651 texDesc
.Format
= cfg
->resourceFormat
[0];
652 assert(cfg
->resourceFormat
[1] == cfg
->resourceFormat
[0]);
653 assert(cfg
->resourceFormat
[2] == cfg
->resourceFormat
[0]);
655 if (pool_type_display
) {
656 texDesc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
657 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
659 texDesc
.Usage
= D3D11_USAGE_STAGING
;
660 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
662 /* align on 16 pixel boundaries */
663 i_width_aligned
= ( i_width_aligned
+ 15 ) & ~15;
664 i_height_aligned
= ( i_height_aligned
+ 15 ) & ~15;
667 for( int i
= 0; i
< plane_count
; i
++ )
669 plane_t
*p
= &planes
[i
];
671 p
->i_lines
= i_height_aligned
* p_chroma_desc
->p
[i
].h
.num
/ p_chroma_desc
->p
[i
].h
.den
;
672 p
->i_visible_lines
= fmt
->i_visible_height
* p_chroma_desc
->p
[i
].h
.num
/ p_chroma_desc
->p
[i
].h
.den
;
673 p
->i_pitch
= i_width_aligned
* p_chroma_desc
->p
[i
].w
.num
/ p_chroma_desc
->p
[i
].w
.den
* p_chroma_desc
->pixel_size
;
674 p
->i_visible_pitch
= fmt
->i_visible_width
* p_chroma_desc
->p
[i
].w
.num
/ p_chroma_desc
->p
[i
].w
.den
* p_chroma_desc
->pixel_size
;
675 p
->i_pixel_pitch
= p_chroma_desc
->pixel_size
;
678 if (!pool_type_display
) {
679 assert( (planes
[0].i_pitch
% 16) == 0 );
682 texDesc
.ArraySize
= 1;
685 texDesc
.Format
= cfg
->formatTexture
;
686 texDesc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
687 if (is_d3d11_opaque(fmt
->i_chroma
)) {
688 texDesc
.BindFlags
|= D3D11_BIND_DECODER
;
689 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
690 texDesc
.CPUAccessFlags
= 0;
692 texDesc
.Usage
= D3D11_USAGE_DYNAMIC
;
693 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
695 texDesc
.ArraySize
= pool_size
;
696 texDesc
.Height
= fmt
->i_height
;
697 texDesc
.Width
= fmt
->i_width
;
699 hr
= ID3D11Device_CreateTexture2D( sys
->d3ddevice
, &texDesc
, NULL
, &slicedTexture
);
701 msg_Err(vd
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
706 for (unsigned picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
707 for (plane
= 0; plane
< plane_count
; plane
++)
710 textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] = slicedTexture
;
711 ID3D11Texture2D_AddRef(slicedTexture
);
713 texDesc
.Height
= planes
[plane
].i_lines
;
714 texDesc
.Width
= planes
[plane
].i_pitch
;
715 hr
= ID3D11Device_CreateTexture2D( sys
->d3ddevice
, &texDesc
, NULL
, &textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] );
717 msg_Err(vd
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
722 for (; plane
< D3D11_MAX_SHADER_VIEW
; plane
++) {
723 if (!cfg
->resourceFormat
[plane
])
724 textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] = NULL
;
727 textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] = textures
[picture_count
* D3D11_MAX_SHADER_VIEW
];
728 ID3D11Texture2D_AddRef(textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
]);
733 if (!is_d3d11_opaque(fmt
->i_chroma
) && cfg
->formatTexture
!= DXGI_FORMAT_UNKNOWN
) {
734 D3D11_MAPPED_SUBRESOURCE mappedResource
;
735 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)textures
[0], 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
737 msg_Err(vd
, "The texture cannot be mapped. (hr=0x%lX)", hr
);
740 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)textures
[0], 0);
741 if (mappedResource
.RowPitch
< p_chroma_desc
->pixel_size
* texDesc
.Width
) {
742 msg_Err( vd
, "The texture row pitch is too small (%d instead of %d)", mappedResource
.RowPitch
,
743 p_chroma_desc
->pixel_size
* texDesc
.Width
);
749 ID3D11Texture2D_Release(slicedTexture
);
753 ID3D11Texture2D_Release(slicedTexture
);
757 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned pool_size
)
759 /* compensate for extra hardware decoding pulling extra pictures from our pool */
762 vout_display_sys_t
*sys
= vd
->sys
;
763 ID3D11Texture2D
*textures
[pool_size
* D3D11_MAX_SHADER_VIEW
];
764 picture_t
**pictures
= NULL
;
767 unsigned picture_count
= 0;
768 picture_pool_configuration_t pool_cfg
= {};
771 return sys
->sys
.pool
;
773 if (vd
->info
.is_slow
)
776 video_format_t surface_fmt
= vd
->fmt
;
777 surface_fmt
.i_width
= sys
->picQuad
.i_width
;
778 surface_fmt
.i_height
= sys
->picQuad
.i_height
;
780 if (AllocateTextures(vd
, sys
->picQuadConfig
, &surface_fmt
, pool_size
, textures
,
781 sys
->picQuadConfig
->formatTexture
!= DXGI_FORMAT_UNKNOWN
))
784 if (!vd
->info
.is_slow
) {
786 ID3D10Multithread
*pMultithread
;
787 hr
= ID3D11Device_QueryInterface( sys
->d3ddevice
, &IID_ID3D10Multithread
, (void **)&pMultithread
);
789 ID3D10Multithread_SetMultithreadProtected(pMultithread
, TRUE
);
790 ID3D10Multithread_Release(pMultithread
);
794 pictures
= calloc(pool_size
, sizeof(*pictures
));
798 for (picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
799 picture_sys_t
*picsys
= calloc(1, sizeof(*picsys
));
800 if (unlikely(picsys
== NULL
))
803 for (plane
= 0; plane
< D3D11_MAX_SHADER_VIEW
; plane
++)
804 picsys
->texture
[plane
] = textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
];
806 picsys
->slice_index
= picture_count
;
807 picsys
->formatTexture
= sys
->picQuadConfig
->formatTexture
;
808 picsys
->context
= sys
->d3dcontext
;
810 picture_resource_t resource
= {
812 .pf_destroy
= DestroyDisplayPoolPicture
,
815 picture
= picture_NewFromResource(&surface_fmt
, &resource
);
816 if (unlikely(picture
== NULL
)) {
818 msg_Err( vd
, "Failed to create picture %d in the pool.", picture_count
);
822 pictures
[picture_count
] = picture
;
823 /* each picture_t holds a ref to the context and release it on Destroy */
824 ID3D11DeviceContext_AddRef(picsys
->context
);
827 #ifdef HAVE_ID3D11VIDEODECODER
828 if (!is_d3d11_opaque(surface_fmt
.i_chroma
) || sys
->legacy_shader
)
830 /* we need a staging texture */
831 if (AllocateTextures(vd
, sys
->picQuadConfig
, &surface_fmt
, 1, textures
, true))
834 sys
->picQuad
.p_chroma_sampling
= vlc_fourcc_GetChromaDescription( surface_fmt
.i_chroma
);
836 for (unsigned plane
= 0; plane
< D3D11_MAX_SHADER_VIEW
; plane
++)
837 sys
->stagingSys
.texture
[plane
] = textures
[plane
];
839 if (AllocateShaderView(VLC_OBJECT(vd
), sys
->d3ddevice
, sys
->picQuadConfig
,
840 textures
, 0, sys
->stagingSys
.resourceView
))
845 for (picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
846 if (AllocateShaderView(VLC_OBJECT(vd
), sys
->d3ddevice
, sys
->picQuadConfig
,
847 pictures
[picture_count
]->p_sys
->texture
, picture_count
,
848 pictures
[picture_count
]->p_sys
->resourceView
))
853 if (SetupQuad( vd
, &surface_fmt
, &sys
->picQuad
, &sys
->sys
.rect_src_clipped
,
854 sys
->picQuadConfig
, sys
->picQuadPixelShader
,
855 surface_fmt
.projection_mode
, vd
->fmt
.orientation
) != VLC_SUCCESS
) {
856 msg_Err(vd
, "Could not Create the main quad picture.");
860 if (sys
->picQuadConfig
->formatTexture
== DXGI_FORMAT_UNKNOWN
)
862 pool_cfg
.lock
= Direct3D11LockDirectTexture
;
863 pool_cfg
.unlock
= Direct3D11UnlockDirectTexture
;
865 else if (vd
->info
.is_slow
) {
866 pool_cfg
.lock
= Direct3D11MapPoolTexture
;
867 //pool_cfg.unlock = Direct3D11UnmapPoolTexture;
869 pool_cfg
.picture
= pictures
;
870 pool_cfg
.picture_count
= pool_size
;
871 sys
->sys
.pool
= picture_pool_NewExtended( &pool_cfg
);
874 if (sys
->sys
.pool
== NULL
) {
876 msg_Dbg(vd
, "Failed to create the picture d3d11 pool");
877 for (unsigned i
=0;i
<picture_count
; ++i
)
878 picture_Release(pictures
[i
]);
882 /* create an empty pool to avoid crashing */
883 pool_cfg
.picture_count
= 0;
884 sys
->sys
.pool
= picture_pool_NewExtended( &pool_cfg
);
886 msg_Dbg(vd
, "D3D11 pool succeed with %d surfaces (%dx%d) context 0x%p",
887 picture_count
, surface_fmt
.i_width
, surface_fmt
.i_height
, sys
->d3dcontext
);
889 return sys
->sys
.pool
;
892 static void DestroyDisplayPoolPicture(picture_t
*picture
)
894 picture_sys_t
*p_sys
= picture
->p_sys
;
895 ReleasePictureSys( p_sys
);
900 static HRESULT
UpdateBackBuffer(vout_display_t
*vd
)
902 vout_display_sys_t
*sys
= vd
->sys
;
904 ID3D11Texture2D
* pDepthStencil
;
905 ID3D11Texture2D
* pBackBuffer
;
908 if (!GetRect(&sys
->sys
, &rect
))
910 rect
= sys
->sys
.rect_dest_clipped
;
911 uint32_t i_width
= RECTWidth(rect
);
912 uint32_t i_height
= RECTHeight(rect
);
914 if (sys
->d3drenderTargetView
) {
915 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
916 sys
->d3drenderTargetView
= NULL
;
918 if (sys
->d3ddepthStencilView
) {
919 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
920 sys
->d3ddepthStencilView
= NULL
;
923 /* TODO detect is the size is the same as the output and switch to fullscreen mode */
924 hr
= IDXGISwapChain_ResizeBuffers(sys
->dxgiswapChain
, 0, i_width
, i_height
,
925 DXGI_FORMAT_UNKNOWN
, 0);
927 msg_Err(vd
, "Failed to resize the backbuffer. (hr=0x%lX)", hr
);
931 hr
= IDXGISwapChain_GetBuffer(sys
->dxgiswapChain
, 0, &IID_ID3D11Texture2D
, (LPVOID
*)&pBackBuffer
);
933 msg_Err(vd
, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr
);
937 hr
= ID3D11Device_CreateRenderTargetView(sys
->d3ddevice
, (ID3D11Resource
*)pBackBuffer
, NULL
, &sys
->d3drenderTargetView
);
938 ID3D11Texture2D_Release(pBackBuffer
);
940 msg_Err(vd
, "Failed to create the target view. (hr=0x%lX)", hr
);
944 D3D11_TEXTURE2D_DESC deptTexDesc
;
945 memset(&deptTexDesc
, 0,sizeof(deptTexDesc
));
946 deptTexDesc
.ArraySize
= 1;
947 deptTexDesc
.BindFlags
= D3D11_BIND_DEPTH_STENCIL
;
948 deptTexDesc
.CPUAccessFlags
= 0;
949 deptTexDesc
.Format
= DXGI_FORMAT_D24_UNORM_S8_UINT
;
950 deptTexDesc
.Width
= i_width
;
951 deptTexDesc
.Height
= i_height
;
952 deptTexDesc
.MipLevels
= 1;
953 deptTexDesc
.MiscFlags
= 0;
954 deptTexDesc
.SampleDesc
.Count
= 1;
955 deptTexDesc
.SampleDesc
.Quality
= 0;
956 deptTexDesc
.Usage
= D3D11_USAGE_DEFAULT
;
958 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &deptTexDesc
, NULL
, &pDepthStencil
);
960 msg_Err(vd
, "Could not create the depth stencil texture. (hr=0x%lX)", hr
);
964 D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc
;
965 memset(&depthViewDesc
, 0, sizeof(depthViewDesc
));
967 depthViewDesc
.Format
= deptTexDesc
.Format
;
968 depthViewDesc
.ViewDimension
= D3D11_DSV_DIMENSION_TEXTURE2D
;
969 depthViewDesc
.Texture2D
.MipSlice
= 0;
971 hr
= ID3D11Device_CreateDepthStencilView(sys
->d3ddevice
, (ID3D11Resource
*)pDepthStencil
, &depthViewDesc
, &sys
->d3ddepthStencilView
);
972 ID3D11Texture2D_Release(pDepthStencil
);
975 msg_Err(vd
, "Could not create the depth stencil view. (hr=0x%lX)", hr
);
982 /* rotation around the Z axis */
983 static void getZRotMatrix(float theta
, FLOAT matrix
[static 16])
987 sincosf(theta
, &st
, &ct
);
997 memcpy(matrix
, m
, sizeof(m
));
1000 /* rotation around the Y axis */
1001 static void getYRotMatrix(float theta
, FLOAT matrix
[static 16])
1005 sincosf(theta
, &st
, &ct
);
1015 memcpy(matrix
, m
, sizeof(m
));
1018 /* rotation around the X axis */
1019 static void getXRotMatrix(float phi
, FLOAT matrix
[static 16])
1023 sincosf(phi
, &sp
, &cp
);
1033 memcpy(matrix
, m
, sizeof(m
));
1036 static void getZoomMatrix(float zoom
, FLOAT matrix
[static 16]) {
1040 1.0f
, 0.0f
, 0.0f
, 0.0f
,
1041 0.0f
, 1.0f
, 0.0f
, 0.0f
,
1042 0.0f
, 0.0f
, 1.0f
, 0.0f
,
1043 0.0f
, 0.0f
, zoom
, 1.0f
1046 memcpy(matrix
, m
, sizeof(m
));
1049 /* perspective matrix see https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml */
1050 static void getProjectionMatrix(float sar
, float fovy
, FLOAT matrix
[static 16]) {
1055 float f
= 1.f
/ tanf(fovy
/ 2.f
);
1058 f
/ sar
, 0.f
, 0.f
, 0.f
,
1060 0.f
, 0.f
, (zNear
+ zFar
) / (zNear
- zFar
), -1.f
,
1061 0.f
, 0.f
, (2 * zNear
* zFar
) / (zNear
- zFar
), 0.f
};
1063 memcpy(matrix
, m
, sizeof(m
));
1066 static float UpdateFOVy(float f_fovx
, float f_sar
)
1068 return 2 * atanf(tanf(f_fovx
/ 2) / f_sar
);
1071 static float UpdateZ(float f_fovx
, float f_fovy
)
1073 /* Do trigonometry to calculate the minimal z value
1074 * that will allow us to zoom out without seeing the outside of the
1075 * sphere (black borders). */
1076 float tan_fovx_2
= tanf(f_fovx
/ 2);
1077 float tan_fovy_2
= tanf(f_fovy
/ 2);
1078 float z_min
= - SPHERE_RADIUS
/ sinf(atanf(sqrtf(
1079 tan_fovx_2
* tan_fovx_2
+ tan_fovy_2
* tan_fovy_2
)));
1081 /* The FOV value above which z is dynamically calculated. */
1082 const float z_thresh
= 90.f
;
1085 if (f_fovx
<= z_thresh
* M_PI
/ 180)
1089 float f
= z_min
/ ((FIELD_OF_VIEW_DEGREES_MAX
- z_thresh
) * M_PI
/ 180);
1090 f_z
= f
* f_fovx
- f
* z_thresh
* M_PI
/ 180;
1097 static void SetQuadVSProjection(vout_display_t
*vd
, d3d_quad_t
*quad
, const vlc_viewpoint_t
*p_vp
)
1099 if (!quad
->pVertexShaderConstants
)
1102 #define RAD(d) ((float) ((d) * M_PI / 180.f))
1103 float f_fovx
= RAD(p_vp
->fov
);
1104 if ( f_fovx
> FIELD_OF_VIEW_DEGREES_MAX
* M_PI
/ 180 + 0.001f
||
1108 float f_sar
= (float) vd
->cfg
->display
.width
/ vd
->cfg
->display
.height
;
1109 float f_teta
= RAD(p_vp
->yaw
) - (float) M_PI_2
;
1110 float f_phi
= RAD(p_vp
->pitch
);
1111 float f_roll
= RAD(p_vp
->roll
);
1112 float f_fovy
= UpdateFOVy(f_fovx
, f_sar
);
1113 float f_z
= UpdateZ(f_fovx
, f_fovy
);
1115 vout_display_sys_t
*sys
= vd
->sys
;
1117 D3D11_MAPPED_SUBRESOURCE mapped
;
1118 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexShaderConstants
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mapped
);
1119 if (SUCCEEDED(hr
)) {
1120 VS_PROJECTION_CONST
*dst_data
= mapped
.pData
;
1121 getXRotMatrix(f_phi
, dst_data
->RotX
);
1122 getYRotMatrix(f_teta
, dst_data
->RotY
);
1123 getZRotMatrix(f_roll
, dst_data
->RotZ
);
1124 getZoomMatrix(SPHERE_RADIUS
* f_z
, dst_data
->View
);
1125 getProjectionMatrix(f_sar
, f_fovy
, dst_data
->Projection
);
1127 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexShaderConstants
, 0);
1131 static void UpdateSize(vout_display_t
*vd
)
1133 vout_display_sys_t
*sys
= vd
->sys
;
1134 #if defined(HAVE_ID3D11VIDEODECODER)
1135 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1137 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1140 msg_Dbg(vd
, "Detected size change %dx%d", RECTWidth(sys
->sys
.rect_dest_clipped
),
1141 RECTHeight(sys
->sys
.rect_dest_clipped
));
1143 UpdateBackBuffer(vd
);
1145 UpdatePicQuadPosition(vd
);
1147 UpdateQuadPosition(vd
, &sys
->picQuad
, &sys
->sys
.rect_src_clipped
,
1148 vd
->fmt
.projection_mode
, vd
->fmt
.orientation
);
1150 #if defined(HAVE_ID3D11VIDEODECODER)
1151 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1153 ReleaseMutex( sys
->context_lock
);
1158 static inline bool RectEquals(const RECT
*r1
, const RECT
*r2
)
1160 return r1
->bottom
== r2
->bottom
&& r1
->top
== r2
->top
&&
1161 r1
->left
== r2
->left
&& r1
->right
== r2
->right
;
1164 #define BEFORE_UPDATE_RECTS \
1165 unsigned int i_outside_width = vd->fmt.i_width; \
1166 unsigned int i_outside_height = vd->fmt.i_height; \
1167 vd->fmt.i_width = vd->sys->picQuad.i_width; \
1168 vd->fmt.i_height = vd->sys->picQuad.i_height;
1169 #define AFTER_UPDATE_RECTS \
1170 vd->fmt.i_width = i_outside_width; \
1171 vd->fmt.i_height = i_outside_height;
1173 static int Control(vout_display_t
*vd
, int query
, va_list args
)
1175 vout_display_sys_t
*sys
= vd
->sys
;
1176 RECT before_src_clipped
= sys
->sys
.rect_src_clipped
;
1177 RECT before_dest_clipped
= sys
->sys
.rect_dest_clipped
;
1178 RECT before_dest
= sys
->sys
.rect_dest
;
1180 BEFORE_UPDATE_RECTS
;
1181 int res
= CommonControl( vd
, query
, args
);
1184 if (query
== VOUT_DISPLAY_CHANGE_VIEWPOINT
)
1186 const vout_display_cfg_t
*cfg
= va_arg(args
, const vout_display_cfg_t
*);
1187 if ( sys
->picQuad
.pVertexShaderConstants
)
1189 SetQuadVSProjection( vd
, &sys
->picQuad
, &cfg
->viewpoint
);
1194 if (!RectEquals(&before_src_clipped
, &sys
->sys
.rect_src_clipped
) ||
1195 !RectEquals(&before_dest_clipped
, &sys
->sys
.rect_dest_clipped
) ||
1196 !RectEquals(&before_dest
, &sys
->sys
.rect_dest
) )
1204 static void Manage(vout_display_t
*vd
)
1206 vout_display_sys_t
*sys
= vd
->sys
;
1207 RECT before_src_clipped
= sys
->sys
.rect_src_clipped
;
1208 RECT before_dest_clipped
= sys
->sys
.rect_dest_clipped
;
1209 RECT before_dest
= sys
->sys
.rect_dest
;
1211 BEFORE_UPDATE_RECTS
;
1215 if (!RectEquals(&before_src_clipped
, &sys
->sys
.rect_src_clipped
) ||
1216 !RectEquals(&before_dest_clipped
, &sys
->sys
.rect_dest_clipped
) ||
1217 !RectEquals(&before_dest
, &sys
->sys
.rect_dest
))
1223 static void DisplayD3DPicture(vout_display_sys_t
*sys
, d3d_quad_t
*quad
, ID3D11ShaderResourceView
*resourceView
[D3D11_MAX_SHADER_VIEW
])
1225 UINT stride
= sizeof(d3d_vertex_t
);
1228 /* Render the quad */
1230 ID3D11DeviceContext_IASetVertexBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexBuffer
, &stride
, &offset
);
1231 ID3D11DeviceContext_IASetIndexBuffer(sys
->d3dcontext
, quad
->pIndexBuffer
, DXGI_FORMAT_R16_UINT
, 0);
1232 if ( quad
->pVertexShaderConstants
)
1233 ID3D11DeviceContext_VSSetConstantBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexShaderConstants
);
1235 ID3D11DeviceContext_VSSetShader(sys
->d3dcontext
, quad
->d3dvertexShader
, NULL
, 0);
1238 ID3D11DeviceContext_PSSetShader(sys
->d3dcontext
, quad
->d3dpixelShader
, NULL
, 0);
1240 ID3D11DeviceContext_PSSetConstantBuffers(sys
->d3dcontext
, 0, quad
->PSConstantsCount
, quad
->pPixelShaderConstants
);
1241 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 0, D3D11_MAX_SHADER_VIEW
, resourceView
);
1243 ID3D11DeviceContext_RSSetViewports(sys
->d3dcontext
, 1, &quad
->cropViewport
);
1245 ID3D11DeviceContext_DrawIndexed(sys
->d3dcontext
, quad
->indexCount
, 0, 0);
1248 static void Prepare(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
1250 vout_display_sys_t
*sys
= vd
->sys
;
1252 picture_sys_t
*p_sys
= ActivePictureSys(picture
);
1254 #if defined(HAVE_ID3D11VIDEODECODER)
1255 if (sys
->context_lock
!= INVALID_HANDLE_VALUE
&& is_d3d11_opaque(picture
->format
.i_chroma
))
1256 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1258 if (p_sys
->formatTexture
== DXGI_FORMAT_UNKNOWN
)
1260 Direct3D11UnlockDirectTexture(picture
);
1261 for (int plane
= 0; plane
< D3D11_MAX_SHADER_VIEW
; plane
++)
1263 if (!p_sys
->resource
[plane
])
1266 unsigned int width
= sys
->picQuad
.i_width
;
1267 unsigned int height
= sys
->picQuad
.i_height
;
1268 unsigned int x_offset
= picture
->format
.i_x_offset
;
1269 unsigned int y_offset
= picture
->format
.i_y_offset
;
1270 x_offset
= x_offset
* sys
->picQuad
.p_chroma_sampling
->p
[plane
].h
.num
/ sys
->picQuad
.p_chroma_sampling
->p
[plane
].h
.den
;
1271 y_offset
= y_offset
* sys
->picQuad
.p_chroma_sampling
->p
[plane
].w
.num
/ sys
->picQuad
.p_chroma_sampling
->p
[plane
].w
.den
;
1272 width
= width
* sys
->picQuad
.p_chroma_sampling
->p
[plane
].h
.num
/ sys
->picQuad
.p_chroma_sampling
->p
[plane
].h
.den
;
1273 height
= height
* sys
->picQuad
.p_chroma_sampling
->p
[plane
].w
.num
/ sys
->picQuad
.p_chroma_sampling
->p
[plane
].w
.den
;
1277 .bottom
= y_offset
+ height
,
1279 .right
= x_offset
+ width
,
1282 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
1283 sys
->stagingSys
.resource
[plane
],
1285 p_sys
->resource
[plane
],
1289 else if (!is_d3d11_opaque(picture
->format
.i_chroma
) || sys
->legacy_shader
) {
1290 D3D11_TEXTURE2D_DESC texDesc
;
1291 if (!is_d3d11_opaque(picture
->format
.i_chroma
))
1292 Direct3D11UnmapPoolTexture(picture
);
1293 ID3D11Texture2D_GetDesc(sys
->stagingSys
.texture
[0], &texDesc
);
1296 .bottom
= picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
,
1298 .right
= picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
,
1301 if ( sys
->picQuadConfig
->formatTexture
!= DXGI_FORMAT_R8G8B8A8_UNORM
&&
1302 sys
->picQuadConfig
->formatTexture
!= DXGI_FORMAT_B5G6R5_UNORM
)
1304 box
.bottom
= (box
.bottom
+ 0x01) & ~0x01;
1305 box
.right
= (box
.right
+ 0x01) & ~0x01;
1307 assert(box
.right
<= texDesc
.Width
);
1308 assert(box
.bottom
<= texDesc
.Height
);
1309 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
1310 sys
->stagingSys
.resource
[KNOWN_DXGI_INDEX
],
1312 p_sys
->resource
[KNOWN_DXGI_INDEX
],
1313 p_sys
->slice_index
, &box
);
1317 D3D11_TEXTURE2D_DESC texDesc
;
1318 ID3D11Texture2D_GetDesc(p_sys
->texture
[0], &texDesc
);
1319 if (texDesc
.BindFlags
& D3D11_BIND_SHADER_RESOURCE
)
1321 /* for performance reason we don't want to allocate this during
1322 * display, do it preferrably when creating the texture */
1323 assert(p_sys
->resourceView
[0]!=NULL
);
1326 if ( sys
->picQuad
.i_height
!= texDesc
.Height
||
1327 sys
->picQuad
.i_width
!= texDesc
.Width
)
1329 /* the decoder produced different sizes than the vout, we need to
1330 * adjust the vertex */
1331 sys
->picQuad
.i_height
= texDesc
.Height
;
1332 sys
->picQuad
.i_width
= texDesc
.Width
;
1334 BEFORE_UPDATE_RECTS
;
1335 UpdateRects(vd
, NULL
, true);
1342 int subpicture_region_count
= 0;
1343 picture_t
**subpicture_regions
= NULL
;
1344 Direct3D11MapSubpicture(vd
, &subpicture_region_count
, &subpicture_regions
, subpicture
);
1345 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
1346 sys
->d3dregion_count
= subpicture_region_count
;
1347 sys
->d3dregions
= subpicture_regions
;
1350 FLOAT blackRGBA
[4] = {0.0f
, 0.0f
, 0.0f
, 1.0f
};
1351 ID3D11DeviceContext_ClearRenderTargetView(sys
->d3dcontext
, sys
->d3drenderTargetView
, blackRGBA
);
1353 /* no ID3D11Device operations should come here */
1355 ID3D11DeviceContext_OMSetRenderTargets(sys
->d3dcontext
, 1, &sys
->d3drenderTargetView
, sys
->d3ddepthStencilView
);
1357 ID3D11DeviceContext_ClearDepthStencilView(sys
->d3dcontext
, sys
->d3ddepthStencilView
, D3D11_CLEAR_DEPTH
| D3D11_CLEAR_STENCIL
, 1.0f
, 0);
1359 /* Render the quad */
1360 if (!is_d3d11_opaque(picture
->format
.i_chroma
) || sys
->legacy_shader
)
1361 DisplayD3DPicture(sys
, &sys
->picQuad
, sys
->stagingSys
.resourceView
);
1363 picture_sys_t
*p_sys
= ActivePictureSys(picture
);
1364 DisplayD3DPicture(sys
, &sys
->picQuad
, p_sys
->resourceView
);
1368 // draw the additional vertices
1369 for (int i
= 0; i
< sys
->d3dregion_count
; ++i
) {
1370 if (sys
->d3dregions
[i
])
1372 d3d_quad_t
*quad
= (d3d_quad_t
*) sys
->d3dregions
[i
]->p_sys
;
1373 DisplayD3DPicture(sys
, quad
, quad
->picSys
.resourceView
);
1378 #if defined(HAVE_ID3D11VIDEODECODER)
1379 if (sys
->context_lock
!= INVALID_HANDLE_VALUE
&& is_d3d11_opaque(picture
->format
.i_chroma
))
1381 ReleaseMutex( sys
->context_lock
);
1385 if (sys
->dxgiswapChain4
&& picture
->format
.mastering
.max_luminance
)
1387 DXGI_HDR_METADATA_HDR10 hdr10
= {0};
1388 hdr10
.GreenPrimary
[0] = picture
->format
.mastering
.primaries
[0];
1389 hdr10
.GreenPrimary
[1] = picture
->format
.mastering
.primaries
[1];
1390 hdr10
.BluePrimary
[0] = picture
->format
.mastering
.primaries
[2];
1391 hdr10
.BluePrimary
[1] = picture
->format
.mastering
.primaries
[3];
1392 hdr10
.RedPrimary
[0] = picture
->format
.mastering
.primaries
[4];
1393 hdr10
.RedPrimary
[1] = picture
->format
.mastering
.primaries
[5];
1394 hdr10
.WhitePoint
[0] = picture
->format
.mastering
.white_point
[0];
1395 hdr10
.WhitePoint
[1] = picture
->format
.mastering
.white_point
[1];
1396 hdr10
.MinMasteringLuminance
= picture
->format
.mastering
.min_luminance
;
1397 hdr10
.MaxMasteringLuminance
= picture
->format
.mastering
.max_luminance
;
1398 hdr10
.MaxContentLightLevel
= picture
->format
.lighting
.MaxCLL
;
1399 hdr10
.MaxFrameAverageLightLevel
= picture
->format
.lighting
.MaxFALL
;
1400 IDXGISwapChain4_SetHDRMetaData(sys
->dxgiswapChain4
, DXGI_HDR_METADATA_TYPE_HDR10
, sizeof(hdr10
), &hdr10
);
1403 //ID3D11DeviceContext_Flush(sys->d3dcontext);
1406 static void Display(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
1408 vout_display_sys_t
*sys
= vd
->sys
;
1410 DXGI_PRESENT_PARAMETERS presentParams
;
1411 memset(&presentParams
, 0, sizeof(presentParams
));
1412 HRESULT hr
= IDXGISwapChain1_Present1(sys
->dxgiswapChain
, 0, 0, &presentParams
);
1413 if (hr
== DXGI_ERROR_DEVICE_REMOVED
|| hr
== DXGI_ERROR_DEVICE_RESET
)
1415 /* TODO device lost */
1416 msg_Dbg(vd
, "SwapChain Present failed. (hr=0x%lX)", hr
);
1419 picture_Release(picture
);
1421 subpicture_Delete(subpicture
);
1426 static void Direct3D11Destroy(vout_display_t
*vd
)
1428 #if !VLC_WINSTORE_APP
1429 vout_display_sys_t
*sys
= vd
->sys
;
1431 if (sys
->hd3d11_dll
)
1432 FreeLibrary(sys
->hd3d11_dll
);
1433 if (sys
->hd3dcompiler_dll
)
1434 FreeLibrary(sys
->hd3dcompiler_dll
);
1436 sys
->OurD3D11CreateDevice
= NULL
;
1437 sys
->OurD3D11CreateDeviceAndSwapChain
= NULL
;
1438 sys
->OurD3DCompile
= NULL
;
1439 sys
->hdxgi_dll
= NULL
;
1440 sys
->hd3d11_dll
= NULL
;
1441 sys
->hd3dcompiler_dll
= NULL
;
1447 #if !VLC_WINSTORE_APP
1448 static HINSTANCE
Direct3D11LoadShaderLibrary(void)
1450 HINSTANCE instance
= NULL
;
1451 /* d3dcompiler_47 is the latest on windows 8.1 */
1452 for (int i
= 47; i
> 41; --i
) {
1454 _sntprintf(filename
, 19, TEXT("D3DCOMPILER_%d.dll"), i
);
1455 instance
= LoadLibrary(filename
);
1456 if (instance
) break;
1462 #define COLOR_RANGE_FULL 1 /* 0-255 */
1463 #define COLOR_RANGE_STUDIO 0 /* 16-235 */
1465 #define TRANSFER_FUNC_10 TRANSFER_FUNC_LINEAR
1466 #define TRANSFER_FUNC_22 TRANSFER_FUNC_SRGB
1467 #define TRANSFER_FUNC_2084 TRANSFER_FUNC_SMPTE_ST2084
1469 #define COLOR_PRIMARIES_BT601 COLOR_PRIMARIES_BT601_525
1471 static const dxgi_color_space color_spaces
[] = {
1472 #define DXGIMAP(AXIS, RANGE, GAMMA, SITTING, PRIMARIES) \
1473 { DXGI_COLOR_SPACE_##AXIS##_##RANGE##_G##GAMMA##_##SITTING##_P##PRIMARIES, \
1474 #AXIS " Rec." #PRIMARIES " gamma:" #GAMMA " range:" #RANGE, \
1475 COLOR_AXIS_##AXIS, COLOR_PRIMARIES_BT##PRIMARIES, TRANSFER_FUNC_##GAMMA, \
1476 COLOR_SPACE_BT##PRIMARIES, COLOR_RANGE_##RANGE},
1478 DXGIMAP(RGB
, FULL
, 22, NONE
, 709)
1479 DXGIMAP(YCBCR
, STUDIO
, 22, LEFT
, 601)
1480 DXGIMAP(YCBCR
, FULL
, 22, LEFT
, 601)
1481 DXGIMAP(RGB
, FULL
, 10, NONE
, 709)
1482 DXGIMAP(RGB
, STUDIO
, 22, NONE
, 709)
1483 DXGIMAP(YCBCR
, STUDIO
, 22, LEFT
, 709)
1484 DXGIMAP(YCBCR
, FULL
, 22, LEFT
, 709)
1485 DXGIMAP(RGB
, STUDIO
, 22, NONE
, 2020)
1486 DXGIMAP(YCBCR
, STUDIO
, 22, LEFT
, 2020)
1487 DXGIMAP(YCBCR
, FULL
, 22, LEFT
, 2020)
1488 DXGIMAP(YCBCR
, STUDIO
, 22, TOPLEFT
, 2020)
1489 DXGIMAP(RGB
, FULL
, 22, NONE
, 2020)
1490 DXGIMAP(RGB
, FULL
, 2084, NONE
, 2020)
1491 DXGIMAP(YCBCR
, STUDIO
, 2084, LEFT
, 2020)
1492 DXGIMAP(RGB
, STUDIO
, 2084, NONE
, 2020)
1493 DXGIMAP(YCBCR
, STUDIO
, 2084, TOPLEFT
, 2020)
1494 /*DXGIMAP(YCBCR, FULL, 22, NONE, 2020, 601)*/
1495 {DXGI_COLOR_SPACE_RESERVED
, NULL
, 0, 0, 0, 0, 0},
1499 static void D3D11SetColorSpace(vout_display_t
*vd
)
1501 vout_display_sys_t
*sys
= vd
->sys
;
1504 int score
, best_score
= 0;
1506 IDXGISwapChain3
*dxgiswapChain3
= NULL
;
1507 sys
->display
.colorspace
= &color_spaces
[0];
1509 hr
= ID3D11Device_QueryInterface( sys
->dxgiswapChain
, &IID_IDXGISwapChain3
, (void **)&dxgiswapChain3
);
1511 msg_Warn(vd
, "could not get a IDXGISwapChain3");
1515 bool src_full_range
= vd
->source
.b_color_range_full
||
1516 /* the YUV->RGB conversion already output full range */
1517 is_d3d11_opaque(vd
->source
.i_chroma
) ||
1518 vlc_fourcc_IsYUV(vd
->source
.i_chroma
);
1519 #if VLC_WINSTORE_APP
1520 if (!src_full_range
&& isXboxHardware(sys
->d3ddevice
)) {
1521 /* even in full range the Xbox outputs with less range so use the max we can*/
1522 src_full_range
= true;
1526 /* pick the best output based on color support and transfer */
1527 /* TODO support YUV output later */
1528 for (int i
=0; color_spaces
[i
].name
; ++i
)
1530 hr
= IDXGISwapChain3_CheckColorSpaceSupport(dxgiswapChain3
, color_spaces
[i
].dxgi
, &support
);
1531 if (SUCCEEDED(hr
) && support
) {
1532 msg_Dbg(vd
, "supports colorspace %s", color_spaces
[i
].name
);
1534 if (color_spaces
[i
].primaries
== vd
->source
.primaries
)
1536 if (color_spaces
[i
].color
== vd
->source
.space
)
1537 score
+= 2; /* we don't want to translate color spaces */
1538 if (color_spaces
[i
].transfer
== vd
->source
.transfer
||
1539 /* favor 2084 output for HLG source */
1540 (color_spaces
[i
].transfer
== TRANSFER_FUNC_SMPTE_ST2084
&& vd
->source
.transfer
== TRANSFER_FUNC_HLG
))
1542 if (color_spaces
[i
].b_full_range
== src_full_range
)
1544 if (score
> best_score
|| (score
&& best
== -1)) {
1554 msg_Warn(vd
, "no matching colorspace found force %s", color_spaces
[best
].name
);
1556 hr
= IDXGISwapChain3_SetColorSpace1(dxgiswapChain3
, color_spaces
[best
].dxgi
);
1559 sys
->display
.colorspace
= &color_spaces
[best
];
1560 msg_Dbg(vd
, "using colorspace %s", sys
->display
.colorspace
->name
);
1563 msg_Err(vd
, "Failed to set colorspace %s. (hr=0x%lX)", sys
->display
.colorspace
->name
, hr
);
1565 /* guestimate the display peak luminance */
1566 switch (sys
->display
.colorspace
->transfer
)
1568 case TRANSFER_FUNC_LINEAR
:
1569 case TRANSFER_FUNC_SRGB
:
1570 sys
->display
.luminance_peak
= DEFAULT_BRIGHTNESS
;
1572 case TRANSFER_FUNC_SMPTE_ST2084
:
1573 sys
->display
.luminance_peak
= 10000;
1575 /* there is no other output transfer on Windows */
1577 vlc_assert_unreachable();
1581 IDXGISwapChain3_Release(dxgiswapChain3
);
1584 static const d3d_format_t
*GetDirectRenderingFormat(vout_display_t
*vd
, vlc_fourcc_t i_src_chroma
)
1586 UINT supportFlags
= D3D11_FORMAT_SUPPORT_SHADER_LOAD
;
1587 if (is_d3d11_opaque(i_src_chroma
))
1588 supportFlags
|= D3D11_FORMAT_SUPPORT_DECODER_OUTPUT
;
1589 return FindD3D11Format( vd
->sys
->d3ddevice
, i_src_chroma
, 0, is_d3d11_opaque(i_src_chroma
), supportFlags
);
1592 static const d3d_format_t
*GetDirectDecoderFormat(vout_display_t
*vd
, vlc_fourcc_t i_src_chroma
)
1594 UINT supportFlags
= D3D11_FORMAT_SUPPORT_DECODER_OUTPUT
;
1595 return FindD3D11Format( vd
->sys
->d3ddevice
, i_src_chroma
, 0, is_d3d11_opaque(i_src_chroma
), supportFlags
);
1598 static const d3d_format_t
*GetDisplayFormatByDepth(vout_display_t
*vd
, uint8_t bit_depth
, bool from_processor
)
1600 UINT supportFlags
= D3D11_FORMAT_SUPPORT_SHADER_LOAD
;
1602 supportFlags
|= D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT
;
1603 return FindD3D11Format( vd
->sys
->d3ddevice
, 0, bit_depth
, false, supportFlags
);
1606 static const d3d_format_t
*GetBlendableFormat(vout_display_t
*vd
, vlc_fourcc_t i_src_chroma
)
1608 UINT supportFlags
= D3D11_FORMAT_SUPPORT_SHADER_LOAD
| D3D11_FORMAT_SUPPORT_BLENDABLE
;
1609 return FindD3D11Format( vd
->sys
->d3ddevice
, i_src_chroma
, 0, false, supportFlags
);
1612 static int Direct3D11Open(vout_display_t
*vd
, video_format_t
*fmt
)
1614 vout_display_sys_t
*sys
= vd
->sys
;
1615 IDXGIFactory2
*dxgifactory
;
1617 #if !VLC_WINSTORE_APP
1619 UINT creationFlags
= 0;
1622 # if !defined(NDEBUG)
1623 # if !VLC_WINSTORE_APP
1624 if (IsDebuggerPresent())
1627 HINSTANCE sdklayer_dll
= LoadLibrary(TEXT("d3d11_1sdklayers.dll"));
1629 creationFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
1630 FreeLibrary(sdklayer_dll
);
1635 if (is_d3d11_opaque(fmt
->i_chroma
))
1636 creationFlags
|= D3D11_CREATE_DEVICE_VIDEO_SUPPORT
;
1638 DXGI_SWAP_CHAIN_DESC1 scd
;
1639 memset(&scd
, 0, sizeof(scd
));
1640 scd
.BufferCount
= 2;
1641 scd
.BufferUsage
= DXGI_USAGE_RENDER_TARGET_OUTPUT
;
1642 scd
.SampleDesc
.Count
= 1;
1643 scd
.SampleDesc
.Quality
= 0;
1644 scd
.Width
= fmt
->i_visible_width
;
1645 scd
.Height
= fmt
->i_visible_height
;
1646 switch(fmt
->i_chroma
)
1648 case VLC_CODEC_D3D11_OPAQUE_10B
:
1649 scd
.Format
= DXGI_FORMAT_R10G10B10A2_UNORM
;
1652 scd
.Format
= DXGI_FORMAT_R8G8B8A8_UNORM
; /* TODO: use DXGI_FORMAT_NV12 */
1655 //scd.Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
1656 scd
.SwapEffect
= DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
;
1658 static const D3D_DRIVER_TYPE driverAttempts
[] = {
1659 D3D_DRIVER_TYPE_HARDWARE
,
1660 D3D_DRIVER_TYPE_WARP
,
1661 #if 0 /* ifndef NDEBUG */
1662 D3D_DRIVER_TYPE_REFERENCE
,
1666 D3D_FEATURE_LEVEL features
[] = {
1667 D3D_FEATURE_LEVEL_11_1
, D3D_FEATURE_LEVEL_11_0
,
1668 D3D_FEATURE_LEVEL_10_1
, D3D_FEATURE_LEVEL_10_0
,
1669 D3D_FEATURE_LEVEL_9_3
, D3D_FEATURE_LEVEL_9_2
, D3D_FEATURE_LEVEL_9_1
1672 for (UINT driver
= 0; driver
< ARRAYSIZE(driverAttempts
); driver
++) {
1673 D3D_FEATURE_LEVEL i_feature_level
;
1674 hr
= D3D11CreateDevice(NULL
, driverAttempts
[driver
], NULL
, creationFlags
,
1675 features
, ARRAY_SIZE(features
), D3D11_SDK_VERSION
,
1676 &sys
->d3ddevice
, &i_feature_level
, &sys
->d3dcontext
);
1677 if (SUCCEEDED(hr
)) {
1679 msg_Dbg(vd
, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
1680 (void *)sys
->d3ddevice
, (void *)sys
->d3dcontext
,
1681 driverAttempts
[driver
], i_feature_level
);
1683 if ( vd
->obj
.force
|| i_feature_level
>= D3D_FEATURE_LEVEL_11_1
)
1685 ID3D11DeviceContext_Release(sys
->d3dcontext
);
1686 sys
->d3dcontext
= NULL
;
1687 ID3D11Device_Release(sys
->d3ddevice
);
1688 sys
->d3ddevice
= NULL
;
1693 msg_Err(vd
, "Could not Create the D3D11 device. (hr=0x%lX)", hr
);
1694 return VLC_EGENERIC
;
1697 IDXGIAdapter
*dxgiadapter
= D3D11DeviceAdapter(sys
->d3ddevice
);
1698 if (unlikely(dxgiadapter
==NULL
)) {
1699 msg_Err(vd
, "Could not get the DXGI Adapter");
1700 return VLC_EGENERIC
;
1703 hr
= IDXGIAdapter_GetParent(dxgiadapter
, &IID_IDXGIFactory2
, (void **)&dxgifactory
);
1704 IDXGIAdapter_Release(dxgiadapter
);
1706 msg_Err(vd
, "Could not get the DXGI Factory. (hr=0x%lX)", hr
);
1707 return VLC_EGENERIC
;
1710 hr
= IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory
, (IUnknown
*)sys
->d3ddevice
,
1711 sys
->sys
.hvideownd
, &scd
, NULL
, NULL
, &sys
->dxgiswapChain
);
1712 IDXGIFactory2_Release(dxgifactory
);
1714 msg_Err(vd
, "Could not create the SwapChain. (hr=0x%lX)", hr
);
1715 return VLC_EGENERIC
;
1719 ID3D11Device_QueryInterface( sys
->dxgiswapChain
, &IID_IDXGISwapChain4
, (void **)&sys
->dxgiswapChain4
);
1721 D3D11SetColorSpace(vd
);
1723 // look for the requested pixel format first
1724 sys
->picQuadConfig
= GetDirectRenderingFormat(vd
, fmt
->i_chroma
);
1726 /* look for a decoder format that can be decoded but not used in shaders */
1727 const d3d_format_t
*decoder_format
= NULL
;
1728 if ( !sys
->picQuadConfig
&& is_d3d11_opaque(fmt
->i_chroma
) )
1729 decoder_format
= GetDirectDecoderFormat(vd
, fmt
->i_chroma
);
1731 // look for any pixel format that we can handle with enough pixels per channel
1732 if ( !sys
->picQuadConfig
)
1734 uint8_t bits_per_channel
;
1735 switch (fmt
->i_chroma
)
1737 case VLC_CODEC_D3D11_OPAQUE
:
1738 bits_per_channel
= 8;
1740 case VLC_CODEC_D3D11_OPAQUE_10B
:
1741 bits_per_channel
= 10;
1745 const vlc_chroma_description_t
*p_format
= vlc_fourcc_GetChromaDescription(fmt
->i_chroma
);
1746 bits_per_channel
= p_format
== NULL
|| p_format
->pixel_bits
== 0 ? 8 : p_format
->pixel_bits
;
1751 sys
->picQuadConfig
= GetDisplayFormatByDepth(vd
, bits_per_channel
, decoder_format
!=NULL
);
1754 // look for any pixel format that we can handle
1755 if ( !sys
->picQuadConfig
)
1756 sys
->picQuadConfig
= GetDisplayFormatByDepth(vd
, 0, false);
1758 if ( !sys
->picQuadConfig
)
1760 msg_Err(vd
, "Could not get a suitable texture pixel format");
1761 return VLC_EGENERIC
;
1764 fmt
->i_chroma
= sys
->picQuadConfig
->fourcc
;
1766 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", sys
->picQuadConfig
->name
,
1767 (char *)&fmt
->i_chroma
);
1768 DxgiFormatMask( sys
->picQuadConfig
->formatTexture
, fmt
);
1770 /* check the region pixel format */
1771 sys
->d3dregion_format
= GetBlendableFormat(vd
, VLC_CODEC_RGBA
);
1772 if (!sys
->d3dregion_format
)
1773 sys
->d3dregion_format
= GetBlendableFormat(vd
, VLC_CODEC_BGRA
);
1775 sys
->picQuad
.i_width
= fmt
->i_width
;
1776 sys
->picQuad
.i_height
= fmt
->i_height
;
1777 if (is_d3d11_opaque(fmt
->i_chroma
))
1779 /* worst case scenario we need 128 alignment for HEVC */
1780 sys
->picQuad
.i_width
= (sys
->picQuad
.i_width
+ 0x7F) & ~0x7F;
1781 sys
->picQuad
.i_height
= (sys
->picQuad
.i_height
+ 0x7F) & ~0x7F;
1783 else if ( sys
->picQuadConfig
->formatTexture
!= DXGI_FORMAT_R8G8B8A8_UNORM
&&
1784 sys
->picQuadConfig
->formatTexture
!= DXGI_FORMAT_B5G6R5_UNORM
)
1786 sys
->picQuad
.i_width
= (sys
->picQuad
.i_width
+ 0x01) & ~0x01;
1787 sys
->picQuad
.i_height
= (sys
->picQuad
.i_height
+ 0x01) & ~0x01;
1790 BEFORE_UPDATE_RECTS
;
1791 UpdateRects(vd
, NULL
, true);
1794 #if defined(HAVE_ID3D11VIDEODECODER)
1795 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1797 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1800 if (Direct3D11CreateResources(vd
, fmt
)) {
1801 #if defined(HAVE_ID3D11VIDEODECODER)
1802 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1804 ReleaseMutex( sys
->context_lock
);
1807 msg_Err(vd
, "Failed to allocate resources");
1808 Direct3D11DestroyResources(vd
);
1809 return VLC_EGENERIC
;
1811 #if defined(HAVE_ID3D11VIDEODECODER)
1812 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1814 ReleaseMutex( sys
->context_lock
);
1818 #if !VLC_WINSTORE_APP
1819 EventThreadUpdateTitle(sys
->sys
.event
, VOUT_TITLE
" (Direct3D11 output)");
1822 msg_Dbg(vd
, "Direct3D11 device adapter successfully initialized");
1826 static void Direct3D11Close(vout_display_t
*vd
)
1828 vout_display_sys_t
*sys
= vd
->sys
;
1830 Direct3D11DestroyResources(vd
);
1831 if (sys
->d3dcontext
)
1833 ID3D11DeviceContext_Flush(sys
->d3dcontext
);
1834 ID3D11DeviceContext_Release(sys
->d3dcontext
);
1835 sys
->d3dcontext
= NULL
;
1839 ID3D11Device_Release(sys
->d3ddevice
);
1840 sys
->d3ddevice
= NULL
;
1842 if (sys
->dxgiswapChain4
)
1844 IDXGISwapChain_Release(sys
->dxgiswapChain4
);
1845 sys
->dxgiswapChain4
= NULL
;
1847 if (sys
->dxgiswapChain
)
1849 IDXGISwapChain_Release(sys
->dxgiswapChain
);
1850 sys
->dxgiswapChain
= NULL
;
1853 msg_Dbg(vd
, "Direct3D11 device adapter closed");
1856 static void UpdatePicQuadPosition(vout_display_t
*vd
)
1858 vout_display_sys_t
*sys
= vd
->sys
;
1860 sys
->picQuad
.cropViewport
.Width
= RECTWidth(sys
->sys
.rect_dest_clipped
);
1861 sys
->picQuad
.cropViewport
.Height
= RECTHeight(sys
->sys
.rect_dest_clipped
);
1862 sys
->picQuad
.cropViewport
.TopLeftX
= sys
->sys
.rect_dest_clipped
.left
;
1863 sys
->picQuad
.cropViewport
.TopLeftY
= sys
->sys
.rect_dest_clipped
.top
;
1865 sys
->picQuad
.cropViewport
.MinDepth
= 0.0f
;
1866 sys
->picQuad
.cropViewport
.MaxDepth
= 1.0f
;
1868 SetQuadVSProjection(vd
, &sys
->picQuad
, &vd
->cfg
->viewpoint
);
1871 msg_Dbg(vd
, "picQuad position (%.02f,%.02f) %.02fx%.02f", sys
->picQuad
.cropViewport
.TopLeftX
, sys
->picQuad
.cropViewport
.TopLeftY
, sys
->picQuad
.cropViewport
.Width
, sys
->picQuad
.cropViewport
.Height
);
1875 static ID3DBlob
* CompileShader(vout_display_t
*vd
, const char *psz_shader
, bool pixel
)
1877 vout_display_sys_t
*sys
= vd
->sys
;
1878 ID3DBlob
* pShaderBlob
= NULL
, *pErrBlob
;
1880 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1881 HRESULT hr
= D3DCompile(psz_shader
, strlen(psz_shader
),
1882 NULL
, NULL
, NULL
, "main",
1883 pixel
? (sys
->legacy_shader
? "ps_4_0_level_9_1" : "ps_4_0") :
1884 (sys
->legacy_shader
? "vs_4_0_level_9_1" : "vs_4_0"),
1885 0, 0, &pShaderBlob
, &pErrBlob
);
1888 char *err
= pErrBlob
? ID3D10Blob_GetBufferPointer(pErrBlob
) : NULL
;
1889 msg_Err(vd
, "invalid %s Shader (hr=0x%lX): %s", pixel
?"Pixel":"Vertex", hr
, err
);
1891 ID3D10Blob_Release(pErrBlob
);
1897 static bool IsRGBShader(const d3d_format_t
*cfg
)
1899 return cfg
->resourceFormat
[0] != DXGI_FORMAT_R8_UNORM
&&
1900 cfg
->resourceFormat
[0] != DXGI_FORMAT_R16_UNORM
&&
1901 cfg
->formatTexture
!= DXGI_FORMAT_YUY2
;
1904 static HRESULT
CompilePixelShader(vout_display_t
*vd
, const d3d_format_t
*format
,
1905 video_transfer_func_t transfer
, bool src_full_range
,
1906 ID3D11PixelShader
**output
)
1908 vout_display_sys_t
*sys
= vd
->sys
;
1910 static const char *DEFAULT_NOOP
= "return rgb";
1911 const char *psz_sampler
;
1912 const char *psz_src_transform
= DEFAULT_NOOP
;
1913 const char *psz_display_transform
= DEFAULT_NOOP
;
1914 const char *psz_tone_mapping
= DEFAULT_NOOP
;
1915 const char *psz_peak_luminance
= DEFAULT_NOOP
;
1916 const char *psz_adjust_range
= DEFAULT_NOOP
;
1917 char *psz_luminance
= NULL
;
1918 char *psz_range
= NULL
;
1920 switch (format
->formatTexture
)
1922 case DXGI_FORMAT_NV12
:
1923 case DXGI_FORMAT_P010
:
1925 "sample.x = shaderTexture[0].Sample(SampleType, In.Texture).x;\
1926 sample.yz = shaderTexture[1].Sample(SampleType, In.Texture).xy;\
1929 case DXGI_FORMAT_YUY2
:
1931 "sample.x = shaderTexture[0].Sample(SampleType, In.Texture).x;\
1932 sample.y = shaderTexture[0].Sample(SampleType, In.Texture).y;\
1933 sample.z = shaderTexture[0].Sample(SampleType, In.Texture).a;\
1936 case DXGI_FORMAT_R8G8B8A8_UNORM
:
1937 case DXGI_FORMAT_B8G8R8A8_UNORM
:
1938 case DXGI_FORMAT_B5G6R5_UNORM
:
1940 "sample = shaderTexture[0].Sample(SampleType, In.Texture);";
1942 case DXGI_FORMAT_UNKNOWN
:
1944 "sample.x = shaderTexture[0].Sample(SampleType, In.Texture).x;\
1945 sample.y = shaderTexture[1].Sample(SampleType, In.Texture).x;\
1946 sample.z = shaderTexture[2].Sample(SampleType, In.Texture).x;\
1950 vlc_assert_unreachable();
1953 video_transfer_func_t src_transfer
;
1954 unsigned src_luminance_peak
;
1957 case TRANSFER_FUNC_SMPTE_ST2084
:
1958 /* TODO ajust this value using HDR metadata ? */
1959 src_luminance_peak
= 7500;
1961 case TRANSFER_FUNC_HLG
:
1962 src_luminance_peak
= 1000;
1964 case TRANSFER_FUNC_BT709
:
1965 case TRANSFER_FUNC_SRGB
:
1966 src_luminance_peak
= DEFAULT_BRIGHTNESS
;
1969 msg_Dbg(vd
, "unhandled source transfer %d", transfer
);
1970 src_luminance_peak
= DEFAULT_BRIGHTNESS
;
1974 if (transfer
!= sys
->display
.colorspace
->transfer
)
1976 /* we need to go in linear mode */
1979 case TRANSFER_FUNC_SMPTE_ST2084
:
1980 /* ST2084 to Linear */
1983 "rgb = pow(rgb, 1.0/ST2084_m2);\
1984 rgb = max(rgb - ST2084_c1, 0.0) / (ST2084_c2 - ST2084_c3 * rgb);\
1985 rgb = pow(rgb, 1.0/ST2084_m1);\
1987 src_transfer
= TRANSFER_FUNC_LINEAR
;
1989 case TRANSFER_FUNC_HLG
:
1992 "rgb.r = inverse_HLG(rgb.r);\
1993 rgb.g = inverse_HLG(rgb.g);\
1994 rgb.b = inverse_HLG(rgb.b);\
1996 src_transfer
= TRANSFER_FUNC_LINEAR
;
1998 case TRANSFER_FUNC_BT709
:
1999 psz_src_transform
= "return pow(rgb, 1.0 / 0.45)";
2000 src_transfer
= TRANSFER_FUNC_LINEAR
;
2002 case TRANSFER_FUNC_SRGB
:
2003 psz_src_transform
= "return pow(rgb, 2.2)";
2004 src_transfer
= TRANSFER_FUNC_LINEAR
;
2007 msg_Dbg(vd
, "unhandled source transfer %d", transfer
);
2008 src_transfer
= transfer
;
2012 switch (sys
->display
.colorspace
->transfer
)
2014 case TRANSFER_FUNC_SRGB
:
2015 if (src_transfer
== TRANSFER_FUNC_LINEAR
)
2017 /* Linear to sRGB */
2018 psz_display_transform
= "return pow(rgb, 1.0 / 2.2)";
2020 if (transfer
== TRANSFER_FUNC_SMPTE_ST2084
|| transfer
== TRANSFER_FUNC_HLG
)
2022 /* HDR tone mapping */
2024 "static const float3 HABLE_DIV = hable(11.2);\
2025 rgb = hable(rgb) / HABLE_DIV;\
2030 msg_Warn(vd
, "don't know how to transfer from %d to sRGB", src_transfer
);
2033 case TRANSFER_FUNC_SMPTE_ST2084
:
2034 if (src_transfer
== TRANSFER_FUNC_LINEAR
)
2036 /* Linear to ST2084 */
2037 psz_display_transform
=
2039 "rgb = pow(rgb, ST2084_m1);\
2040 rgb = (ST2084_c1 + ST2084_c2 * rgb) / (1 + ST2084_c3 * rgb);\
2041 rgb = pow(rgb, ST2084_m2);\
2045 msg_Warn(vd
, "don't know how to transfer from %d to SMPTE ST 2084", src_transfer
);
2048 msg_Warn(vd
, "don't know how to transfer from %d to %d", src_transfer
, sys
->display
.colorspace
->transfer
);
2053 if (src_luminance_peak
!= sys
->display
.luminance_peak
)
2055 psz_luminance
= malloc(64);
2056 if (likely(psz_luminance
))
2058 sprintf(psz_luminance
, "return rgb * %f", (float)src_luminance_peak
/ (float)sys
->display
.luminance_peak
);
2059 psz_peak_luminance
= psz_luminance
;
2063 int range_adjust
= sys
->display
.colorspace
->b_full_range
;
2064 #if VLC_WINSTORE_APP
2065 if (isXboxHardware(sys
->d3ddevice
)) {
2066 /* the Xbox lies, when it says it outputs full range it's less than full range */
2070 if (!IsRGBShader(format
))
2071 range_adjust
--; /* the YUV->RGB conversion already output full range */
2075 if (range_adjust
!= 0)
2077 psz_range
= malloc(256);
2078 if (likely(psz_range
))
2080 FLOAT itu_black_level
;
2081 FLOAT itu_range_factor
;
2082 FLOAT itu_white_level
;
2083 switch (format
->bitsPerChannel
)
2086 /* Rec. ITU-R BT.709-6 §4.6 */
2087 itu_black_level
= 16.f
/ 255.f
;
2088 itu_white_level
= 235.f
/ 255.f
;
2089 itu_range_factor
= (float)(235 - 16) / 255.f
;
2092 /* Rec. ITU-R BT.709-6 §4.6 */
2093 itu_black_level
= 64.f
/ 1023.f
;
2094 itu_white_level
= 940.f
/ 1023.f
;
2095 itu_range_factor
= (float)(940 - 64) / 1023.f
;
2098 /* Rec. ITU-R BT.2020-2 Table 5 */
2099 itu_black_level
= 256.f
/ 4095.f
;
2100 itu_white_level
= 3760.f
/ 4095.f
;
2101 itu_range_factor
= (float)(3760 - 256) / 4095.f
;
2104 /* unknown bitdepth, use approximation for infinite bit depth */
2105 itu_black_level
= 16.f
/ 256.f
;
2106 itu_white_level
= 235.f
/ 256.f
;
2107 itu_range_factor
= (float)(235 - 16) / 256.f
;
2111 FLOAT black_level
= 0;
2112 FLOAT range_factor
= 1.0f
;
2113 if (range_adjust
> 0)
2115 /* expand the range from studio to full range */
2116 while (range_adjust
--)
2118 black_level
-= itu_black_level
;
2119 range_factor
/= itu_range_factor
;
2121 sprintf(psz_range
, "return max(0,min(1,(rgb + %f) * %f))",
2122 black_level
, range_factor
);
2126 /* shrink the range to studio range */
2127 while (range_adjust
++)
2129 black_level
+= itu_black_level
;
2130 range_factor
*= itu_range_factor
;
2132 sprintf(psz_range
, "return clamp(rgb + %f * %f,%f,%f)",
2133 black_level
, range_factor
, itu_black_level
, itu_white_level
);
2135 psz_adjust_range
= psz_range
;
2139 char *shader
= malloc(strlen(globPixelShaderDefault
) + 32 + strlen(psz_sampler
) +
2140 strlen(psz_src_transform
) + strlen(psz_display_transform
) +
2141 strlen(psz_tone_mapping
) + strlen(psz_peak_luminance
) + strlen(psz_adjust_range
));
2144 msg_Err(vd
, "no room for the Pixel Shader");
2145 free(psz_luminance
);
2147 return E_OUTOFMEMORY
;
2149 sprintf(shader
, globPixelShaderDefault
, sys
->legacy_shader
? "" : "Array", psz_src_transform
,
2150 psz_display_transform
, psz_tone_mapping
, psz_peak_luminance
, psz_adjust_range
, psz_sampler
);
2152 if (!IsRGBShader(format
)) {
2153 msg_Dbg(vd
,"psz_src_transform %s", psz_src_transform
);
2154 msg_Dbg(vd
,"psz_tone_mapping %s", psz_tone_mapping
);
2155 msg_Dbg(vd
,"psz_peak_luminance %s", psz_peak_luminance
);
2156 msg_Dbg(vd
,"psz_display_transform %s", psz_display_transform
);
2157 msg_Dbg(vd
,"psz_adjust_range %s", psz_adjust_range
);
2160 free(psz_luminance
);
2163 ID3DBlob
*pPSBlob
= CompileShader(vd
, shader
, true);
2166 return E_INVALIDARG
;
2168 HRESULT hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
,
2169 (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
2170 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, output
);
2172 ID3D10Blob_Release(pPSBlob
);
2176 #if (!VLC_WINSTORE_APP) && defined (HAVE_ID3D11VIDEODECODER)
2178 static HKEY
GetAdapterRegistry(DXGI_ADAPTER_DESC
*adapterDesc
)
2182 TCHAR szData
[256], lookup
[256];
2185 _sntprintf(lookup
, 256, TEXT("pci\\ven_%04x&dev_%04x&rev_cf"), adapterDesc
->VendorId
, adapterDesc
->DeviceId
);
2188 _sntprintf(key
, 128, TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\%04d"), i
);
2189 if( RegOpenKeyEx(HKEY_LOCAL_MACHINE
, key
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
2192 len
= sizeof(szData
);
2193 if( RegQueryValueEx( hKey
, TEXT("MatchingDeviceId"), NULL
, NULL
, (LPBYTE
) &szData
, &len
) == ERROR_SUCCESS
) {
2194 if (_tcscmp(lookup
, szData
) == 0)
2204 static bool CanUseTextureArray(vout_display_t
*vd
)
2206 #ifndef HAVE_ID3D11VIDEODECODER
2210 vout_display_sys_t
*sys
= vd
->sys
;
2213 IDXGIAdapter
*pAdapter
= D3D11DeviceAdapter(sys
->d3ddevice
);
2217 DXGI_ADAPTER_DESC adapterDesc
;
2218 HRESULT hr
= IDXGIAdapter_GetDesc(pAdapter
, &adapterDesc
);
2219 IDXGIAdapter_Release(pAdapter
);
2223 /* ATI/AMD hardware has issues with pixel shaders with Texture2DArray */
2224 if (adapterDesc
.VendorId
!= 0x1002)
2227 #if !VLC_WINSTORE_APP
2228 HKEY hKey
= GetAdapterRegistry(&adapterDesc
);
2232 LONG err
= RegQueryValueEx( hKey
, TEXT("DriverVersion"), NULL
, NULL
, (LPBYTE
) &szData
, &len
);
2235 if (err
== ERROR_SUCCESS
)
2237 int wddm
, d3d_features
, revision
, build
;
2238 /* see https://msdn.microsoft.com/windows/hardware/commercialize/design/compatibility/device-graphics */
2239 if (_stscanf(szData
, TEXT("%d.%d.%d.%d"), &wddm
, &d3d_features
, &revision
, &build
) == 4)
2240 /* it should be OK starting from driver 22.19.162.xxx */
2241 return wddm
> 22 || (wddm
== 22 && (d3d_features
> 19 || (d3d_features
== 19 && revision
>= 162)));
2244 msg_Dbg(vd
, "fallback to legacy shader mode for old AMD drivers");
2249 /* TODO : handle errors better
2250 TODO : seperate out into smaller functions like createshaders */
2251 static int Direct3D11CreateResources(vout_display_t
*vd
, video_format_t
*fmt
)
2253 vout_display_sys_t
*sys
= vd
->sys
;
2256 #if defined(HAVE_ID3D11VIDEODECODER)
2257 sys
->context_lock
= CreateMutexEx( NULL
, NULL
, 0, SYNCHRONIZE
);
2258 ID3D11Device_SetPrivateData( sys
->d3ddevice
, &GUID_CONTEXT_MUTEX
, sizeof( sys
->context_lock
), &sys
->context_lock
);
2261 hr
= UpdateBackBuffer(vd
);
2263 msg_Err(vd
, "Could not update the backbuffer. (hr=0x%lX)", hr
);
2264 return VLC_EGENERIC
;
2267 ID3D11BlendState
*pSpuBlendState
;
2268 D3D11_BLEND_DESC spuBlendDesc
= { 0 };
2269 spuBlendDesc
.RenderTarget
[0].BlendEnable
= TRUE
;
2270 spuBlendDesc
.RenderTarget
[0].SrcBlend
= D3D11_BLEND_SRC_ALPHA
;
2271 spuBlendDesc
.RenderTarget
[0].DestBlend
= D3D11_BLEND_INV_SRC_ALPHA
;
2272 spuBlendDesc
.RenderTarget
[0].BlendOp
= D3D11_BLEND_OP_ADD
;
2274 spuBlendDesc
.RenderTarget
[0].SrcBlendAlpha
= D3D11_BLEND_ONE
;
2275 spuBlendDesc
.RenderTarget
[0].DestBlendAlpha
= D3D11_BLEND_ZERO
;
2276 spuBlendDesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
2278 spuBlendDesc
.RenderTarget
[0].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
2280 spuBlendDesc
.RenderTarget
[1].BlendEnable
= TRUE
;
2281 spuBlendDesc
.RenderTarget
[1].SrcBlend
= D3D11_BLEND_ONE
;
2282 spuBlendDesc
.RenderTarget
[1].DestBlend
= D3D11_BLEND_ZERO
;
2283 spuBlendDesc
.RenderTarget
[1].BlendOp
= D3D11_BLEND_OP_ADD
;
2285 spuBlendDesc
.RenderTarget
[1].SrcBlendAlpha
= D3D11_BLEND_ONE
;
2286 spuBlendDesc
.RenderTarget
[1].DestBlendAlpha
= D3D11_BLEND_ZERO
;
2287 spuBlendDesc
.RenderTarget
[1].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
2289 spuBlendDesc
.RenderTarget
[1].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
2290 hr
= ID3D11Device_CreateBlendState(sys
->d3ddevice
, &spuBlendDesc
, &pSpuBlendState
);
2292 msg_Err(vd
, "Could not create SPU blend state. (hr=0x%lX)", hr
);
2293 return VLC_EGENERIC
;
2295 ID3D11DeviceContext_OMSetBlendState(sys
->d3dcontext
, pSpuBlendState
, NULL
, 0xFFFFFFFF);
2296 ID3D11BlendState_Release(pSpuBlendState
);
2298 /* disable depth testing as we're only doing 2D
2299 * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
2300 * see http://rastertek.com/dx11tut11.html
2302 D3D11_DEPTH_STENCIL_DESC stencilDesc
;
2303 ZeroMemory(&stencilDesc
, sizeof(stencilDesc
));
2305 ID3D11DepthStencilState
*pDepthStencilState
;
2306 hr
= ID3D11Device_CreateDepthStencilState(sys
->d3ddevice
, &stencilDesc
, &pDepthStencilState
);
2307 if (SUCCEEDED(hr
)) {
2308 ID3D11DeviceContext_OMSetDepthStencilState(sys
->d3dcontext
, pDepthStencilState
, 0);
2309 ID3D11DepthStencilState_Release(pDepthStencilState
);
2312 sys
->legacy_shader
= !CanUseTextureArray(vd
);
2313 vd
->info
.is_slow
= !is_d3d11_opaque(fmt
->i_chroma
) && sys
->picQuadConfig
->formatTexture
!= DXGI_FORMAT_UNKNOWN
;
2315 hr
= CompilePixelShader(vd
, sys
->picQuadConfig
, fmt
->transfer
, fmt
->b_color_range_full
, &sys
->picQuadPixelShader
);
2318 #ifdef HAVE_ID3D11VIDEODECODER
2319 if (!sys
->legacy_shader
)
2321 sys
->legacy_shader
= true;
2322 msg_Dbg(vd
, "fallback to legacy shader mode");
2323 hr
= CompilePixelShader(vd
, sys
->picQuadConfig
, fmt
->transfer
, fmt
->b_color_range_full
, &sys
->picQuadPixelShader
);
2328 msg_Err(vd
, "Failed to create the pixel shader. (hr=0x%lX)", hr
);
2329 return VLC_EGENERIC
;
2333 if (sys
->d3dregion_format
!= NULL
)
2335 hr
= CompilePixelShader(vd
, sys
->d3dregion_format
, TRANSFER_FUNC_SRGB
, true, &sys
->pSPUPixelShader
);
2338 ID3D11PixelShader_Release(sys
->picQuadPixelShader
);
2339 sys
->picQuadPixelShader
= NULL
;
2340 msg_Err(vd
, "Failed to create the SPU pixel shader. (hr=0x%lX)", hr
);
2341 return VLC_EGENERIC
;
2345 ID3DBlob
*pVSBlob
= CompileShader(vd
, globVertexShaderFlat
, false);
2347 return VLC_EGENERIC
;
2349 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
2350 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &sys
->flatVSShader
);
2353 ID3D11Device_Release(pVSBlob
);
2354 msg_Err(vd
, "Failed to create the flat vertex shader. (hr=0x%lX)", hr
);
2355 return VLC_EGENERIC
;
2358 D3D11_INPUT_ELEMENT_DESC layout
[] = {
2359 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D11_APPEND_ALIGNED_ELEMENT
, D3D11_INPUT_PER_VERTEX_DATA
, 0},
2360 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT
, 0, D3D11_APPEND_ALIGNED_ELEMENT
, D3D11_INPUT_PER_VERTEX_DATA
, 0},
2363 ID3D11InputLayout
* pVertexLayout
= NULL
;
2364 hr
= ID3D11Device_CreateInputLayout(sys
->d3ddevice
, layout
, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
2365 ID3D10Blob_GetBufferSize(pVSBlob
), &pVertexLayout
);
2367 ID3D10Blob_Release(pVSBlob
);
2370 msg_Err(vd
, "Failed to create the vertex input layout. (hr=0x%lX)", hr
);
2371 return VLC_EGENERIC
;
2373 ID3D11DeviceContext_IASetInputLayout(sys
->d3dcontext
, pVertexLayout
);
2374 ID3D11InputLayout_Release(pVertexLayout
);
2376 pVSBlob
= CompileShader(vd
, globVertexShaderProjection
, false);
2378 return VLC_EGENERIC
;
2380 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
2381 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &sys
->projectionVSShader
);
2384 ID3D11Device_Release(pVSBlob
);
2385 msg_Err(vd
, "Failed to create the projection vertex shader. (hr=0x%lX)", hr
);
2386 return VLC_EGENERIC
;
2388 ID3D10Blob_Release(pVSBlob
);
2390 ID3D11DeviceContext_IASetPrimitiveTopology(sys
->d3dcontext
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
2392 UpdatePicQuadPosition(vd
);
2394 D3D11_SAMPLER_DESC sampDesc
;
2395 memset(&sampDesc
, 0, sizeof(sampDesc
));
2396 sampDesc
.Filter
= D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
;
2397 sampDesc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
2398 sampDesc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
2399 sampDesc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
2400 sampDesc
.ComparisonFunc
= D3D11_COMPARISON_ALWAYS
;
2401 sampDesc
.MinLOD
= 0;
2402 sampDesc
.MaxLOD
= D3D11_FLOAT32_MAX
;
2404 ID3D11SamplerState
*d3dsampState
;
2405 hr
= ID3D11Device_CreateSamplerState(sys
->d3ddevice
, &sampDesc
, &d3dsampState
);
2408 msg_Err(vd
, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr
);
2409 return VLC_EGENERIC
;
2411 ID3D11DeviceContext_PSSetSamplers(sys
->d3dcontext
, 0, 1, &d3dsampState
);
2412 ID3D11SamplerState_Release(d3dsampState
);
2414 msg_Dbg(vd
, "Direct3D11 resources created");
2418 static void Direct3D11DestroyPool(vout_display_t
*vd
)
2420 vout_display_sys_t
*sys
= vd
->sys
;
2423 picture_pool_Release(sys
->sys
.pool
);
2424 sys
->sys
.pool
= NULL
;
2428 * Compute the vertex ordering needed to rotate the video. Without
2429 * rotation, the vertices of the rectangle are defined in a clockwise
2430 * order. This function computes a remapping of the coordinates to
2431 * implement the rotation, given fixed texture coordinates.
2432 * The unrotated order is the following:
2436 * For a 180 degrees rotation it should like this:
2440 * Vertex 0 should be assigned coordinates at index 2 from the
2441 * unrotated order and so on, thus yielding order: 2 3 0 1.
2443 static void orientationVertexOrder(video_orientation_t orientation
, int vertex_order
[static 4])
2445 switch (orientation
) {
2446 case ORIENT_ROTATED_90
:
2447 vertex_order
[0] = 3;
2448 vertex_order
[1] = 0;
2449 vertex_order
[2] = 1;
2450 vertex_order
[3] = 2;
2452 case ORIENT_ROTATED_270
:
2453 vertex_order
[0] = 1;
2454 vertex_order
[1] = 2;
2455 vertex_order
[2] = 3;
2456 vertex_order
[3] = 0;
2458 case ORIENT_ROTATED_180
:
2459 vertex_order
[0] = 2;
2460 vertex_order
[1] = 3;
2461 vertex_order
[2] = 0;
2462 vertex_order
[3] = 1;
2464 case ORIENT_TRANSPOSED
:
2465 vertex_order
[0] = 2;
2466 vertex_order
[1] = 1;
2467 vertex_order
[2] = 0;
2468 vertex_order
[3] = 3;
2470 case ORIENT_HFLIPPED
:
2471 vertex_order
[0] = 3;
2472 vertex_order
[1] = 2;
2473 vertex_order
[2] = 1;
2474 vertex_order
[3] = 0;
2476 case ORIENT_VFLIPPED
:
2477 vertex_order
[0] = 1;
2478 vertex_order
[1] = 0;
2479 vertex_order
[2] = 3;
2480 vertex_order
[3] = 2;
2482 case ORIENT_ANTI_TRANSPOSED
: /* transpose + vflip */
2483 vertex_order
[0] = 1;
2484 vertex_order
[1] = 2;
2485 vertex_order
[2] = 3;
2486 vertex_order
[3] = 0;
2489 vertex_order
[0] = 0;
2490 vertex_order
[1] = 1;
2491 vertex_order
[2] = 2;
2492 vertex_order
[3] = 3;
2497 static void SetupQuadFlat(d3d_vertex_t
*dst_data
, const RECT
*output
,
2498 const d3d_quad_t
*quad
,
2499 WORD
*triangle_pos
, video_orientation_t orientation
)
2501 unsigned int dst_x
= output
->left
;
2502 unsigned int dst_y
= output
->top
;
2503 unsigned int dst_width
= RECTWidth(*output
);
2504 unsigned int dst_height
= RECTHeight(*output
);
2505 unsigned int src_width
= quad
->i_width
;
2506 unsigned int src_height
= quad
->i_height
;
2507 LONG MidY
= output
->top
+ output
->bottom
; // /2
2508 LONG MidX
= output
->left
+ output
->right
; // /2
2510 /* the clamping will not work properly on the side of the texture as it
2511 * will have decoder pixels not mean to be displayed but used for interpolation
2512 * So we lose the last line that will be partially green */
2513 if (src_width
!= dst_width
)
2515 if (src_height
!= dst_height
)
2518 float top
, bottom
, left
, right
;
2519 top
= (float)MidY
/ (float)(MidY
- 2*dst_y
);
2520 bottom
= -(2.f
*src_height
- MidY
) / (float)(MidY
- 2*dst_y
);
2521 right
= (2.f
*src_width
- MidX
) / (float)(MidX
- 2*dst_x
);
2522 left
= -(float)MidX
/ (float)(MidX
- 2*dst_x
);
2524 const float vertices_coords
[4][2] = {
2531 /* Compute index remapping necessary to implement the rotation. */
2532 int vertex_order
[4];
2533 orientationVertexOrder(orientation
, vertex_order
);
2535 for (int i
= 0; i
< 4; ++i
) {
2536 dst_data
[i
].position
.x
= vertices_coords
[vertex_order
[i
]][0];
2537 dst_data
[i
].position
.y
= vertices_coords
[vertex_order
[i
]][1];
2541 dst_data
[0].position
.z
= 0.0f
;
2542 dst_data
[0].texture
.x
= 0.0f
;
2543 dst_data
[0].texture
.y
= 1.0f
;
2546 dst_data
[1].position
.z
= 0.0f
;
2547 dst_data
[1].texture
.x
= 1.0f
;
2548 dst_data
[1].texture
.y
= 1.0f
;
2551 dst_data
[2].position
.z
= 0.0f
;
2552 dst_data
[2].texture
.x
= 1.0f
;
2553 dst_data
[2].texture
.y
= 0.0f
;
2556 dst_data
[3].position
.z
= 0.0f
;
2557 dst_data
[3].texture
.x
= 0.0f
;
2558 dst_data
[3].texture
.y
= 0.0f
;
2560 triangle_pos
[0] = 3;
2561 triangle_pos
[1] = 1;
2562 triangle_pos
[2] = 0;
2564 triangle_pos
[3] = 2;
2565 triangle_pos
[4] = 1;
2566 triangle_pos
[5] = 3;
2569 #define SPHERE_SLICES 128
2570 #define nbLatBands SPHERE_SLICES
2571 #define nbLonBands SPHERE_SLICES
2573 static void SetupQuadSphere(d3d_vertex_t
*dst_data
, WORD
*triangle_pos
)
2575 for (unsigned lat
= 0; lat
<= nbLatBands
; lat
++) {
2576 float theta
= lat
* (float) M_PI
/ nbLatBands
;
2577 float sinTheta
, cosTheta
;
2579 sincosf(theta
, &sinTheta
, &cosTheta
);
2581 for (unsigned lon
= 0; lon
<= nbLonBands
; lon
++) {
2582 float phi
= lon
* 2 * (float) M_PI
/ nbLonBands
;
2583 float sinPhi
, cosPhi
;
2585 sincosf(phi
, &sinPhi
, &cosPhi
);
2587 float x
= cosPhi
* sinTheta
;
2589 float z
= sinPhi
* sinTheta
;
2591 unsigned off1
= lat
* (nbLonBands
+ 1) + lon
;
2592 dst_data
[off1
].position
.x
= SPHERE_RADIUS
* x
;
2593 dst_data
[off1
].position
.y
= SPHERE_RADIUS
* y
;
2594 dst_data
[off1
].position
.z
= SPHERE_RADIUS
* z
;
2596 dst_data
[off1
].texture
.x
= lon
/ (float) nbLonBands
; // 0(left) to 1(right)
2597 dst_data
[off1
].texture
.y
= lat
/ (float) nbLatBands
; // 0(top) to 1 (bottom)
2601 for (unsigned lat
= 0; lat
< nbLatBands
; lat
++) {
2602 for (unsigned lon
= 0; lon
< nbLonBands
; lon
++) {
2603 unsigned first
= (lat
* (nbLonBands
+ 1)) + lon
;
2604 unsigned second
= first
+ nbLonBands
+ 1;
2606 unsigned off
= (lat
* nbLatBands
+ lon
) * 3 * 2;
2608 triangle_pos
[off
] = first
;
2609 triangle_pos
[off
+ 1] = first
+ 1;
2610 triangle_pos
[off
+ 2] = second
;
2612 triangle_pos
[off
+ 3] = second
;
2613 triangle_pos
[off
+ 4] = first
+ 1;
2614 triangle_pos
[off
+ 5] = second
+ 1;
2619 static bool AllocQuadVertices(vout_display_t
*vd
, d3d_quad_t
*quad
,
2620 video_projection_mode_t projection
)
2623 vout_display_sys_t
*sys
= vd
->sys
;
2625 if (projection
== PROJECTION_MODE_RECTANGULAR
)
2627 quad
->vertexCount
= 4;
2628 quad
->indexCount
= 2 * 3;
2630 else if (projection
== PROJECTION_MODE_EQUIRECTANGULAR
)
2632 quad
->vertexCount
= (SPHERE_SLICES
+1) * (SPHERE_SLICES
+1);
2633 quad
->indexCount
= nbLatBands
* nbLonBands
* 2 * 3;
2637 msg_Warn(vd
, "Projection mode %d not handled", projection
);
2641 D3D11_BUFFER_DESC bd
;
2642 memset(&bd
, 0, sizeof(bd
));
2643 bd
.Usage
= D3D11_USAGE_DYNAMIC
;
2644 bd
.ByteWidth
= sizeof(d3d_vertex_t
) * quad
->vertexCount
;
2645 bd
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
2646 bd
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
2648 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &bd
, NULL
, &quad
->pVertexBuffer
);
2650 msg_Err(vd
, "Failed to create vertex buffer. (hr=%lX)", hr
);
2654 /* create the index of the vertices */
2655 D3D11_BUFFER_DESC quadDesc
= {
2656 .Usage
= D3D11_USAGE_DYNAMIC
,
2657 .ByteWidth
= sizeof(WORD
) * quad
->indexCount
,
2658 .BindFlags
= D3D11_BIND_INDEX_BUFFER
,
2659 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
2662 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &quadDesc
, NULL
, &quad
->pIndexBuffer
);
2664 msg_Err(vd
, "Could not create the quad indices. (hr=0x%lX)", hr
);
2671 static bool UpdateQuadPosition( vout_display_t
*vd
, d3d_quad_t
*quad
,
2673 video_projection_mode_t projection
,
2674 video_orientation_t orientation
)
2676 vout_display_sys_t
*sys
= vd
->sys
;
2678 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2680 /* create the vertices */
2681 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2683 msg_Err(vd
, "Failed to lock the vertex buffer (hr=0x%lX)", hr
);
2686 d3d_vertex_t
*dst_data
= mappedResource
.pData
;
2688 /* create the vertex indices */
2689 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2691 msg_Err(vd
, "Failed to lock the index buffer (hr=0x%lX)", hr
);
2692 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
2695 WORD
*triangle_pos
= mappedResource
.pData
;
2697 if ( projection
== PROJECTION_MODE_RECTANGULAR
)
2698 SetupQuadFlat(dst_data
, output
, quad
, triangle_pos
, orientation
);
2700 SetupQuadSphere(dst_data
, triangle_pos
);
2702 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0);
2703 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
2708 static int SetupQuad(vout_display_t
*vd
, const video_format_t
*fmt
, d3d_quad_t
*quad
,
2710 const d3d_format_t
*cfg
, ID3D11PixelShader
*d3dpixelShader
,
2711 video_projection_mode_t projection
, video_orientation_t orientation
)
2713 vout_display_sys_t
*sys
= vd
->sys
;
2715 const bool RGB_shader
= IsRGBShader(cfg
);
2717 /* pixel shader constant buffer */
2718 PS_CONSTANT_BUFFER defaultConstants
= {
2721 static_assert((sizeof(PS_CONSTANT_BUFFER
)%16)==0,"Constant buffers require 16-byte alignment");
2722 D3D11_BUFFER_DESC constantDesc
= {
2723 .Usage
= D3D11_USAGE_DYNAMIC
,
2724 .ByteWidth
= sizeof(PS_CONSTANT_BUFFER
),
2725 .BindFlags
= D3D11_BIND_CONSTANT_BUFFER
,
2726 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
2728 D3D11_SUBRESOURCE_DATA constantInit
= { .pSysMem
= &defaultConstants
};
2729 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
[0]);
2731 msg_Err(vd
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
2735 FLOAT itu_black_level
= 0.f
;
2736 FLOAT itu_achromacy
= 0.f
;
2739 switch (cfg
->bitsPerChannel
)
2742 /* Rec. ITU-R BT.709-6 §4.6 */
2743 itu_black_level
= 16.f
/ 255.f
;
2744 itu_achromacy
= 128.f
/ 255.f
;
2747 /* Rec. ITU-R BT.709-6 §4.6 */
2748 itu_black_level
= 64.f
/ 1023.f
;
2749 itu_achromacy
= 512.f
/ 1023.f
;
2752 /* Rec. ITU-R BT.2020-2 Table 5 */
2753 itu_black_level
= 256.f
/ 4095.f
;
2754 itu_achromacy
= 2048.f
/ 4095.f
;
2757 /* unknown bitdepth, use approximation for infinite bit depth */
2758 itu_black_level
= 16.f
/ 256.f
;
2759 itu_achromacy
= 128.f
/ 256.f
;
2764 static const FLOAT IDENTITY_4X4
[4 * 4] = {
2771 /* matrices for studio range */
2772 /* see https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion, in studio range */
2773 static const FLOAT COLORSPACE_BT601_TO_FULL
[4*4] = {
2774 1.164383561643836f
, 0.f
, 1.596026785714286f
, 0.f
,
2775 1.164383561643836f
, -0.391762290094914f
, -0.812967647237771f
, 0.f
,
2776 1.164383561643836f
, 2.017232142857142f
, 0.f
, 0.f
,
2779 /* see https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion, in studio range */
2780 static const FLOAT COLORSPACE_BT709_TO_FULL
[4*4] = {
2781 1.164383561643836f
, 0.f
, 1.792741071428571f
, 0.f
,
2782 1.164383561643836f
, -0.213248614273730f
, -0.532909328559444f
, 0.f
,
2783 1.164383561643836f
, 2.112401785714286f
, 0.f
, 0.f
,
2786 /* see https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion, in studio range */
2787 static const FLOAT COLORSPACE_BT2020_TO_FULL
[4*4] = {
2788 1.164383561643836f
, 0.000000000000f
, 1.678674107143f
, 0.f
,
2789 1.164383561643836f
, -0.127007098661f
, -0.440987687946f
, 0.f
,
2790 1.164383561643836f
, 2.141772321429f
, 0.000000000000f
, 0.f
,
2794 PS_COLOR_TRANSFORM colorspace
;
2796 memcpy(colorspace
.WhitePoint
, IDENTITY_4X4
, sizeof(colorspace
.WhitePoint
));
2798 const FLOAT
*ppColorspace
;
2800 ppColorspace
= IDENTITY_4X4
;
2802 switch (fmt
->space
){
2803 case COLOR_SPACE_BT709
:
2804 ppColorspace
= COLORSPACE_BT709_TO_FULL
;
2806 case COLOR_SPACE_BT2020
:
2807 ppColorspace
= COLORSPACE_BT2020_TO_FULL
;
2809 case COLOR_SPACE_BT601
:
2810 ppColorspace
= COLORSPACE_BT601_TO_FULL
;
2813 case COLOR_SPACE_UNDEF
:
2814 if( fmt
->i_height
> 576 )
2815 ppColorspace
= COLORSPACE_BT709_TO_FULL
;
2817 ppColorspace
= COLORSPACE_BT601_TO_FULL
;
2820 /* all matrices work in studio range and output in full range */
2821 colorspace
.WhitePoint
[0*4 + 3] = -itu_black_level
;
2822 colorspace
.WhitePoint
[1*4 + 3] = -itu_achromacy
;
2823 colorspace
.WhitePoint
[2*4 + 3] = -itu_achromacy
;
2826 memcpy(colorspace
.Colorspace
, ppColorspace
, sizeof(colorspace
.Colorspace
));
2828 constantInit
.pSysMem
= &colorspace
;
2830 static_assert((sizeof(PS_COLOR_TRANSFORM
)%16)==0,"Constant buffers require 16-byte alignment");
2831 constantDesc
.ByteWidth
= sizeof(PS_COLOR_TRANSFORM
);
2832 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
[1]);
2834 msg_Err(vd
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
2837 quad
->PSConstantsCount
= 2;
2839 /* vertex shader constant buffer */
2840 if ( projection
== PROJECTION_MODE_EQUIRECTANGULAR
)
2842 constantDesc
.ByteWidth
= sizeof(VS_PROJECTION_CONST
);
2843 static_assert((sizeof(VS_PROJECTION_CONST
)%16)==0,"Constant buffers require 16-byte alignment");
2844 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, NULL
, &quad
->pVertexShaderConstants
);
2846 msg_Err(vd
, "Could not create the vertex shader constant buffer. (hr=0x%lX)", hr
);
2850 SetQuadVSProjection( vd
, quad
, &vd
->cfg
->viewpoint
);
2853 quad
->picSys
.formatTexture
= cfg
->formatTexture
;
2854 quad
->picSys
.context
= sys
->d3dcontext
;
2855 ID3D11DeviceContext_AddRef(quad
->picSys
.context
);
2857 if (!AllocQuadVertices(vd
, quad
, projection
))
2859 if (!UpdateQuadPosition(vd
, quad
, output
, projection
, orientation
))
2862 quad
->d3dpixelShader
= d3dpixelShader
;
2863 if (projection
== PROJECTION_MODE_RECTANGULAR
)
2864 quad
->d3dvertexShader
= sys
->flatVSShader
;
2866 quad
->d3dvertexShader
= sys
->projectionVSShader
;
2872 return VLC_EGENERIC
;
2875 static void ReleaseQuad(d3d_quad_t
*quad
)
2877 if (quad
->pPixelShaderConstants
[0])
2879 ID3D11Buffer_Release(quad
->pPixelShaderConstants
[0]);
2880 quad
->pPixelShaderConstants
[0] = NULL
;
2882 if (quad
->pPixelShaderConstants
[1])
2884 ID3D11Buffer_Release(quad
->pPixelShaderConstants
[1]);
2885 quad
->pPixelShaderConstants
[1] = NULL
;
2887 if (quad
->pVertexBuffer
)
2889 ID3D11Buffer_Release(quad
->pVertexBuffer
);
2890 quad
->pVertexBuffer
= NULL
;
2892 quad
->d3dvertexShader
= NULL
;
2893 if (quad
->pIndexBuffer
)
2895 ID3D11Buffer_Release(quad
->pIndexBuffer
);
2896 quad
->pIndexBuffer
= NULL
;
2898 if (quad
->pVertexShaderConstants
)
2900 ID3D11Buffer_Release(quad
->pVertexShaderConstants
);
2901 quad
->pVertexShaderConstants
= NULL
;
2903 ReleasePictureSys(&quad
->picSys
);
2906 static void Direct3D11DestroyResources(vout_display_t
*vd
)
2908 vout_display_sys_t
*sys
= vd
->sys
;
2910 Direct3D11DestroyPool(vd
);
2912 ReleaseQuad(&sys
->picQuad
);
2913 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
2914 sys
->d3dregion_count
= 0;
2916 ReleasePictureSys(&sys
->stagingSys
);
2918 if (sys
->flatVSShader
)
2920 ID3D11VertexShader_Release(sys
->flatVSShader
);
2921 sys
->flatVSShader
= NULL
;
2923 if (sys
->projectionVSShader
)
2925 ID3D11VertexShader_Release(sys
->projectionVSShader
);
2926 sys
->projectionVSShader
= NULL
;
2928 if (sys
->d3drenderTargetView
)
2930 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
2931 sys
->d3drenderTargetView
= NULL
;
2933 if (sys
->d3ddepthStencilView
)
2935 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
2936 sys
->d3ddepthStencilView
= NULL
;
2938 if (sys
->pSPUPixelShader
)
2940 ID3D11PixelShader_Release(sys
->pSPUPixelShader
);
2941 sys
->pSPUPixelShader
= NULL
;
2943 if (sys
->picQuadPixelShader
)
2945 ID3D11PixelShader_Release(sys
->picQuadPixelShader
);
2946 sys
->picQuadPixelShader
= NULL
;
2948 #if defined(HAVE_ID3D11VIDEODECODER)
2949 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
2951 CloseHandle( sys
->context_lock
);
2952 sys
->context_lock
= INVALID_HANDLE_VALUE
;
2956 msg_Dbg(vd
, "Direct3D11 resources destroyed");
2959 static void Direct3D11DeleteRegions(int count
, picture_t
**region
)
2961 for (int i
= 0; i
< count
; ++i
) {
2963 picture_Release(region
[i
]);
2969 static void DestroyPictureQuad(picture_t
*p_picture
)
2971 ReleaseQuad( (d3d_quad_t
*) p_picture
->p_sys
);
2975 static void UpdateQuadOpacity(vout_display_t
*vd
, const d3d_quad_t
*quad
, float opacity
)
2977 vout_display_sys_t
*sys
= vd
->sys
;
2978 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2980 HRESULT hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
[0], 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2981 if (SUCCEEDED(hr
)) {
2982 FLOAT
*dst_data
= mappedResource
.pData
;
2983 *dst_data
= opacity
;
2984 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
[0], 0);
2987 msg_Err(vd
, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr
);
2991 static int Direct3D11MapSubpicture(vout_display_t
*vd
, int *subpicture_region_count
,
2992 picture_t
***region
, subpicture_t
*subpicture
)
2994 vout_display_sys_t
*sys
= vd
->sys
;
2995 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2996 D3D11_TEXTURE2D_DESC texDesc
;
3000 if (sys
->d3dregion_format
== NULL
)
3001 return VLC_EGENERIC
;
3004 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
)
3007 *region
= calloc(count
, sizeof(picture_t
*));
3008 if (unlikely(*region
==NULL
))
3010 *subpicture_region_count
= count
;
3013 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
, i
++) {
3014 if (!r
->fmt
.i_width
|| !r
->fmt
.i_height
)
3015 continue; // won't render anything, keep the cache for later
3017 for (int j
= 0; j
< sys
->d3dregion_count
; j
++) {
3018 picture_t
*cache
= sys
->d3dregions
[j
];
3019 if (cache
!= NULL
&& ((d3d_quad_t
*) cache
->p_sys
)->picSys
.texture
[KNOWN_DXGI_INDEX
]) {
3020 ID3D11Texture2D_GetDesc( ((d3d_quad_t
*) cache
->p_sys
)->picSys
.texture
[KNOWN_DXGI_INDEX
], &texDesc
);
3021 if (texDesc
.Format
== sys
->d3dregion_format
->formatTexture
&&
3022 texDesc
.Width
== r
->fmt
.i_visible_width
&&
3023 texDesc
.Height
== r
->fmt
.i_visible_height
) {
3024 (*region
)[i
] = cache
;
3025 memset(&sys
->d3dregions
[j
], 0, sizeof(cache
)); // do not reuse this cached value
3031 picture_t
*quad_picture
= (*region
)[i
];
3032 if (quad_picture
== NULL
) {
3033 ID3D11Texture2D
*textures
[D3D11_MAX_SHADER_VIEW
] = {0};
3034 d3d_quad_t
*d3dquad
= calloc(1, sizeof(*d3dquad
));
3035 if (unlikely(d3dquad
==NULL
)) {
3038 if (AllocateTextures(vd
, sys
->d3dregion_format
, &r
->fmt
, 1, textures
, true)) {
3039 msg_Err(vd
, "Failed to allocate %dx%d texture for OSD",
3040 r
->fmt
.i_visible_width
, r
->fmt
.i_visible_height
);
3041 for (int i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++)
3043 ID3D11Texture2D_Release(textures
[i
]);
3048 for (unsigned plane
= 0; plane
< D3D11_MAX_SHADER_VIEW
; plane
++) {
3049 d3dquad
->picSys
.texture
[plane
] = textures
[plane
];
3051 if (AllocateShaderView(VLC_OBJECT(vd
), sys
->d3ddevice
, sys
->d3dregion_format
,
3052 d3dquad
->picSys
.texture
, 0,
3053 d3dquad
->picSys
.resourceView
)) {
3054 msg_Err(vd
, "Failed to create %dx%d shader view for OSD",
3055 r
->fmt
.i_visible_width
, r
->fmt
.i_visible_height
);
3059 d3dquad
->i_width
= r
->fmt
.i_width
;
3060 d3dquad
->i_height
= r
->fmt
.i_height
;
3062 output
.left
= r
->fmt
.i_x_offset
;
3063 output
.right
= r
->fmt
.i_x_offset
+ r
->fmt
.i_width
;
3064 output
.top
= r
->fmt
.i_y_offset
;
3065 output
.bottom
= r
->fmt
.i_y_offset
+ r
->fmt
.i_height
;
3067 err
= SetupQuad( vd
, &r
->fmt
, d3dquad
, &output
,
3068 sys
->d3dregion_format
, sys
->pSPUPixelShader
,
3069 PROJECTION_MODE_RECTANGULAR
, ORIENT_NORMAL
);
3070 if (err
!= VLC_SUCCESS
) {
3071 msg_Err(vd
, "Failed to create %dx%d quad for OSD",
3072 r
->fmt
.i_visible_width
, r
->fmt
.i_visible_height
);
3076 picture_resource_t picres
= {
3077 .p_sys
= (picture_sys_t
*) d3dquad
,
3078 .pf_destroy
= DestroyPictureQuad
,
3080 (*region
)[i
] = picture_NewFromResource(&r
->fmt
, &picres
);
3081 if ((*region
)[i
] == NULL
) {
3082 msg_Err(vd
, "Failed to create %dx%d picture for OSD",
3083 r
->fmt
.i_width
, r
->fmt
.i_height
);
3084 ReleaseQuad(d3dquad
);
3087 quad_picture
= (*region
)[i
];
3090 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, ((d3d_quad_t
*) quad_picture
->p_sys
)->picSys
.resource
[KNOWN_DXGI_INDEX
], 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
3091 if( SUCCEEDED(hr
) ) {
3092 err
= CommonUpdatePicture(quad_picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
3093 if (err
!= VLC_SUCCESS
) {
3094 msg_Err(vd
, "Failed to set the buffer on the SPU picture" );
3095 picture_Release(quad_picture
);
3099 picture_CopyPixels(quad_picture
, r
->p_picture
);
3101 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, ((d3d_quad_t
*) quad_picture
->p_sys
)->picSys
.resource
[KNOWN_DXGI_INDEX
], 0);
3103 msg_Err(vd
, "Failed to map the SPU texture (hr=0x%lX)", hr
);
3104 picture_Release(quad_picture
);
3108 d3d_quad_t
*quad
= (d3d_quad_t
*) quad_picture
->p_sys
;
3110 quad
->cropViewport
.Width
= (FLOAT
) r
->fmt
.i_visible_width
* RECTWidth(sys
->sys
.rect_dest
) / subpicture
->i_original_picture_width
;
3111 quad
->cropViewport
.Height
= (FLOAT
) r
->fmt
.i_visible_height
* RECTHeight(sys
->sys
.rect_dest
) / subpicture
->i_original_picture_height
;
3112 quad
->cropViewport
.MinDepth
= 0.0f
;
3113 quad
->cropViewport
.MaxDepth
= 1.0f
;
3114 quad
->cropViewport
.TopLeftX
= sys
->sys
.rect_dest
.left
+ (FLOAT
) r
->i_x
* RECTWidth(sys
->sys
.rect_dest
) / subpicture
->i_original_picture_width
;
3115 quad
->cropViewport
.TopLeftY
= sys
->sys
.rect_dest
.top
+ (FLOAT
) r
->i_y
* RECTHeight(sys
->sys
.rect_dest
) / subpicture
->i_original_picture_height
;
3117 UpdateQuadOpacity(vd
, quad
, r
->i_alpha
/ 255.0f
);