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 < 0x601
26 # define _WIN32_WINNT 0x601
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout_display.h>
43 /* avoided until we can pass ISwapchainPanel without c++/cx mode
44 # include <windows.ui.xaml.media.dxinterop.h> */
48 #include "../../video_chroma/dxgi_fmt.h"
52 # define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
54 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
56 # define D3DCompile(args...) sys->OurD3DCompile(args)
59 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH
, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
60 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT
, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
61 DEFINE_GUID(GUID_CONTEXT_MUTEX
, 0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
63 static int Open(vlc_object_t
*);
64 static void Close(vlc_object_t
*);
66 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
67 #define HW_BLENDING_TEXT N_("Use hardware blending support")
68 #define HW_BLENDING_LONGTEXT N_(\
69 "Try to use hardware acceleration for subtitle/OSD blending.")
72 set_shortname("Direct3D11")
73 set_description(N_("Direct3D11 video output"))
75 set_category(CAT_VIDEO
)
76 set_subcategory(SUBCAT_VIDEO_VOUT
)
78 add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT
, HW_BLENDING_LONGTEXT
, true)
81 add_integer("winrt-d3ddevice", 0x0, NULL
, NULL
, true); /* ID3D11Device* */
82 add_integer("winrt-d3dcontext", 0x0, NULL
, NULL
, true); /* ID3D11DeviceContext* */
83 add_integer("winrt-swapchain", 0x0, NULL
, NULL
, true); /* IDXGISwapChain1* */
86 set_capability("vout display", 240)
87 add_shortcut("direct3d11")
88 set_callbacks(Open
, Close
)
91 #ifdef HAVE_ID3D11VIDEODECODER
92 /* VLC_CODEC_D3D11_OPAQUE */
95 ID3D11VideoDecoderOutputView
*decoder
; /* may be NULL for pictures from the pool */
96 ID3D11Texture2D
*texture
;
97 ID3D11DeviceContext
*context
;
102 /* internal picture_t pool */
105 ID3D11Texture2D
*texture
;
107 } picture_sys_pool_t
;
109 /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
110 typedef struct d3d_vertex_t
{
123 #define RECTWidth(r) (int)((r).right - (r).left)
124 #define RECTHeight(r) (int)((r).bottom - (r).top)
126 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
);
128 static void Prepare(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
129 static void Display(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
131 static HINSTANCE
Direct3D11LoadShaderLibrary(void);
132 static void Direct3D11Destroy(vout_display_t
*);
134 static int Direct3D11Open (vout_display_t
*, video_format_t
*);
135 static void Direct3D11Close(vout_display_t
*);
137 static int Direct3D11CreateResources (vout_display_t
*, video_format_t
*);
138 static void Direct3D11DestroyResources(vout_display_t
*);
140 static int Direct3D11CreatePool (vout_display_t
*, video_format_t
*);
141 static void Direct3D11DestroyPool(vout_display_t
*);
143 static void DestroyDisplayPicture(picture_t
*);
144 static void DestroyDisplayPoolPicture(picture_t
*);
145 static int Direct3D11MapTexture(picture_t
*);
146 static int Direct3D11UnmapTexture(picture_t
*);
147 static void Direct3D11DeleteRegions(int, picture_t
**);
148 static int Direct3D11MapSubpicture(vout_display_t
*, int *, picture_t
***, subpicture_t
*);
150 static int AllocQuad(vout_display_t
*, const video_format_t
*, d3d_quad_t
*,
151 d3d_quad_cfg_t
*, ID3D11PixelShader
*, bool b_visible
);
152 static void ReleaseQuad(d3d_quad_t
*);
153 static void UpdatePicQuadPosition(vout_display_t
*);
154 static void UpdateQuadOpacity(vout_display_t
*, const d3d_quad_t
*, float);
156 static int Control(vout_display_t
*vd
, int query
, va_list args
);
157 static void Manage(vout_display_t
*vd
);
159 /* All the #if USE_DXGI contain an alternative method to setup dx11
160 They both need to be benchmarked to see which performs better */
162 /* I have no idea why MS decided dxgi headers do not define this
163 As they do have prototypes for d3d11 functions */
164 typedef HRESULT(WINAPI
*PFN_CREATE_DXGI_FACTORY
)(REFIID riid
, void **ppFactory
);
167 /* TODO: Move to a direct3d11_shaders header */
168 static const char* globVertexShaderDefault
= "\
171 float4 Position : POSITION;\
172 float2 Texture : TEXCOORD0;\
173 float Opacity : OPACITY;\
178 float4 Position : SV_POSITION;\
179 float2 Texture : TEXCOORD0;\
180 float Opacity : OPACITY;\
183 VS_OUTPUT VS( VS_INPUT In )\
186 Output.Position = In.Position;\
187 Output.Texture = In.Texture;\
188 Output.Opacity = In.Opacity;\
193 static const char* globPixelShaderDefault
= "\
194 Texture2D shaderTexture;\
195 SamplerState SampleType;\
199 float4 Position : SV_POSITION;\
200 float2 Texture : TEXCOORD0;\
201 float Opacity : OPACITY;\
204 float4 PS( PS_INPUT In ) : SV_TARGET\
208 rgba = shaderTexture.Sample(SampleType, In.Texture);\
209 rgba.a = rgba.a * In.Opacity;\
214 static const char *globPixelShaderBiplanarYUV_BT601_2RGB
= "\
215 Texture2D shaderTextureY;\
216 Texture2D shaderTextureUV;\
217 SamplerState SampleType;\
221 float4 Position : SV_POSITION;\
222 float2 Texture : TEXCOORD0;\
223 float Opacity : OPACITY;\
226 float4 PS( PS_INPUT In ) : SV_TARGET\
230 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
231 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
232 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
233 yuv.y = yuv.y - 0.5;\
234 yuv.z = yuv.z - 0.5;\
235 rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
236 rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
237 rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
238 rgba.a = In.Opacity;\
243 static const char *globPixelShaderBiplanarYUV_BT709_2RGB
= "\
244 Texture2D shaderTextureY;\
245 Texture2D shaderTextureUV;\
246 SamplerState SampleType;\
250 float4 Position : SV_POSITION;\
251 float2 Texture : TEXCOORD0;\
252 float Opacity : OPACITY;\
255 float4 PS( PS_INPUT In ) : SV_TARGET\
259 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
260 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
261 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
262 yuv.y = yuv.y - 0.5;\
263 yuv.z = yuv.z - 0.5;\
264 rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
265 rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
266 rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
267 rgba.a = In.Opacity;\
272 /* RGB-709 to RGB-2020 based on https://www.researchgate.net/publication/258434326_Beyond_BT709 */
273 static const char *globPixelShaderBiplanarYUV_BT2020_2RGB
= "\
274 Texture2D shaderTextureY;\
275 Texture2D shaderTextureUV;\
276 SamplerState SampleType;\
280 float4 Position : SV_POSITION;\
281 float2 Texture : TEXCOORD0;\
282 float Opacity : OPACITY;\
285 float4 PS( PS_INPUT In ) : SV_TARGET\
289 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
290 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
291 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
292 yuv.y = yuv.y - 0.5;\
293 yuv.z = yuv.z - 0.5;\
294 rgba.x = yuv.x + 1.792741071428571 * yuv.z;\
295 rgba.y = yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y;\
296 rgba.z = yuv.x + 2.112401785714286 * yuv.y;\
297 rgba.x = saturate( 1.661 * rgba.x - 0.588 * rgba.y - 0.073 * rgba.z);\
298 rgba.y = saturate(-0.125 * rgba.x + 1.133 * rgba.y - 0.008 * rgba.z);\
299 rgba.z = saturate(-0.018 * rgba.x - 0.101 * rgba.y + 1.119 * rgba.z);\
300 rgba.a = In.Opacity;\
305 static const char *globPixelShaderBiplanarYUYV_BT709_2RGB
= "\
306 Texture2D shaderTextureYUYV;\
307 SamplerState SampleType;\
311 float4 Position : SV_POSITION;\
312 float2 Texture : TEXCOORD0;\
313 float Opacity : OPACITY;\
316 float4 PS( PS_INPUT In ) : SV_TARGET\
320 yuv.x = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
321 yuv.y = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
322 yuv.z = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
323 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
324 yuv.y = yuv.y - 0.5;\
325 yuv.z = yuv.z - 0.5;\
326 rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
327 rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
328 rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
329 rgba.a = In.Opacity;\
334 static const char *globPixelShaderBiplanarYUYV_BT601_2RGB
= "\
335 Texture2D shaderTextureYUYV;\
336 SamplerState SampleType;\
340 float4 Position : SV_POSITION;\
341 float2 Texture : TEXCOORD0;\
342 float Opacity : OPACITY;\
345 float4 PS( PS_INPUT In ) : SV_TARGET\
349 yuv.x = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
350 yuv.y = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
351 yuv.z = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
352 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
353 yuv.y = yuv.y - 0.5;\
354 yuv.z = yuv.z - 0.5;\
355 rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
356 rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
357 rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
358 rgba.a = In.Opacity;\
363 #if !VLC_WINSTORE_APP
364 static int OpenHwnd(vout_display_t
*vd
)
366 HINSTANCE hd3d11_dll
= LoadLibrary(TEXT("D3D11.DLL"));
368 msg_Warn(vd
, "cannot load d3d11.dll, aborting");
372 HINSTANCE hd3dcompiler_dll
= Direct3D11LoadShaderLibrary();
373 if (!hd3dcompiler_dll
) {
374 msg_Err(vd
, "cannot load d3dcompiler.dll, aborting");
375 Direct3D11Destroy(vd
);
380 HINSTANCE hdxgi_dll
= LoadLibrary(TEXT("DXGI.DLL"));
382 msg_Warn(vd
, "cannot load dxgi.dll, aborting");
383 Direct3D11Destroy(vd
);
388 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
392 sys
->hd3d11_dll
= hd3d11_dll
;
393 sys
->hd3dcompiler_dll
= hd3dcompiler_dll
;
395 sys
->OurD3DCompile
= (void *)GetProcAddress(sys
->hd3dcompiler_dll
, "D3DCompile");
396 if (!sys
->OurD3DCompile
) {
397 msg_Err(vd
, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
398 Direct3D11Destroy(vd
);
403 sys
->hdxgi_dll
= hdxgi_dll
;
405 /* TODO : enable all dxgi versions from 1.3 -> 1.1 */
406 PFN_CREATE_DXGI_FACTORY OurCreateDXGIFactory
=
407 (void *)GetProcAddress(hdxgi_dll
, "CreateDXGIFactory");
408 if (!OurCreateDXGIFactory
) {
409 msg_Err(vd
, "Cannot locate reference to CreateDXGIFactory in dxgi DLL");
410 Direct3D11Destroy(vd
);
414 UINT i_factory_flags
= 0;
416 i_factory_flags
|= DXGI_CREATE_FACTORY_DEBUG
;
419 /* TODO : detect the directx version supported and use IID_IDXGIFactory3 or 2 */
420 HRESULT hr
= OurCreateDXGIFactory(&IID_IDXGIFactory2
, (void **)&sys
->dxgifactory
);
422 msg_Err(vd
, "Could not create dxgi factory. (hr=0x%lX)", hr
);
423 Direct3D11Destroy(vd
);
427 sys
->OurD3D11CreateDeviceAndSwapChain
=
428 (void *)GetProcAddress(hd3d11_dll
, "D3D11CreateDeviceAndSwapChain");
429 if (!sys
->OurD3D11CreateDeviceAndSwapChain
) {
430 msg_Err(vd
, "Cannot locate reference to D3D11CreateDeviceAndSwapChain in d3d11 DLL");
431 Direct3D11Destroy(vd
);
436 sys
->OurD3D11CreateDevice
=
437 (void *)GetProcAddress(hd3d11_dll
, "D3D11CreateDevice");
438 if (!sys
->OurD3D11CreateDevice
) {
439 msg_Err(vd
, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
440 Direct3D11Destroy(vd
);
447 static int OpenCoreW(vout_display_t
*vd
)
449 IDXGISwapChain1
* dxgiswapChain
= var_InheritInteger(vd
, "winrt-swapchain");
452 ID3D11Device
* d3ddevice
= var_InheritInteger(vd
, "winrt-d3ddevice");
455 ID3D11DeviceContext
* d3dcontext
= var_InheritInteger(vd
, "winrt-d3dcontext");
459 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
463 sys
->dxgiswapChain
= dxgiswapChain
;
464 sys
->d3ddevice
= d3ddevice
;
465 sys
->d3dcontext
= d3dcontext
;
466 IDXGISwapChain_AddRef (sys
->dxgiswapChain
);
467 ID3D11Device_AddRef (sys
->d3ddevice
);
468 ID3D11DeviceContext_AddRef(sys
->d3dcontext
);
474 static bool is_d3d11_opaque(vlc_fourcc_t chroma
)
478 case VLC_CODEC_D3D11_OPAQUE
:
479 case VLC_CODEC_D3D11_OPAQUE_10B
:
486 static int Open(vlc_object_t
*object
)
488 vout_display_t
*vd
= (vout_display_t
*)object
;
490 #if !VLC_WINSTORE_APP
491 int ret
= OpenHwnd(vd
);
493 int ret
= OpenCoreW(vd
);
496 if (ret
!= VLC_SUCCESS
)
503 if (Direct3D11Open(vd
, &fmt
)) {
504 msg_Err(vd
, "Direct3D11 could not be opened");
508 vout_display_info_t info
= vd
->info
;
509 info
.is_slow
= !is_d3d11_opaque(fmt
.i_chroma
);
510 info
.has_double_click
= true;
511 info
.has_hide_mouse
= false;
512 info
.has_event_thread
= true;
513 info
.has_pictures_invalid
= !is_d3d11_opaque(fmt
.i_chroma
);
515 if (var_InheritBool(vd
, "direct3d11-hw-blending") &&
516 vd
->sys
->d3dregion_format
!= DXGI_FORMAT_UNKNOWN
)
517 info
.subpicture_chromas
= vd
->sys
->pSubpictureChromas
;
519 info
.subpicture_chromas
= NULL
;
521 video_format_Clean(&vd
->fmt
);
522 video_format_Copy(&vd
->fmt
, &fmt
);
526 vd
->prepare
= Prepare
;
527 vd
->display
= Display
;
528 vd
->control
= Control
;
531 msg_Dbg(vd
, "Direct3D11 Open Succeeded");
540 static void Close(vlc_object_t
*object
)
542 vout_display_t
* vd
= (vout_display_t
*)object
;
546 Direct3D11Destroy(vd
);
550 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned pool_size
)
552 if ( vd
->sys
->pool
!= NULL
)
553 return vd
->sys
->pool
;
555 #ifdef HAVE_ID3D11VIDEODECODER
556 picture_t
** pictures
= NULL
;
557 unsigned picture_count
= 0;
560 ID3D10Multithread
*pMultithread
;
561 hr
= ID3D11Device_QueryInterface( vd
->sys
->d3ddevice
, &IID_ID3D10Multithread
, (void **)&pMultithread
);
563 ID3D10Multithread_SetMultithreadProtected(pMultithread
, TRUE
);
564 ID3D10Multithread_Release(pMultithread
);
567 pictures
= calloc(pool_size
, sizeof(*pictures
));
571 D3D11_TEXTURE2D_DESC texDesc
;
572 ZeroMemory(&texDesc
, sizeof(texDesc
));
573 texDesc
.Width
= vd
->fmt
.i_width
;
574 texDesc
.Height
= vd
->fmt
.i_height
;
575 texDesc
.MipLevels
= 1;
576 texDesc
.Format
= vd
->sys
->picQuadConfig
.textureFormat
;
577 texDesc
.SampleDesc
.Count
= 1;
578 texDesc
.MiscFlags
= 0; //D3D11_RESOURCE_MISC_SHARED;
579 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
580 texDesc
.BindFlags
= D3D11_BIND_DECODER
;
581 texDesc
.CPUAccessFlags
= 0;
583 texDesc
.ArraySize
= pool_size
;
585 ID3D11Texture2D
*texture
;
586 hr
= ID3D11Device_CreateTexture2D( vd
->sys
->d3ddevice
, &texDesc
, NULL
, &texture
);
588 msg_Err(vd
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
592 for (picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
593 picture_sys_t
*picsys
= calloc(1, sizeof(*picsys
));
594 if (unlikely(picsys
== NULL
))
597 ID3D11Texture2D_AddRef(texture
);
598 picsys
->texture
= texture
;
599 picsys
->slice_index
= picture_count
;
600 picsys
->context
= vd
->sys
->d3dcontext
;
602 picture_resource_t resource
= {
604 .pf_destroy
= DestroyDisplayPoolPicture
,
607 picture_t
*picture
= picture_NewFromResource(&vd
->fmt
, &resource
);
608 if (unlikely(picture
== NULL
)) {
610 msg_Err( vd
, "Failed to create picture %d in the pool.", picture_count
);
614 pictures
[picture_count
] = picture
;
615 /* each picture_t holds a ref to the context and release it on Destroy */
616 ID3D11DeviceContext_AddRef(picsys
->context
);
618 ID3D11Texture2D_Release(texture
);
620 msg_Dbg(vd
, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d) texture 0x%p context 0x%p",
621 pool_size
, vd
->fmt
.i_width
, vd
->fmt
.i_height
, texture
, vd
->sys
->d3dcontext
);
623 picture_pool_configuration_t pool_cfg
;
624 memset(&pool_cfg
, 0, sizeof(pool_cfg
));
625 pool_cfg
.picture_count
= pool_size
;
626 pool_cfg
.picture
= pictures
;
628 vd
->sys
->pool
= picture_pool_NewExtended( &pool_cfg
);
631 if (vd
->sys
->pool
==NULL
&& pictures
) {
632 msg_Dbg(vd
, "Failed to create the picture d3d11 pool");
633 for (unsigned i
=0;i
<picture_count
; ++i
)
634 DestroyDisplayPoolPicture(pictures
[i
]);
637 /* create an empty pool to avoid crashing */
638 picture_pool_configuration_t pool_cfg
;
639 memset( &pool_cfg
, 0, sizeof( pool_cfg
) );
640 pool_cfg
.picture_count
= 0;
642 vd
->sys
->pool
= picture_pool_NewExtended( &pool_cfg
);
645 return vd
->sys
->pool
;
648 #ifdef HAVE_ID3D11VIDEODECODER
649 static void DestroyDisplayPoolPicture(picture_t
*picture
)
651 picture_sys_t
*p_sys
= (picture_sys_t
*) picture
->p_sys
;
654 ID3D11Texture2D_Release(p_sys
->texture
);
656 ID3D11DeviceContext_Release(p_sys
->context
);
663 static void DestroyDisplayPicture(picture_t
*picture
)
665 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*) picture
->p_sys
;
668 ID3D11Texture2D_Release(p_sys
->texture
);
674 static HRESULT
UpdateBackBuffer(vout_display_t
*vd
)
676 vout_display_sys_t
*sys
= vd
->sys
;
678 ID3D11Texture2D
* pDepthStencil
;
679 ID3D11Texture2D
* pBackBuffer
;
680 uint32_t i_width
= RECTWidth(sys
->rect_dest_clipped
);
681 uint32_t i_height
= RECTHeight(sys
->rect_dest_clipped
);
683 UINT dataSize
= sizeof(i_width
);
684 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_WIDTH
, &dataSize
, &i_width
);
686 msg_Err(vd
, "Can't get swapchain width, size %d. (hr=0x%lX)", hr
, dataSize
);
689 dataSize
= sizeof(i_height
);
690 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_HEIGHT
, &dataSize
, &i_height
);
692 msg_Err(vd
, "Can't get swapchain height, size %d. (hr=0x%lX)", hr
, dataSize
);
697 if (sys
->d3drenderTargetView
) {
698 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
699 sys
->d3drenderTargetView
= NULL
;
701 if (sys
->d3ddepthStencilView
) {
702 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
703 sys
->d3ddepthStencilView
= NULL
;
706 hr
= IDXGISwapChain_ResizeBuffers(sys
->dxgiswapChain
, 0, i_width
, i_height
,
707 DXGI_FORMAT_UNKNOWN
, 0);
709 msg_Err(vd
, "Failed to resize the backbuffer. (hr=0x%lX)", hr
);
713 hr
= IDXGISwapChain_GetBuffer(sys
->dxgiswapChain
, 0, &IID_ID3D11Texture2D
, (LPVOID
*)&pBackBuffer
);
715 msg_Err(vd
, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr
);
719 hr
= ID3D11Device_CreateRenderTargetView(sys
->d3ddevice
, (ID3D11Resource
*)pBackBuffer
, NULL
, &sys
->d3drenderTargetView
);
720 ID3D11Texture2D_Release(pBackBuffer
);
722 msg_Err(vd
, "Failed to create the target view. (hr=0x%lX)", hr
);
726 D3D11_TEXTURE2D_DESC deptTexDesc
;
727 memset(&deptTexDesc
, 0,sizeof(deptTexDesc
));
728 deptTexDesc
.ArraySize
= 1;
729 deptTexDesc
.BindFlags
= D3D11_BIND_DEPTH_STENCIL
;
730 deptTexDesc
.CPUAccessFlags
= 0;
731 deptTexDesc
.Format
= DXGI_FORMAT_D24_UNORM_S8_UINT
;
732 deptTexDesc
.Width
= i_width
;
733 deptTexDesc
.Height
= i_height
;
734 deptTexDesc
.MipLevels
= 1;
735 deptTexDesc
.MiscFlags
= 0;
736 deptTexDesc
.SampleDesc
.Count
= 1;
737 deptTexDesc
.SampleDesc
.Quality
= 0;
738 deptTexDesc
.Usage
= D3D11_USAGE_DEFAULT
;
740 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &deptTexDesc
, NULL
, &pDepthStencil
);
742 msg_Err(vd
, "Could not create the depth stencil texture. (hr=0x%lX)", hr
);
746 D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc
;
747 memset(&depthViewDesc
, 0, sizeof(depthViewDesc
));
749 depthViewDesc
.Format
= deptTexDesc
.Format
;
750 depthViewDesc
.ViewDimension
= D3D11_DSV_DIMENSION_TEXTURE2D
;
751 depthViewDesc
.Texture2D
.MipSlice
= 0;
753 hr
= ID3D11Device_CreateDepthStencilView(sys
->d3ddevice
, (ID3D11Resource
*)pDepthStencil
, &depthViewDesc
, &sys
->d3ddepthStencilView
);
754 ID3D11Texture2D_Release(pDepthStencil
);
757 msg_Err(vd
, "Could not create the depth stencil view. (hr=0x%lX)", hr
);
764 static void CropStagingFormat(vout_display_t
*vd
, video_format_t
*backup_fmt
)
766 if ( vd
->sys
->stagingQuad
.pTexture
== NULL
)
769 video_format_Copy( backup_fmt
, &vd
->source
);
770 /* the texture we display is a cropped version of the source */
771 vd
->source
.i_x_offset
= 0;
772 vd
->source
.i_y_offset
= 0;
773 vd
->source
.i_width
= vd
->source
.i_visible_width
;
774 vd
->source
.i_height
= vd
->source
.i_visible_height
;
777 static void UncropStagingFormat(vout_display_t
*vd
, video_format_t
*backup_fmt
)
779 if ( vd
->sys
->stagingQuad
.pTexture
== NULL
)
781 video_format_Copy( &vd
->source
, backup_fmt
);
784 static int Control(vout_display_t
*vd
, int query
, va_list args
)
786 video_format_t core_source
;
787 CropStagingFormat( vd
, &core_source
);
788 int res
= CommonControl( vd
, query
, args
);
789 UncropStagingFormat( vd
, &core_source
);
793 static void Manage(vout_display_t
*vd
)
795 vout_display_sys_t
*sys
= vd
->sys
;
796 RECT size_before
= sys
->rect_dest_clipped
;
798 video_format_t core_source
;
799 CropStagingFormat( vd
, &core_source
);
802 if (RECTWidth(size_before
) != RECTWidth(sys
->rect_dest_clipped
) ||
803 RECTHeight(size_before
) != RECTHeight(sys
->rect_dest_clipped
))
805 #if defined(HAVE_ID3D11VIDEODECODER)
806 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
808 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
811 msg_Dbg(vd
, "Manage detected size change %dx%d", RECTWidth(sys
->rect_dest_clipped
),
812 RECTHeight(sys
->rect_dest_clipped
));
814 UpdateBackBuffer(vd
);
816 UpdatePicQuadPosition(vd
);
817 #if defined(HAVE_ID3D11VIDEODECODER)
818 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
820 ReleaseMutex( sys
->context_lock
);
824 UncropStagingFormat( vd
, &core_source
);
827 static void Prepare(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
829 vout_display_sys_t
*sys
= vd
->sys
;
831 if ( !is_d3d11_opaque(picture
->format
.i_chroma
) &&
832 sys
->stagingQuad
.pTexture
!= NULL
)
834 Direct3D11UnmapTexture(picture
);
837 box
.left
= picture
->format
.i_x_offset
;
838 /* box.right = picture->format.i_x_offset + picture->format.i_visible_width; */
839 box
.top
= picture
->format
.i_y_offset
;
840 /* box.bottom = picture->format.i_y_offset + picture->format.i_visible_height; */
844 D3D11_TEXTURE2D_DESC dstDesc
;
845 ID3D11Texture2D_GetDesc(sys
->picQuad
.pTexture
, &dstDesc
);
846 box
.bottom
= box
.top
+ dstDesc
.Height
;
847 box
.right
= box
.left
+ dstDesc
.Width
;
849 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
850 (ID3D11Resource
*) sys
->picQuad
.pTexture
,
852 (ID3D11Resource
*) sys
->stagingQuad
.pTexture
,
856 #ifdef HAVE_ID3D11VIDEODECODER
857 if (is_d3d11_opaque(picture
->format
.i_chroma
)) {
858 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
860 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
863 picture_sys_t
*p_sys
= picture
->p_sys
;
864 D3D11_TEXTURE2D_DESC texDesc
;
865 ID3D11Texture2D_GetDesc( p_sys
->texture
, &texDesc
);
866 if (texDesc
.Format
== DXGI_FORMAT_NV12
|| texDesc
.Format
== DXGI_FORMAT_P010
)
868 box
.left
= (picture
->format
.i_x_offset
+ 1) & ~1;
869 box
.right
= (picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
) & ~1;
870 box
.top
= (picture
->format
.i_y_offset
+ 1) & ~1;
871 box
.bottom
= (picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
) & ~1;
875 box
.left
= picture
->format
.i_x_offset
;
876 box
.right
= picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
;
877 box
.top
= picture
->format
.i_y_offset
;
878 box
.bottom
= picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
;
883 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
884 (ID3D11Resource
*) sys
->picQuad
.pTexture
,
886 (ID3D11Resource
*) p_sys
->texture
,
887 p_sys
->slice_index
, &box
);
892 int subpicture_region_count
= 0;
893 picture_t
**subpicture_regions
= NULL
;
894 Direct3D11MapSubpicture(vd
, &subpicture_region_count
, &subpicture_regions
, subpicture
);
895 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
896 sys
->d3dregion_count
= subpicture_region_count
;
897 sys
->d3dregions
= subpicture_regions
;
901 static void DisplayD3DPicture(vout_display_sys_t
*sys
, d3d_quad_t
*quad
)
903 UINT stride
= sizeof(d3d_vertex_t
);
906 /* Render the quad */
907 ID3D11DeviceContext_RSSetViewports(sys
->d3dcontext
, 1, &quad
->cropViewport
);
908 ID3D11DeviceContext_PSSetShader(sys
->d3dcontext
, quad
->d3dpixelShader
, NULL
, 0);
909 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 0, 1, &quad
->d3dresViewY
);
911 if( quad
->d3dresViewUV
)
912 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 1, 1, &quad
->d3dresViewUV
);
914 ID3D11DeviceContext_IASetVertexBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexBuffer
, &stride
, &offset
);
915 ID3D11DeviceContext_DrawIndexed(sys
->d3dcontext
, 6, 0, 0);
918 static void Display(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
920 vout_display_sys_t
*sys
= vd
->sys
;
922 FLOAT blackRGBA
[4] = {0.0f
, 0.0f
, 0.0f
, 1.0f
};
923 ID3D11DeviceContext_ClearRenderTargetView(sys
->d3dcontext
, sys
->d3drenderTargetView
, blackRGBA
);
925 /* no ID3D11Device operations should come here */
927 ID3D11DeviceContext_OMSetRenderTargets(sys
->d3dcontext
, 1, &sys
->d3drenderTargetView
, sys
->d3ddepthStencilView
);
929 ID3D11DeviceContext_ClearDepthStencilView(sys
->d3dcontext
, sys
->d3ddepthStencilView
, D3D11_CLEAR_DEPTH
| D3D11_CLEAR_STENCIL
, 1.0f
, 0);
931 if ( !is_d3d11_opaque(picture
->format
.i_chroma
) &&
932 sys
->stagingQuad
.pTexture
== NULL
)
933 Direct3D11UnmapTexture(picture
);
935 /* Render the quad */
936 DisplayD3DPicture(sys
, &sys
->picQuad
);
939 // draw the additional vertices
940 for (int i
= 0; i
< sys
->d3dregion_count
; ++i
) {
941 if (sys
->d3dregions
[i
])
942 DisplayD3DPicture(sys
, (d3d_quad_t
*) sys
->d3dregions
[i
]->p_sys
);
946 DXGI_PRESENT_PARAMETERS presentParams
;
947 memset(&presentParams
, 0, sizeof(presentParams
));
948 HRESULT hr
= IDXGISwapChain1_Present1(sys
->dxgiswapChain
, 0, 0, &presentParams
);
949 if (hr
== DXGI_ERROR_DEVICE_REMOVED
|| hr
== DXGI_ERROR_DEVICE_RESET
)
951 /* TODO device lost */
952 msg_Dbg(vd
, "SwapChain Present failed. (hr=0x%lX)", hr
);
954 #if defined(HAVE_ID3D11VIDEODECODER)
955 if( is_d3d11_opaque(picture
->format
.i_chroma
) && sys
->context_lock
!= INVALID_HANDLE_VALUE
) {
956 ReleaseMutex( sys
->context_lock
);
960 picture_Release(picture
);
962 subpicture_Delete(subpicture
);
967 static void Direct3D11Destroy(vout_display_t
*vd
)
969 #if !VLC_WINSTORE_APP
970 vout_display_sys_t
*sys
= vd
->sys
;
974 FreeLibrary(sys
->hdxgi_dll
);
978 FreeLibrary(sys
->hd3d11_dll
);
979 if (sys
->hd3dcompiler_dll
)
980 FreeLibrary(sys
->hd3dcompiler_dll
);
982 sys
->OurD3D11CreateDevice
= NULL
;
983 sys
->OurD3D11CreateDeviceAndSwapChain
= NULL
;
984 sys
->OurD3DCompile
= NULL
;
985 sys
->hdxgi_dll
= NULL
;
986 sys
->hd3d11_dll
= NULL
;
987 sys
->hd3dcompiler_dll
= NULL
;
993 #if !VLC_WINSTORE_APP
994 static HINSTANCE
Direct3D11LoadShaderLibrary(void)
996 HINSTANCE instance
= NULL
;
997 /* d3dcompiler_47 is the latest on windows 8.1 */
998 for (int i
= 47; i
> 41; --i
) {
1000 _sntprintf(filename
, 19, TEXT("D3DCOMPILER_%d.dll"), i
);
1001 instance
= LoadLibrary(filename
);
1002 if (instance
) break;
1009 static int Direct3D11Open(vout_display_t
*vd
, video_format_t
*fmt
)
1011 vout_display_sys_t
*sys
= vd
->sys
;
1014 #if !VLC_WINSTORE_APP
1016 UINT creationFlags
= 0;
1019 # if !defined(NDEBUG) && defined(_MSC_VER)
1020 creationFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
1023 DXGI_SWAP_CHAIN_DESC1 scd
;
1024 memset(&scd
, 0, sizeof(scd
));
1025 scd
.BufferCount
= 2;
1026 scd
.BufferUsage
= DXGI_USAGE_RENDER_TARGET_OUTPUT
;
1027 scd
.SampleDesc
.Count
= 1;
1028 scd
.SampleDesc
.Quality
= 0;
1029 scd
.Width
= fmt
->i_visible_width
;
1030 scd
.Height
= fmt
->i_visible_height
;
1031 switch(fmt
->i_chroma
)
1033 case VLC_CODEC_D3D11_OPAQUE_10B
:
1034 scd
.Format
= DXGI_FORMAT_R10G10B10A2_UNORM
;
1037 scd
.Format
= DXGI_FORMAT_R8G8B8A8_UNORM
; /* TODO: use DXGI_FORMAT_NV12 */
1040 //scd.Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
1041 scd
.SwapEffect
= DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
;
1043 IDXGIAdapter
*dxgiadapter
;
1044 static const D3D_FEATURE_LEVEL featureLevels
[] =
1046 0xc000 /* D3D_FEATURE_LEVEL_12_1 */,
1047 0xc100 /* D3D_FEATURE_LEVEL_12_0 */,
1048 D3D_FEATURE_LEVEL_11_1
,
1049 D3D_FEATURE_LEVEL_11_0
,
1050 D3D_FEATURE_LEVEL_10_1
,
1051 D3D_FEATURE_LEVEL_10_0
,
1052 D3D_FEATURE_LEVEL_9_3
,
1053 D3D_FEATURE_LEVEL_9_2
,
1054 D3D_FEATURE_LEVEL_9_1
,
1058 /* TODO : list adapters for the user to choose from */
1059 hr
= IDXGIFactory2_EnumAdapters(sys
->dxgifactory
, 0, &dxgiadapter
);
1061 msg_Err(vd
, "Could not create find factory. (hr=0x%lX)", hr
);
1062 return VLC_EGENERIC
;
1065 IDXGIOutput
* output
;
1066 hr
= IDXGIAdapter_EnumOutputs(dxgiadapter
, 0, &output
);
1068 msg_Err(vd
, "Could not Enumerate DXGI Outputs. (hr=0x%lX)", hr
);
1069 IDXGIAdapter_Release(dxgiadapter
);
1070 return VLC_EGENERIC
;
1074 memset(&md
, 0, sizeof(md
));
1075 md
.Width
= fmt
->i_visible_width
;
1076 md
.Height
= fmt
->i_visible_height
;
1077 md
.Format
= scd
.BufferDesc
.Format
;
1078 md
.Scaling
= DXGI_MODE_SCALING_UNSPECIFIED
;
1080 hr
= IDXGIOutput_FindClosestMatchingMode(output
, &md
, &scd
.BufferDesc
, NULL
);
1082 msg_Err(vd
, "Failed to find a supported video mode. (hr=0x%lX)", hr
);
1083 IDXGIAdapter_Release(dxgiadapter
);
1084 return VLC_EGENERIC
;
1087 /* mode desc doesn't carry over the width and height*/
1088 scd
.BufferDesc
.Width
= fmt
->i_visible_width
;
1089 scd
.BufferDesc
.Height
= fmt
->i_visible_height
;
1091 hr
= D3D11CreateDeviceAndSwapChain(dxgiadapter
,
1092 D3D_DRIVER_TYPE_UNKNOWN
, NULL
, creationFlags
,
1093 featureLevels
, ARRAYSIZE(featureLevels
),
1094 D3D11_SDK_VERSION
, &scd
, &sys
->dxgiswapChain
,
1095 &sys
->d3ddevice
, NULL
, &sys
->d3dcontext
);
1096 IDXGIAdapter_Release(dxgiadapter
);
1098 msg_Err(vd
, "Could not Create the D3D11 device and SwapChain. (hr=0x%lX)", hr
);
1099 return VLC_EGENERIC
;
1104 static const D3D_DRIVER_TYPE driverAttempts
[] = {
1105 D3D_DRIVER_TYPE_HARDWARE
,
1106 D3D_DRIVER_TYPE_WARP
,
1108 D3D_DRIVER_TYPE_REFERENCE
,
1112 for (UINT driver
= 0; driver
< ARRAYSIZE(driverAttempts
); driver
++) {
1113 D3D_FEATURE_LEVEL i_feature_level
;
1114 hr
= D3D11CreateDevice(NULL
, driverAttempts
[driver
], NULL
, creationFlags
,
1115 featureLevels
, 9, D3D11_SDK_VERSION
,
1116 &sys
->d3ddevice
, &i_feature_level
, &sys
->d3dcontext
);
1117 if (SUCCEEDED(hr
)) {
1119 msg_Dbg(vd
, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
1120 (void *)sys
->d3ddevice
, (void *)sys
->d3dcontext
,
1121 driverAttempts
[driver
], i_feature_level
);
1128 msg_Err(vd
, "Could not Create the D3D11 device. (hr=0x%lX)", hr
);
1129 return VLC_EGENERIC
;
1132 IDXGIDevice
*pDXGIDevice
= NULL
;
1133 hr
= ID3D11Device_QueryInterface(sys
->d3ddevice
, &IID_IDXGIDevice
, (void **)&pDXGIDevice
);
1135 msg_Err(vd
, "Could not Query DXGI Interface. (hr=0x%lX)", hr
);
1136 return VLC_EGENERIC
;
1139 hr
= IDXGIDevice_GetAdapter(pDXGIDevice
, &dxgiadapter
);
1140 IDXGIAdapter_Release(pDXGIDevice
);
1142 msg_Err(vd
, "Could not get the DXGI Adapter. (hr=0x%lX)", hr
);
1143 return VLC_EGENERIC
;
1146 hr
= IDXGIAdapter_GetParent(dxgiadapter
, &IID_IDXGIFactory2
, (void **)&sys
->dxgifactory
);
1147 IDXGIAdapter_Release(dxgiadapter
);
1149 msg_Err(vd
, "Could not get the DXGI Factory. (hr=0x%lX)", hr
);
1150 return VLC_EGENERIC
;
1153 hr
= IDXGIFactory2_CreateSwapChainForHwnd(sys
->dxgifactory
, (IUnknown
*)sys
->d3ddevice
,
1154 sys
->hvideownd
, &scd
, NULL
, NULL
, &sys
->dxgiswapChain
);
1155 IDXGIFactory2_Release(sys
->dxgifactory
);
1157 msg_Err(vd
, "Could not create the SwapChain. (hr=0x%lX)", hr
);
1158 return VLC_EGENERIC
;
1164 vlc_fourcc_t i_src_chroma
= fmt
->i_chroma
;
1167 // look for the requested pixel format first
1168 UINT i_quadSupportFlags
= D3D11_FORMAT_SUPPORT_TEXTURE2D
| D3D11_FORMAT_SUPPORT_SHADER_LOAD
;
1169 UINT i_formatSupport
;
1170 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1171 output_format
->name
!= NULL
; ++output_format
)
1173 if( i_src_chroma
== output_format
->fourcc
)
1175 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1176 output_format
->formatTexture
,
1177 &i_formatSupport
)) &&
1178 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
)
1180 msg_Dbg( vd
, "Using pixel format %s from chroma %4.4s", output_format
->name
,
1181 (char *)&i_src_chroma
);
1182 fmt
->i_chroma
= output_format
->fourcc
;
1183 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1184 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1185 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1186 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1192 // look for any pixel format that we can handle with enough pixels per channel
1193 if ( !fmt
->i_chroma
)
1195 uint8_t bits_per_channel
;
1196 switch (i_src_chroma
)
1198 case VLC_CODEC_D3D11_OPAQUE
:
1199 bits_per_channel
= 8;
1201 case VLC_CODEC_D3D11_OPAQUE_10B
:
1202 bits_per_channel
= 10;
1206 const vlc_chroma_description_t
*p_format
= vlc_fourcc_GetChromaDescription(i_src_chroma
);
1207 bits_per_channel
= p_format
== NULL
|| p_format
->pixel_bits
== 0 ? 8 : p_format
->pixel_bits
;
1212 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1213 output_format
->name
!= NULL
; ++output_format
)
1215 if( bits_per_channel
<= output_format
->bitsPerChannel
&&
1216 !is_d3d11_opaque(output_format
->fourcc
) )
1218 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1219 output_format
->formatTexture
,
1220 &i_formatSupport
)) &&
1221 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
)
1223 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", output_format
->name
,
1224 (char *)&i_src_chroma
);
1225 fmt
->i_chroma
= output_format
->fourcc
;
1226 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1227 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1228 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1229 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1235 // look for any pixel format that we can handle
1236 if ( !fmt
->i_chroma
)
1238 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1239 output_format
->name
!= NULL
; ++output_format
)
1241 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1242 output_format
->formatTexture
,
1243 &i_formatSupport
)) &&
1244 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
&&
1245 !is_d3d11_opaque(output_format
->fourcc
) )
1247 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", output_format
->name
,
1248 (char *)&i_src_chroma
);
1249 fmt
->i_chroma
= output_format
->fourcc
;
1250 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1251 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1252 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1253 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1258 if ( !fmt
->i_chroma
)
1260 msg_Err(vd
, "Could not get a suitable texture pixel format");
1261 return VLC_EGENERIC
;
1264 /* check the region pixel format */
1265 i_quadSupportFlags
|= D3D11_FORMAT_SUPPORT_BLENDABLE
;
1266 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1267 DXGI_FORMAT_R8G8B8A8_UNORM
,
1268 &i_formatSupport
)) &&
1269 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
) {
1270 sys
->d3dregion_format
= DXGI_FORMAT_R8G8B8A8_UNORM
;
1271 sys
->pSubpictureChromas
[0] = VLC_CODEC_RGBA
;
1272 sys
->pSubpictureChromas
[1] = 0;
1273 } else if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1274 DXGI_FORMAT_B8G8R8A8_UNORM
,
1275 &i_formatSupport
)) &&
1276 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
) {
1277 sys
->d3dregion_format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
1278 sys
->pSubpictureChromas
[0] = VLC_CODEC_BGRA
;
1279 sys
->pSubpictureChromas
[1] = 0;
1281 sys
->d3dregion_format
= DXGI_FORMAT_UNKNOWN
;
1284 if (sys
->picQuadConfig
.resourceFormatYRGB
== DXGI_FORMAT_R8_UNORM
||
1285 sys
->picQuadConfig
.resourceFormatYRGB
== DXGI_FORMAT_R16_UNORM
)
1287 if (vd
->fmt
.space
== COLOR_SPACE_BT2020
)
1288 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT2020_2RGB
;
1289 else if (vd
->fmt
.space
== COLOR_SPACE_BT709
)
1290 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT709_2RGB
;
1291 else if (vd
->fmt
.space
== COLOR_SPACE_BT601
)
1292 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT601_2RGB
;
1293 else if( fmt
->i_height
> 576 )
1294 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT709_2RGB
;
1296 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT601_2RGB
;
1299 if (fmt
->i_chroma
== VLC_CODEC_YUYV
)
1301 if( fmt
->i_height
> 576 )
1302 sys
->d3dPxShader
= globPixelShaderBiplanarYUYV_BT709_2RGB
;
1304 sys
->d3dPxShader
= globPixelShaderBiplanarYUYV_BT601_2RGB
;
1307 sys
->d3dPxShader
= globPixelShaderDefault
;
1309 if (sys
->d3dregion_format
!= DXGI_FORMAT_UNKNOWN
)
1310 sys
->psz_rgbaPxShader
= globPixelShaderDefault
;
1312 sys
->psz_rgbaPxShader
= NULL
;
1314 if ( fmt
->i_height
!= fmt
->i_visible_height
|| fmt
->i_width
!= fmt
->i_visible_width
)
1316 msg_Dbg( vd
, "use a staging texture to crop to visible size" );
1317 AllocQuad( vd
, fmt
, &sys
->stagingQuad
, &sys
->picQuadConfig
, NULL
, false );
1320 video_format_t core_source
;
1321 CropStagingFormat( vd
, &core_source
);
1322 UpdateRects(vd
, NULL
, NULL
, true);
1323 UncropStagingFormat( vd
, &core_source
);
1325 #if defined(HAVE_ID3D11VIDEODECODER)
1326 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1328 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1331 if (Direct3D11CreateResources(vd
, fmt
)) {
1332 #if defined(HAVE_ID3D11VIDEODECODER)
1333 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1335 ReleaseMutex( sys
->context_lock
);
1338 msg_Err(vd
, "Failed to allocate resources");
1339 Direct3D11DestroyResources(vd
);
1340 return VLC_EGENERIC
;
1342 #if defined(HAVE_ID3D11VIDEODECODER)
1343 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1345 ReleaseMutex( sys
->context_lock
);
1349 #if !VLC_WINSTORE_APP
1350 EventThreadUpdateTitle(sys
->event
, VOUT_TITLE
" (Direct3D11 output)");
1353 msg_Dbg(vd
, "Direct3D11 device adapter successfully initialized");
1357 static void Direct3D11Close(vout_display_t
*vd
)
1359 vout_display_sys_t
*sys
= vd
->sys
;
1361 Direct3D11DestroyResources(vd
);
1362 if (sys
->d3dcontext
)
1364 ID3D11DeviceContext_Flush(sys
->d3dcontext
);
1365 ID3D11DeviceContext_Release(sys
->d3dcontext
);
1366 sys
->d3dcontext
= NULL
;
1370 ID3D11Device_Release(sys
->d3ddevice
);
1371 sys
->d3ddevice
= NULL
;
1373 if (sys
->dxgiswapChain
)
1375 IDXGISwapChain_Release(sys
->dxgiswapChain
);
1376 sys
->dxgiswapChain
= NULL
;
1379 msg_Dbg(vd
, "Direct3D11 device adapter closed");
1382 static void UpdatePicQuadPosition(vout_display_t
*vd
)
1384 vout_display_sys_t
*sys
= vd
->sys
;
1385 int i_width
= RECTWidth(sys
->rect_dest_clipped
);
1386 int i_height
= RECTHeight(sys
->rect_dest_clipped
);
1388 int i_top
= sys
->rect_src_clipped
.top
* i_height
;
1389 i_top
/= vd
->source
.i_visible_height
;
1390 i_top
-= sys
->rect_dest_clipped
.top
;
1391 int i_left
= sys
->rect_src_clipped
.left
* i_width
;
1392 i_left
/= vd
->source
.i_visible_width
;
1393 i_left
-= sys
->rect_dest_clipped
.left
;
1395 sys
->picQuad
.cropViewport
.Width
= (FLOAT
) vd
->source
.i_width
* i_width
/ vd
->source
.i_visible_width
;
1396 sys
->picQuad
.cropViewport
.Height
= (FLOAT
) vd
->source
.i_height
* i_height
/ vd
->source
.i_visible_height
;
1397 sys
->picQuad
.cropViewport
.TopLeftX
= -i_left
;
1398 sys
->picQuad
.cropViewport
.TopLeftY
= -i_top
;
1400 sys
->picQuad
.cropViewport
.MinDepth
= 0.0f
;
1401 sys
->picQuad
.cropViewport
.MaxDepth
= 1.0f
;
1404 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
);
1408 /* TODO : handle errors better
1409 TODO : seperate out into smaller functions like createshaders */
1410 static int Direct3D11CreateResources(vout_display_t
*vd
, video_format_t
*fmt
)
1412 vout_display_sys_t
*sys
= vd
->sys
;
1415 #if defined(HAVE_ID3D11VIDEODECODER)
1416 sys
->context_lock
= CreateMutexEx( NULL
, NULL
, 0, SYNCHRONIZE
);
1417 ID3D11Device_SetPrivateData( sys
->d3ddevice
, &GUID_CONTEXT_MUTEX
, sizeof( sys
->context_lock
), &sys
->context_lock
);
1420 hr
= UpdateBackBuffer(vd
);
1422 msg_Err(vd
, "Could not update the backbuffer. (hr=0x%lX)", hr
);
1423 return VLC_EGENERIC
;
1426 ID3D11BlendState
*pSpuBlendState
;
1427 D3D11_BLEND_DESC spuBlendDesc
= { 0 };
1428 spuBlendDesc
.RenderTarget
[0].BlendEnable
= TRUE
;
1429 spuBlendDesc
.RenderTarget
[0].SrcBlend
= D3D11_BLEND_SRC_ALPHA
;
1430 spuBlendDesc
.RenderTarget
[0].DestBlend
= D3D11_BLEND_INV_SRC_ALPHA
;
1431 spuBlendDesc
.RenderTarget
[0].BlendOp
= D3D11_BLEND_OP_ADD
;
1433 spuBlendDesc
.RenderTarget
[0].SrcBlendAlpha
= D3D11_BLEND_ONE
;
1434 spuBlendDesc
.RenderTarget
[0].DestBlendAlpha
= D3D11_BLEND_ZERO
;
1435 spuBlendDesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
1437 spuBlendDesc
.RenderTarget
[0].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
1439 spuBlendDesc
.RenderTarget
[1].BlendEnable
= TRUE
;
1440 spuBlendDesc
.RenderTarget
[1].SrcBlend
= D3D11_BLEND_ONE
;
1441 spuBlendDesc
.RenderTarget
[1].DestBlend
= D3D11_BLEND_ZERO
;
1442 spuBlendDesc
.RenderTarget
[1].BlendOp
= D3D11_BLEND_OP_ADD
;
1444 spuBlendDesc
.RenderTarget
[1].SrcBlendAlpha
= D3D11_BLEND_ONE
;
1445 spuBlendDesc
.RenderTarget
[1].DestBlendAlpha
= D3D11_BLEND_ZERO
;
1446 spuBlendDesc
.RenderTarget
[1].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
1448 spuBlendDesc
.RenderTarget
[1].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
1449 hr
= ID3D11Device_CreateBlendState(sys
->d3ddevice
, &spuBlendDesc
, &pSpuBlendState
);
1451 msg_Err(vd
, "Could not create SPU blend state. (hr=0x%lX)", hr
);
1452 return VLC_EGENERIC
;
1454 ID3D11DeviceContext_OMSetBlendState(sys
->d3dcontext
, pSpuBlendState
, NULL
, 0xFFFFFFFF);
1455 ID3D11BlendState_Release(pSpuBlendState
);
1457 /* disable depth testing as we're only doing 2D
1458 * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
1459 * see http://rastertek.com/dx11tut11.html
1461 D3D11_DEPTH_STENCIL_DESC stencilDesc
;
1462 ZeroMemory(&stencilDesc
, sizeof(stencilDesc
));
1464 ID3D11DepthStencilState
*pDepthStencilState
;
1465 hr
= ID3D11Device_CreateDepthStencilState(sys
->d3ddevice
, &stencilDesc
, &pDepthStencilState
);
1466 if (SUCCEEDED(hr
)) {
1467 ID3D11DeviceContext_OMSetDepthStencilState(sys
->d3dcontext
, pDepthStencilState
, 0);
1468 ID3D11DepthStencilState_Release(pDepthStencilState
);
1471 ID3DBlob
* pVSBlob
= NULL
;
1473 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1474 hr
= D3DCompile(globVertexShaderDefault
, strlen(globVertexShaderDefault
),
1475 NULL
, NULL
, NULL
, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob
, NULL
);
1478 msg_Err(vd
, "The Vertex Shader is invalid. (hr=0x%lX)", hr
);
1479 return VLC_EGENERIC
;
1482 ID3D11VertexShader
*d3dvertexShader
;
1483 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1484 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &d3dvertexShader
);
1487 ID3D11Device_Release(pVSBlob
);
1488 msg_Err(vd
, "Failed to create the vertex shader. (hr=0x%lX)", hr
);
1489 return VLC_EGENERIC
;
1491 ID3D11DeviceContext_VSSetShader(sys
->d3dcontext
, d3dvertexShader
, NULL
, 0);
1492 ID3D11VertexShader_Release(d3dvertexShader
);
1494 D3D11_INPUT_ELEMENT_DESC layout
[] = {
1495 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, 0, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1496 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT
, 0, 12, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1497 { "OPACITY", 0, DXGI_FORMAT_R32_FLOAT
, 0, 20, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1500 ID3D11InputLayout
* pVertexLayout
= NULL
;
1501 hr
= ID3D11Device_CreateInputLayout(sys
->d3ddevice
, layout
, 3, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1502 ID3D10Blob_GetBufferSize(pVSBlob
), &pVertexLayout
);
1504 ID3D10Blob_Release(pVSBlob
);
1507 msg_Err(vd
, "Failed to create the vertex input layout. (hr=0x%lX)", hr
);
1508 return VLC_EGENERIC
;
1511 ID3D11DeviceContext_IASetInputLayout(sys
->d3dcontext
, pVertexLayout
);
1512 ID3D11SamplerState_Release(pVertexLayout
);
1514 /* create the index of the vertices */
1520 D3D11_BUFFER_DESC quadDesc
= {
1521 .Usage
= D3D11_USAGE_DEFAULT
,
1522 .ByteWidth
= sizeof(WORD
) * 6,
1523 .BindFlags
= D3D11_BIND_INDEX_BUFFER
,
1524 .CPUAccessFlags
= 0,
1527 D3D11_SUBRESOURCE_DATA quadIndicesInit
= {
1531 ID3D11Buffer
* pIndexBuffer
= NULL
;
1532 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &quadDesc
, &quadIndicesInit
, &pIndexBuffer
);
1534 msg_Err(vd
, "Could not Create the common quad indices. (hr=0x%lX)", hr
);
1535 return VLC_EGENERIC
;
1537 ID3D11DeviceContext_IASetIndexBuffer(sys
->d3dcontext
, pIndexBuffer
, DXGI_FORMAT_R16_UINT
, 0);
1538 ID3D11Buffer_Release(pIndexBuffer
);
1540 ID3D11DeviceContext_IASetPrimitiveTopology(sys
->d3dcontext
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
1542 ID3DBlob
* pPSBlob
= NULL
;
1544 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1545 hr
= D3DCompile(sys
->d3dPxShader
, strlen(sys
->d3dPxShader
),
1546 NULL
, NULL
, NULL
, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob
, NULL
);
1550 msg_Err(vd
, "The Pixel Shader is invalid. (hr=0x%lX)", hr
);
1551 return VLC_EGENERIC
;
1554 ID3D11PixelShader
*pPicQuadShader
;
1555 hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
1556 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, &pPicQuadShader
);
1558 ID3D10Blob_Release(pPSBlob
);
1561 msg_Err(vd
, "Failed to create the pixel shader. (hr=0x%lX)", hr
);
1562 return VLC_EGENERIC
;
1565 if (sys
->psz_rgbaPxShader
!= NULL
)
1567 hr
= D3DCompile(sys
->psz_rgbaPxShader
, strlen(sys
->psz_rgbaPxShader
),
1568 NULL
, NULL
, NULL
, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob
, NULL
);
1570 ID3D11PixelShader_Release(pPicQuadShader
);
1571 msg_Err(vd
, "The RGBA Pixel Shader is invalid. (hr=0x%lX)", hr
);
1572 return VLC_EGENERIC
;
1575 hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
1576 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, &sys
->pSPUPixelShader
);
1578 ID3D10Blob_Release(pPSBlob
);
1581 ID3D11PixelShader_Release(pPicQuadShader
);
1582 msg_Err(vd
, "Failed to create the SPU pixel shader. (hr=0x%lX)", hr
);
1583 return VLC_EGENERIC
;
1587 if (AllocQuad( vd
, fmt
, &sys
->picQuad
, &sys
->picQuadConfig
, pPicQuadShader
, true) != VLC_SUCCESS
) {
1588 ID3D11PixelShader_Release(pPicQuadShader
);
1589 msg_Err(vd
, "Could not Create the main quad picture. (hr=0x%lX)", hr
);
1590 return VLC_EGENERIC
;
1592 ID3D11PixelShader_Release(pPicQuadShader
);
1594 video_format_t core_source
;
1595 CropStagingFormat( vd
, &core_source
);
1596 UpdatePicQuadPosition(vd
);
1597 UncropStagingFormat( vd
, &core_source
);
1599 D3D11_SAMPLER_DESC sampDesc
;
1600 memset(&sampDesc
, 0, sizeof(sampDesc
));
1601 sampDesc
.Filter
= D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
;
1602 sampDesc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1603 sampDesc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1604 sampDesc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1605 sampDesc
.ComparisonFunc
= D3D11_COMPARISON_ALWAYS
;
1606 sampDesc
.MinLOD
= 0;
1607 sampDesc
.MaxLOD
= D3D11_FLOAT32_MAX
;
1609 ID3D11SamplerState
*d3dsampState
;
1610 hr
= ID3D11Device_CreateSamplerState(sys
->d3ddevice
, &sampDesc
, &d3dsampState
);
1613 msg_Err(vd
, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr
);
1614 return VLC_EGENERIC
;
1616 ID3D11DeviceContext_PSSetSamplers(sys
->d3dcontext
, 0, 1, &d3dsampState
);
1617 ID3D11SamplerState_Release(d3dsampState
);
1619 if (Direct3D11CreatePool(vd
, fmt
))
1621 msg_Err(vd
, "Direct3D picture pool initialization failed");
1622 return VLC_EGENERIC
;
1625 msg_Dbg(vd
, "Direct3D11 resources created");
1629 static int Direct3D11CreatePool(vout_display_t
*vd
, video_format_t
*fmt
)
1631 vout_display_sys_t
*sys
= vd
->sys
;
1633 if ( is_d3d11_opaque(fmt
->i_chroma
) )
1634 /* a D3D11VA pool will be created when needed */
1637 picture_sys_pool_t
*picsys
= calloc(1, sizeof(*picsys
));
1638 if (unlikely(picsys
== NULL
)) {
1642 if ( sys
->stagingQuad
.pTexture
!= NULL
)
1643 picsys
->texture
= sys
->stagingQuad
.pTexture
;
1645 picsys
->texture
= sys
->picQuad
.pTexture
;
1648 picture_resource_t resource
= {
1649 .p_sys
= (picture_sys_t
*) picsys
,
1650 .pf_destroy
= DestroyDisplayPicture
,
1653 picture_t
*picture
= picture_NewFromResource(fmt
, &resource
);
1658 ID3D11Texture2D_AddRef(picsys
->texture
);
1660 picture_pool_configuration_t pool_cfg
;
1661 memset(&pool_cfg
, 0, sizeof(pool_cfg
));
1662 pool_cfg
.picture_count
= 1;
1663 pool_cfg
.picture
= &picture
;
1664 pool_cfg
.lock
= Direct3D11MapTexture
;
1665 //pool_cfg.unlock = Direct3D11UnmapTexture;
1667 sys
->pool
= picture_pool_NewExtended(&pool_cfg
);
1669 picture_Release(picture
);
1676 static void Direct3D11DestroyPool(vout_display_t
*vd
)
1678 vout_display_sys_t
*sys
= vd
->sys
;
1681 picture_pool_Release(sys
->pool
);
1685 static int AllocQuad(vout_display_t
*vd
, const video_format_t
*fmt
, d3d_quad_t
*quad
,
1686 d3d_quad_cfg_t
*cfg
, ID3D11PixelShader
*d3dpixelShader
, bool b_visible
)
1688 vout_display_sys_t
*sys
= vd
->sys
;
1689 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1691 quad
->vertexCount
= 4;
1693 D3D11_BUFFER_DESC bd
;
1694 memset(&bd
, 0, sizeof(bd
));
1695 bd
.Usage
= D3D11_USAGE_DYNAMIC
;
1696 bd
.ByteWidth
= sizeof(d3d_vertex_t
) * quad
->vertexCount
;
1697 bd
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
1698 bd
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
1700 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &bd
, NULL
, &quad
->pVertexBuffer
);
1702 msg_Err(vd
, "Failed to create vertex buffer. (hr=%lX)", hr
);
1706 D3D11_TEXTURE2D_DESC texDesc
;
1707 memset(&texDesc
, 0, sizeof(texDesc
));
1708 texDesc
.Width
= b_visible
? fmt
->i_visible_width
: fmt
->i_width
;
1709 texDesc
.Height
= b_visible
? fmt
->i_visible_height
: fmt
->i_height
;
1710 texDesc
.MipLevels
= texDesc
.ArraySize
= 1;
1711 texDesc
.Format
= cfg
->textureFormat
;
1712 texDesc
.SampleDesc
.Count
= 1;
1713 texDesc
.Usage
= D3D11_USAGE_DYNAMIC
;
1714 texDesc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
1715 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
1716 texDesc
.MiscFlags
= 0;
1718 /* remove half pixels, we don't want green lines */
1719 const vlc_chroma_description_t
*p_chroma_desc
= vlc_fourcc_GetChromaDescription( fmt
->i_chroma
);
1720 for (unsigned plane
= 0; plane
< p_chroma_desc
->plane_count
; ++plane
)
1723 i_extra
= (texDesc
.Width
* p_chroma_desc
->p
[plane
].w
.num
) % p_chroma_desc
->p
[plane
].w
.den
;
1725 texDesc
.Width
-= p_chroma_desc
->p
[plane
].w
.den
/ p_chroma_desc
->p
[plane
].w
.num
- i_extra
;
1726 i_extra
= (texDesc
.Height
* p_chroma_desc
->p
[plane
].h
.num
) % p_chroma_desc
->p
[plane
].h
.den
;
1728 texDesc
.Height
-= p_chroma_desc
->p
[plane
].h
.den
/ p_chroma_desc
->p
[plane
].h
.num
- i_extra
;
1730 if (texDesc
.Format
== DXGI_FORMAT_NV12
|| texDesc
.Format
== DXGI_FORMAT_P010
)
1732 texDesc
.Width
&= ~1;
1733 texDesc
.Height
&= ~1;
1736 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &texDesc
, NULL
, &quad
->pTexture
);
1738 msg_Err(vd
, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr
);
1742 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pTexture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
1744 msg_Err(vd
, "The texture cannot be mapped. (hr=0x%lX)", hr
);
1747 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pTexture
, 0);
1748 if (mappedResource
.RowPitch
< p_chroma_desc
->pixel_size
* texDesc
.Width
) {
1749 msg_Err( vd
, "The texture row pitch is too small (%d instead of %d)", mappedResource
.RowPitch
,
1750 p_chroma_desc
->pixel_size
* texDesc
.Width
);
1754 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc
;
1755 memset(&resviewDesc
, 0, sizeof(resviewDesc
));
1756 resviewDesc
.Format
= cfg
->resourceFormatYRGB
;
1757 resviewDesc
.ViewDimension
= D3D11_SRV_DIMENSION_TEXTURE2D
;
1758 resviewDesc
.Texture2D
.MipLevels
= texDesc
.MipLevels
;
1760 hr
= ID3D11Device_CreateShaderResourceView(sys
->d3ddevice
, (ID3D11Resource
*)quad
->pTexture
, &resviewDesc
, &quad
->d3dresViewY
);
1762 msg_Err(vd
, "Could not Create the Y/RGB D3d11 Texture ResourceView. (hr=0x%lX)", hr
);
1766 if( cfg
->resourceFormatUV
)
1768 resviewDesc
.Format
= cfg
->resourceFormatUV
;
1769 hr
= ID3D11Device_CreateShaderResourceView(sys
->d3ddevice
, (ID3D11Resource
*)quad
->pTexture
, &resviewDesc
, &quad
->d3dresViewUV
);
1771 msg_Err(vd
, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr
);
1776 if ( d3dpixelShader
!= NULL
)
1778 quad
->d3dpixelShader
= d3dpixelShader
;
1779 ID3D11PixelShader_AddRef(quad
->d3dpixelShader
);
1784 float bottom
= -1.0f
;
1786 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
1787 if (SUCCEEDED(hr
)) {
1788 d3d_vertex_t
*dst_data
= mappedResource
.pData
;
1791 dst_data
[0].position
.x
= left
;
1792 dst_data
[0].position
.y
= bottom
;
1793 dst_data
[0].position
.z
= 0.0f
;
1794 dst_data
[0].texture
.x
= 0.0f
;
1795 dst_data
[0].texture
.y
= 1.0f
;
1796 dst_data
[0].opacity
= 1.0f
;
1799 dst_data
[1].position
.x
= right
;
1800 dst_data
[1].position
.y
= bottom
;
1801 dst_data
[1].position
.z
= 0.0f
;
1802 dst_data
[1].texture
.x
= 1.0f
;
1803 dst_data
[1].texture
.y
= 1.0f
;
1804 dst_data
[1].opacity
= 1.0f
;
1807 dst_data
[2].position
.x
= right
;
1808 dst_data
[2].position
.y
= top
;
1809 dst_data
[2].position
.z
= 0.0f
;
1810 dst_data
[2].texture
.x
= 1.0f
;
1811 dst_data
[2].texture
.y
= 0.0f
;
1812 dst_data
[2].opacity
= 1.0f
;
1815 dst_data
[3].position
.x
= left
;
1816 dst_data
[3].position
.y
= top
;
1817 dst_data
[3].position
.z
= 0.0f
;
1818 dst_data
[3].texture
.x
= 0.0f
;
1819 dst_data
[3].texture
.y
= 0.0f
;
1820 dst_data
[3].opacity
= 1.0f
;
1822 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
1825 msg_Err(vd
, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr
);
1833 return VLC_EGENERIC
;
1836 static void ReleaseQuad(d3d_quad_t
*quad
)
1838 if (quad
->pVertexBuffer
)
1840 ID3D11Buffer_Release(quad
->pVertexBuffer
);
1841 quad
->pVertexBuffer
= NULL
;
1845 ID3D11Texture2D_Release(quad
->pTexture
);
1846 quad
->pTexture
= NULL
;
1848 if (quad
->d3dresViewY
)
1850 ID3D11ShaderResourceView_Release(quad
->d3dresViewY
);
1851 quad
->d3dresViewY
= NULL
;
1853 if (quad
->d3dresViewUV
)
1855 ID3D11ShaderResourceView_Release(quad
->d3dresViewUV
);
1856 quad
->d3dresViewUV
= NULL
;
1858 if (quad
->d3dpixelShader
)
1860 ID3D11VertexShader_Release(quad
->d3dpixelShader
);
1861 quad
->d3dpixelShader
= NULL
;
1865 static void Direct3D11DestroyResources(vout_display_t
*vd
)
1867 vout_display_sys_t
*sys
= vd
->sys
;
1869 Direct3D11DestroyPool(vd
);
1871 if ( sys
->stagingQuad
.pTexture
)
1872 ReleaseQuad(&sys
->stagingQuad
);
1873 ReleaseQuad(&sys
->picQuad
);
1874 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
1875 sys
->d3dregion_count
= 0;
1877 if (sys
->d3drenderTargetView
)
1879 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
1880 sys
->d3drenderTargetView
= NULL
;
1882 if (sys
->d3ddepthStencilView
)
1884 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
1885 sys
->d3ddepthStencilView
= NULL
;
1887 if (sys
->pSPUPixelShader
)
1889 ID3D11VertexShader_Release(sys
->pSPUPixelShader
);
1890 sys
->pSPUPixelShader
= NULL
;
1892 #if defined(HAVE_ID3D11VIDEODECODER)
1893 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1895 CloseHandle( sys
->context_lock
);
1896 sys
->context_lock
= INVALID_HANDLE_VALUE
;
1900 msg_Dbg(vd
, "Direct3D11 resources destroyed");
1903 static int Direct3D11MapTexture(picture_t
*picture
)
1905 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*) picture
->p_sys
;
1906 vout_display_t
*vd
= p_sys
->vd
;
1907 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1909 hr
= ID3D11DeviceContext_Map(vd
->sys
->d3dcontext
, (ID3D11Resource
*)p_sys
->texture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
1912 msg_Dbg( vd
, "failed to map the texture (hr=0x%lX)", hr
);
1913 return VLC_EGENERIC
;
1915 return CommonUpdatePicture(picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
1918 static int Direct3D11UnmapTexture(picture_t
*picture
)
1920 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*)picture
->p_sys
;
1921 vout_display_t
*vd
= p_sys
->vd
;
1922 ID3D11DeviceContext_Unmap(vd
->sys
->d3dcontext
, (ID3D11Resource
*)p_sys
->texture
, 0);
1926 static void Direct3D11DeleteRegions(int count
, picture_t
**region
)
1928 for (int i
= 0; i
< count
; ++i
) {
1930 picture_Release(region
[i
]);
1936 static void DestroyPictureQuad(picture_t
*p_picture
)
1938 ReleaseQuad( (d3d_quad_t
*) p_picture
->p_sys
);
1942 static void UpdateQuadOpacity(vout_display_t
*vd
, const d3d_quad_t
*quad
, float opacity
)
1944 vout_display_sys_t
*sys
= vd
->sys
;
1945 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1947 HRESULT hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0, D3D11_MAP_WRITE_NO_OVERWRITE
, 0, &mappedResource
);
1948 if (SUCCEEDED(hr
)) {
1949 d3d_vertex_t
*dst_data
= mappedResource
.pData
;
1951 for (size_t i
=0; i
<quad
->vertexCount
; ++i
)
1952 dst_data
[i
].opacity
= opacity
;
1954 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
1957 msg_Err(vd
, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr
);
1961 static int Direct3D11MapSubpicture(vout_display_t
*vd
, int *subpicture_region_count
,
1962 picture_t
***region
, subpicture_t
*subpicture
)
1964 vout_display_sys_t
*sys
= vd
->sys
;
1965 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1966 D3D11_TEXTURE2D_DESC texDesc
;
1971 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
)
1974 *region
= calloc(count
, sizeof(picture_t
*));
1975 if (unlikely(*region
==NULL
))
1977 *subpicture_region_count
= count
;
1980 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
, i
++) {
1981 if (!r
->fmt
.i_width
|| !r
->fmt
.i_height
)
1982 continue; // won't render anything, keep the cache for later
1984 for (int j
= 0; j
< sys
->d3dregion_count
; j
++) {
1985 picture_t
*cache
= sys
->d3dregions
[j
];
1986 if (cache
!= NULL
&& ((d3d_quad_t
*) cache
->p_sys
)->pTexture
) {
1987 ID3D11Texture2D_GetDesc( ((d3d_quad_t
*) cache
->p_sys
)->pTexture
, &texDesc
);
1988 if (texDesc
.Format
== sys
->d3dregion_format
&&
1989 texDesc
.Width
== r
->fmt
.i_visible_width
&&
1990 texDesc
.Height
== r
->fmt
.i_visible_height
) {
1991 (*region
)[i
] = cache
;
1992 memset(&sys
->d3dregions
[j
], 0, sizeof(cache
)); // do not reuse this cached value
1998 picture_t
*quad_picture
= (*region
)[i
];
1999 if (quad_picture
== NULL
) {
2000 d3d_quad_t
*d3dquad
= calloc(1, sizeof(*d3dquad
));
2001 if (unlikely(d3dquad
==NULL
)) {
2004 d3d_quad_cfg_t rgbaCfg
= {
2005 .textureFormat
= sys
->d3dregion_format
,
2006 .resourceFormatYRGB
= sys
->d3dregion_format
,
2008 err
= AllocQuad(vd
, &r
->fmt
, d3dquad
, &rgbaCfg
, sys
->pSPUPixelShader
, false);
2009 if (err
!= VLC_SUCCESS
) {
2010 msg_Err(vd
, "Failed to create %dx%d texture for OSD",
2011 r
->fmt
.i_visible_width
, r
->fmt
.i_visible_height
);
2015 picture_resource_t picres
= {
2016 .p_sys
= (picture_sys_t
*) d3dquad
,
2017 .pf_destroy
= DestroyPictureQuad
,
2019 (*region
)[i
] = picture_NewFromResource(&r
->fmt
, &picres
);
2020 if ((*region
)[i
] == NULL
) {
2021 msg_Err(vd
, "Failed to create %dx%d picture for OSD",
2022 r
->fmt
.i_width
, r
->fmt
.i_height
);
2023 ReleaseQuad(d3dquad
);
2026 quad_picture
= (*region
)[i
];
2029 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)((d3d_quad_t
*) quad_picture
->p_sys
)->pTexture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2030 if( SUCCEEDED(hr
) ) {
2031 err
= CommonUpdatePicture(quad_picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
2032 if (err
!= VLC_SUCCESS
) {
2033 msg_Err(vd
, "Failed to set the buffer on the SPU picture" );
2034 picture_Release(quad_picture
);
2038 picture_CopyPixels(quad_picture
, r
->p_picture
);
2040 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)((d3d_quad_t
*) quad_picture
->p_sys
)->pTexture
, 0);
2042 msg_Err(vd
, "Failed to map the SPU texture (hr=0x%lX)", hr
);
2043 picture_Release(quad_picture
);
2047 d3d_quad_t
*quad
= (d3d_quad_t
*) quad_picture
->p_sys
;
2049 quad
->cropViewport
.Width
= (FLOAT
) r
->fmt
.i_visible_width
* RECTWidth(sys
->rect_dest
) / subpicture
->i_original_picture_width
;
2050 quad
->cropViewport
.Height
= (FLOAT
) r
->fmt
.i_visible_height
* RECTHeight(sys
->rect_dest
) / subpicture
->i_original_picture_height
;
2051 quad
->cropViewport
.MinDepth
= 0.0f
;
2052 quad
->cropViewport
.MaxDepth
= 1.0f
;
2053 quad
->cropViewport
.TopLeftX
= sys
->rect_dest
.left
+ (FLOAT
) r
->i_x
* RECTWidth(sys
->rect_dest
) / subpicture
->i_original_picture_width
;
2054 quad
->cropViewport
.TopLeftY
= sys
->rect_dest
.top
+ (FLOAT
) r
->i_y
* RECTHeight(sys
->rect_dest
) / subpicture
->i_original_picture_height
;
2056 UpdateQuadOpacity(vd
, quad
, r
->i_alpha
/ 255.0f
);