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 /* avoided until we can pass ISwapchainPanel without c++/cx mode
45 # include <windows.ui.xaml.media.dxinterop.h> */
49 #include "../../video_chroma/dxgi_fmt.h"
52 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
53 # define D3DCompile(args...) sys->OurD3DCompile(args)
56 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH
, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
57 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT
, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
58 DEFINE_GUID(GUID_CONTEXT_MUTEX
, 0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
60 static int Open(vlc_object_t
*);
61 static void Close(vlc_object_t
*);
63 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
64 #define HW_BLENDING_TEXT N_("Use hardware blending support")
65 #define HW_BLENDING_LONGTEXT N_(\
66 "Try to use hardware acceleration for subtitle/OSD blending.")
69 set_shortname("Direct3D11")
70 set_description(N_("Direct3D11 video output"))
72 set_category(CAT_VIDEO
)
73 set_subcategory(SUBCAT_VIDEO_VOUT
)
75 add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT
, HW_BLENDING_LONGTEXT
, true)
78 add_integer("winrt-d3dcontext", 0x0, NULL
, NULL
, true); /* ID3D11DeviceContext* */
79 add_integer("winrt-swapchain", 0x0, NULL
, NULL
, true); /* IDXGISwapChain1* */
82 set_capability("vout display", 240)
83 add_shortcut("direct3d11")
84 set_callbacks(Open
, Close
)
87 #ifdef HAVE_ID3D11VIDEODECODER
88 /* VLC_CODEC_D3D11_OPAQUE */
91 ID3D11VideoDecoderOutputView
*decoder
; /* may be NULL for pictures from the pool */
92 ID3D11Texture2D
*texture
;
93 ID3D11DeviceContext
*context
;
98 /* internal picture_t pool */
101 ID3D11Texture2D
*texture
;
103 } picture_sys_pool_t
;
105 /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
106 typedef struct d3d_vertex_t
{
120 FLOAT opacityPadding
[3];
121 } PS_CONSTANT_BUFFER
;
126 FLOAT Colorspace
[4*4];
127 } PS_COLOR_TRANSFORM
;
134 FLOAT Projection
[4*4];
135 } VS_PROJECTION_CONST
;
137 #define SPHERE_RADIUS 1.f
139 #define RECTWidth(r) (int)((r).right - (r).left)
140 #define RECTHeight(r) (int)((r).bottom - (r).top)
142 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
);
144 static void Prepare(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
145 static void Display(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
147 static HINSTANCE
Direct3D11LoadShaderLibrary(void);
148 static void Direct3D11Destroy(vout_display_t
*);
150 static int Direct3D11Open (vout_display_t
*, video_format_t
*);
151 static void Direct3D11Close(vout_display_t
*);
153 static int Direct3D11CreateResources (vout_display_t
*, video_format_t
*);
154 static void Direct3D11DestroyResources(vout_display_t
*);
156 static int Direct3D11CreatePool (vout_display_t
*, video_format_t
*);
157 static void Direct3D11DestroyPool(vout_display_t
*);
159 static void DestroyDisplayPicture(picture_t
*);
160 static void DestroyDisplayPoolPicture(picture_t
*);
161 static int Direct3D11MapTexture(picture_t
*);
162 static int Direct3D11UnmapTexture(picture_t
*);
163 static void Direct3D11DeleteRegions(int, picture_t
**);
164 static int Direct3D11MapSubpicture(vout_display_t
*, int *, picture_t
***, subpicture_t
*);
166 static int AllocQuad(vout_display_t
*, const video_format_t
*, d3d_quad_t
*,
167 d3d_quad_cfg_t
*, ID3D11PixelShader
*, bool b_visible
,
168 video_projection_mode_t
);
169 static void ReleaseQuad(d3d_quad_t
*);
170 static void UpdatePicQuadPosition(vout_display_t
*);
171 static void UpdateQuadOpacity(vout_display_t
*, const d3d_quad_t
*, float);
173 static int Control(vout_display_t
*vd
, int query
, va_list args
);
174 static void Manage(vout_display_t
*vd
);
176 /* TODO: Move to a direct3d11_shaders header */
177 static const char* globVertexShaderFlat
= "\
180 float4 Position : POSITION;\
181 float2 Texture : TEXCOORD0;\
186 float4 Position : SV_POSITION;\
187 float2 Texture : TEXCOORD0;\
190 VS_OUTPUT VS( VS_INPUT In )\
196 static const char* globVertexShaderProjection
= "\
197 cbuffer VS_PROJECTION_CONST : register(b0)\
203 float4x4 Projection;\
207 float4 Position : POSITION;\
208 float2 Texture : TEXCOORD0;\
213 float4 Position : SV_POSITION;\
214 float2 Texture : TEXCOORD0;\
217 VS_OUTPUT VS( VS_INPUT In )\
220 float4 pos = In.Position;\
221 pos = mul(RotY, pos);\
222 pos = mul(RotX, pos);\
223 pos = mul(RotZ, pos);\
224 pos = mul(View, pos);\
225 pos = mul(Projection, pos);\
226 Output.Position = pos;\
227 Output.Texture = In.Texture;\
232 static const char* globPixelShaderDefault
= "\
233 cbuffer PS_CONSTANT_BUFFER : register(b0)\
236 float opacityPadding[3];\
238 Texture2D shaderTexture;\
239 SamplerState SampleType;\
243 float4 Position : SV_POSITION;\
244 float2 Texture : TEXCOORD0;\
247 float4 PS( PS_INPUT In ) : SV_TARGET\
251 rgba = shaderTexture.Sample(SampleType, In.Texture);\
252 rgba.a = rgba.a * Opacity;\
257 static const char *globPixelShaderBiplanarYUV_2RGB
= "\
258 cbuffer PS_CONSTANT_BUFFER : register(b0)\
261 float opacityPadding[3];\
263 cbuffer PS_COLOR_TRANSFORM : register(b1)\
269 float4x4 Colorspace;\
271 Texture2D shaderTextureY;\
272 Texture2D shaderTextureUV;\
273 SamplerState SampleType;\
277 float4 Position : SV_POSITION;\
278 float2 Texture : TEXCOORD0;\
281 float4 PS( PS_INPUT In ) : SV_TARGET\
285 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
286 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
288 yuv.x += WhitePointX;\
289 yuv.y += WhitePointY;\
290 yuv.z += WhitePointZ;\
291 rgba = saturate(mul(yuv, Colorspace));\
296 static const char *globPixelShaderBiplanarYUYV_2RGB
= "\
297 cbuffer PS_CONSTANT_BUFFER : register(b0)\
300 float opacityPadding[3];\
302 cbuffer PS_COLOR_TRANSFORM : register(b1)\
308 float4x4 Colorspace;\
310 Texture2D shaderTextureYUYV;\
311 SamplerState SampleType;\
315 float4 Position : SV_POSITION;\
316 float2 Texture : TEXCOORD0;\
319 float4 PS( PS_INPUT In ) : SV_TARGET\
323 yuv.x = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
324 yuv.y = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
325 yuv.z = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
327 yuv.x += WhitePointX;\
328 yuv.y += WhitePointY;\
329 yuv.z += WhitePointZ;\
330 rgba = saturate(mul(yuv, Colorspace));\
335 #if !VLC_WINSTORE_APP
336 static int OpenHwnd(vout_display_t
*vd
)
338 HINSTANCE hd3d11_dll
= LoadLibrary(TEXT("D3D11.DLL"));
340 msg_Warn(vd
, "cannot load d3d11.dll, aborting");
344 HINSTANCE hd3dcompiler_dll
= Direct3D11LoadShaderLibrary();
345 if (!hd3dcompiler_dll
) {
346 msg_Err(vd
, "cannot load d3dcompiler.dll, aborting");
347 Direct3D11Destroy(vd
);
351 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
355 sys
->hd3d11_dll
= hd3d11_dll
;
356 sys
->hd3dcompiler_dll
= hd3dcompiler_dll
;
358 sys
->OurD3DCompile
= (void *)GetProcAddress(sys
->hd3dcompiler_dll
, "D3DCompile");
359 if (!sys
->OurD3DCompile
) {
360 msg_Err(vd
, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
361 Direct3D11Destroy(vd
);
365 sys
->OurD3D11CreateDevice
=
366 (void *)GetProcAddress(hd3d11_dll
, "D3D11CreateDevice");
367 if (!sys
->OurD3D11CreateDevice
) {
368 msg_Err(vd
, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
369 Direct3D11Destroy(vd
);
375 static int OpenCoreW(vout_display_t
*vd
)
377 IDXGISwapChain1
* dxgiswapChain
= var_InheritInteger(vd
, "winrt-swapchain");
380 ID3D11DeviceContext
* d3dcontext
= var_InheritInteger(vd
, "winrt-d3dcontext");
383 ID3D11Device
* d3ddevice
= NULL
;
384 ID3D11DeviceContext_GetDevice(d3dcontext
, &d3ddevice
);
388 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
392 sys
->dxgiswapChain
= dxgiswapChain
;
393 sys
->d3ddevice
= d3ddevice
;
394 sys
->d3dcontext
= d3dcontext
;
395 IDXGISwapChain_AddRef (sys
->dxgiswapChain
);
396 ID3D11Device_AddRef (sys
->d3ddevice
);
397 ID3D11DeviceContext_AddRef(sys
->d3dcontext
);
403 static bool is_d3d11_opaque(vlc_fourcc_t chroma
)
407 case VLC_CODEC_D3D11_OPAQUE
:
408 case VLC_CODEC_D3D11_OPAQUE_10B
:
415 static int Open(vlc_object_t
*object
)
417 vout_display_t
*vd
= (vout_display_t
*)object
;
419 #if !VLC_WINSTORE_APP
420 int ret
= OpenHwnd(vd
);
422 int ret
= OpenCoreW(vd
);
425 if (ret
!= VLC_SUCCESS
)
432 if (Direct3D11Open(vd
, &fmt
)) {
433 msg_Err(vd
, "Direct3D11 could not be opened");
437 vout_display_info_t info
= vd
->info
;
438 info
.is_slow
= !is_d3d11_opaque(fmt
.i_chroma
);
439 info
.has_double_click
= true;
440 info
.has_hide_mouse
= false;
441 info
.has_pictures_invalid
= !is_d3d11_opaque(fmt
.i_chroma
);
443 if (var_InheritBool(vd
, "direct3d11-hw-blending") &&
444 vd
->sys
->d3dregion_format
!= DXGI_FORMAT_UNKNOWN
)
445 info
.subpicture_chromas
= vd
->sys
->pSubpictureChromas
;
447 info
.subpicture_chromas
= NULL
;
449 video_format_Clean(&vd
->fmt
);
450 video_format_Copy(&vd
->fmt
, &fmt
);
454 vd
->prepare
= Prepare
;
455 vd
->display
= Display
;
456 vd
->control
= Control
;
459 msg_Dbg(vd
, "Direct3D11 Open Succeeded");
468 static void Close(vlc_object_t
*object
)
470 vout_display_t
* vd
= (vout_display_t
*)object
;
474 Direct3D11Destroy(vd
);
478 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned pool_size
)
480 if ( vd
->sys
->pool
!= NULL
)
481 return vd
->sys
->pool
;
483 if (pool_size
> 30) {
484 msg_Err(vd
, "Avoid crashing when using ID3D11VideoDecoderOutputView with too many slices (%d)", pool_size
);
488 #ifdef HAVE_ID3D11VIDEODECODER
489 picture_t
** pictures
= NULL
;
490 unsigned picture_count
= 0;
493 ID3D10Multithread
*pMultithread
;
494 hr
= ID3D11Device_QueryInterface( vd
->sys
->d3ddevice
, &IID_ID3D10Multithread
, (void **)&pMultithread
);
496 ID3D10Multithread_SetMultithreadProtected(pMultithread
, TRUE
);
497 ID3D10Multithread_Release(pMultithread
);
500 pictures
= calloc(pool_size
, sizeof(*pictures
));
504 D3D11_TEXTURE2D_DESC texDesc
;
505 ZeroMemory(&texDesc
, sizeof(texDesc
));
506 texDesc
.Width
= vd
->fmt
.i_width
;
507 texDesc
.Height
= vd
->fmt
.i_height
;
508 texDesc
.MipLevels
= 1;
509 texDesc
.Format
= vd
->sys
->picQuadConfig
.textureFormat
;
510 texDesc
.SampleDesc
.Count
= 1;
511 texDesc
.MiscFlags
= 0; //D3D11_RESOURCE_MISC_SHARED;
512 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
513 texDesc
.BindFlags
= D3D11_BIND_DECODER
;
514 texDesc
.CPUAccessFlags
= 0;
516 texDesc
.ArraySize
= pool_size
;
518 ID3D11Texture2D
*texture
;
519 hr
= ID3D11Device_CreateTexture2D( vd
->sys
->d3ddevice
, &texDesc
, NULL
, &texture
);
521 msg_Err(vd
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
525 for (picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
526 picture_sys_t
*picsys
= calloc(1, sizeof(*picsys
));
527 if (unlikely(picsys
== NULL
))
530 ID3D11Texture2D_AddRef(texture
);
531 picsys
->texture
= texture
;
532 picsys
->slice_index
= picture_count
;
533 picsys
->context
= vd
->sys
->d3dcontext
;
535 picture_resource_t resource
= {
537 .pf_destroy
= DestroyDisplayPoolPicture
,
540 picture_t
*picture
= picture_NewFromResource(&vd
->fmt
, &resource
);
541 if (unlikely(picture
== NULL
)) {
543 msg_Err( vd
, "Failed to create picture %d in the pool.", picture_count
);
547 pictures
[picture_count
] = picture
;
548 /* each picture_t holds a ref to the context and release it on Destroy */
549 ID3D11DeviceContext_AddRef(picsys
->context
);
551 ID3D11Texture2D_Release(texture
);
553 msg_Dbg(vd
, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d) texture 0x%p context 0x%p",
554 pool_size
, vd
->fmt
.i_width
, vd
->fmt
.i_height
, texture
, vd
->sys
->d3dcontext
);
556 picture_pool_configuration_t pool_cfg
;
557 memset(&pool_cfg
, 0, sizeof(pool_cfg
));
558 pool_cfg
.picture_count
= pool_size
;
559 pool_cfg
.picture
= pictures
;
561 vd
->sys
->pool
= picture_pool_NewExtended( &pool_cfg
);
564 if (vd
->sys
->pool
==NULL
&& pictures
) {
565 msg_Dbg(vd
, "Failed to create the picture d3d11 pool");
566 for (unsigned i
=0;i
<picture_count
; ++i
)
567 DestroyDisplayPoolPicture(pictures
[i
]);
570 /* create an empty pool to avoid crashing */
571 picture_pool_configuration_t pool_cfg
;
572 memset( &pool_cfg
, 0, sizeof( pool_cfg
) );
573 pool_cfg
.picture_count
= 0;
575 vd
->sys
->pool
= picture_pool_NewExtended( &pool_cfg
);
578 return vd
->sys
->pool
;
581 #ifdef HAVE_ID3D11VIDEODECODER
582 static void DestroyDisplayPoolPicture(picture_t
*picture
)
584 picture_sys_t
*p_sys
= (picture_sys_t
*) picture
->p_sys
;
587 ID3D11Texture2D_Release(p_sys
->texture
);
589 ID3D11DeviceContext_Release(p_sys
->context
);
596 static void DestroyDisplayPicture(picture_t
*picture
)
598 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*) picture
->p_sys
;
601 ID3D11Texture2D_Release(p_sys
->texture
);
607 static HRESULT
UpdateBackBuffer(vout_display_t
*vd
)
609 vout_display_sys_t
*sys
= vd
->sys
;
611 ID3D11Texture2D
* pDepthStencil
;
612 ID3D11Texture2D
* pBackBuffer
;
613 uint32_t i_width
= RECTWidth(sys
->rect_dest_clipped
);
614 uint32_t i_height
= RECTHeight(sys
->rect_dest_clipped
);
616 UINT dataSize
= sizeof(i_width
);
617 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_WIDTH
, &dataSize
, &i_width
);
619 msg_Err(vd
, "Can't get swapchain width, size %d. (hr=0x%lX)", hr
, dataSize
);
622 dataSize
= sizeof(i_height
);
623 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_HEIGHT
, &dataSize
, &i_height
);
625 msg_Err(vd
, "Can't get swapchain height, size %d. (hr=0x%lX)", hr
, dataSize
);
630 if (sys
->d3drenderTargetView
) {
631 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
632 sys
->d3drenderTargetView
= NULL
;
634 if (sys
->d3ddepthStencilView
) {
635 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
636 sys
->d3ddepthStencilView
= NULL
;
639 hr
= IDXGISwapChain_ResizeBuffers(sys
->dxgiswapChain
, 0, i_width
, i_height
,
640 DXGI_FORMAT_UNKNOWN
, 0);
642 msg_Err(vd
, "Failed to resize the backbuffer. (hr=0x%lX)", hr
);
646 hr
= IDXGISwapChain_GetBuffer(sys
->dxgiswapChain
, 0, &IID_ID3D11Texture2D
, (LPVOID
*)&pBackBuffer
);
648 msg_Err(vd
, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr
);
652 hr
= ID3D11Device_CreateRenderTargetView(sys
->d3ddevice
, (ID3D11Resource
*)pBackBuffer
, NULL
, &sys
->d3drenderTargetView
);
653 ID3D11Texture2D_Release(pBackBuffer
);
655 msg_Err(vd
, "Failed to create the target view. (hr=0x%lX)", hr
);
659 D3D11_TEXTURE2D_DESC deptTexDesc
;
660 memset(&deptTexDesc
, 0,sizeof(deptTexDesc
));
661 deptTexDesc
.ArraySize
= 1;
662 deptTexDesc
.BindFlags
= D3D11_BIND_DEPTH_STENCIL
;
663 deptTexDesc
.CPUAccessFlags
= 0;
664 deptTexDesc
.Format
= DXGI_FORMAT_D24_UNORM_S8_UINT
;
665 deptTexDesc
.Width
= i_width
;
666 deptTexDesc
.Height
= i_height
;
667 deptTexDesc
.MipLevels
= 1;
668 deptTexDesc
.MiscFlags
= 0;
669 deptTexDesc
.SampleDesc
.Count
= 1;
670 deptTexDesc
.SampleDesc
.Quality
= 0;
671 deptTexDesc
.Usage
= D3D11_USAGE_DEFAULT
;
673 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &deptTexDesc
, NULL
, &pDepthStencil
);
675 msg_Err(vd
, "Could not create the depth stencil texture. (hr=0x%lX)", hr
);
679 D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc
;
680 memset(&depthViewDesc
, 0, sizeof(depthViewDesc
));
682 depthViewDesc
.Format
= deptTexDesc
.Format
;
683 depthViewDesc
.ViewDimension
= D3D11_DSV_DIMENSION_TEXTURE2D
;
684 depthViewDesc
.Texture2D
.MipSlice
= 0;
686 hr
= ID3D11Device_CreateDepthStencilView(sys
->d3ddevice
, (ID3D11Resource
*)pDepthStencil
, &depthViewDesc
, &sys
->d3ddepthStencilView
);
687 ID3D11Texture2D_Release(pDepthStencil
);
690 msg_Err(vd
, "Could not create the depth stencil view. (hr=0x%lX)", hr
);
697 /* rotation around the Z axis */
698 static void getZRotMatrix(float theta
, FLOAT matrix
[static 16])
702 sincosf(theta
, &st
, &ct
);
712 memcpy(matrix
, m
, sizeof(m
));
715 /* rotation around the Y axis */
716 static void getYRotMatrix(float theta
, FLOAT matrix
[static 16])
720 sincosf(theta
, &st
, &ct
);
730 memcpy(matrix
, m
, sizeof(m
));
733 /* rotation around the X axis */
734 static void getXRotMatrix(float phi
, FLOAT matrix
[static 16])
738 sincosf(phi
, &sp
, &cp
);
748 memcpy(matrix
, m
, sizeof(m
));
751 static void getZoomMatrix(float zoom
, FLOAT matrix
[static 16]) {
755 1.0f
, 0.0f
, 0.0f
, 0.0f
,
756 0.0f
, 1.0f
, 0.0f
, 0.0f
,
757 0.0f
, 0.0f
, 1.0f
, 0.0f
,
758 0.0f
, 0.0f
, zoom
, 1.0f
761 memcpy(matrix
, m
, sizeof(m
));
764 /* perspective matrix see https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml */
765 static void getProjectionMatrix(float sar
, float fovy
, FLOAT matrix
[static 16]) {
770 float f
= 1.f
/ tanf(fovy
/ 2.f
);
773 f
/ sar
, 0.f
, 0.f
, 0.f
,
775 0.f
, 0.f
, (zNear
+ zFar
) / (zNear
- zFar
), -1.f
,
776 0.f
, 0.f
, (2 * zNear
* zFar
) / (zNear
- zFar
), 0.f
};
778 memcpy(matrix
, m
, sizeof(m
));
781 static float UpdateFOVy(float f_fovx
, float f_sar
)
783 return 2 * atanf(tanf(f_fovx
/ 2) / f_sar
);
786 static float UpdateZ(float f_fovx
, float f_fovy
)
788 /* Do trigonometry to calculate the minimal z value
789 * that will allow us to zoom out without seeing the outside of the
790 * sphere (black borders). */
791 float tan_fovx_2
= tanf(f_fovx
/ 2);
792 float tan_fovy_2
= tanf(f_fovy
/ 2);
793 float z_min
= - SPHERE_RADIUS
/ sinf(atanf(sqrtf(
794 tan_fovx_2
* tan_fovx_2
+ tan_fovy_2
* tan_fovy_2
)));
796 /* The FOV value above which z is dynamically calculated. */
797 const float z_thresh
= 90.f
;
800 if (f_fovx
<= z_thresh
* M_PI
/ 180)
804 float f
= z_min
/ ((FIELD_OF_VIEW_DEGREES_MAX
- z_thresh
) * M_PI
/ 180);
805 f_z
= f
* f_fovx
- f
* z_thresh
* M_PI
/ 180;
812 static void SetQuadVSProjection(vout_display_t
*vd
, d3d_quad_t
*quad
, const vlc_viewpoint_t
*p_vp
)
814 if (!quad
->pVertexShaderConstants
)
817 #define RAD(d) ((float) ((d) * M_PI / 180.f))
818 float f_fovx
= RAD(p_vp
->fov
);
819 if ( f_fovx
> FIELD_OF_VIEW_DEGREES_MAX
* M_PI
/ 180 + 0.001f
||
823 float f_sar
= (float) vd
->cfg
->display
.width
/ vd
->cfg
->display
.height
;
824 float f_teta
= RAD(p_vp
->yaw
) - (float) M_PI_2
;
825 float f_phi
= RAD(p_vp
->pitch
);
826 float f_roll
= RAD(p_vp
->roll
);
827 float f_fovy
= UpdateFOVy(f_fovx
, f_sar
);
828 float f_z
= UpdateZ(f_fovx
, f_fovy
);
830 vout_display_sys_t
*sys
= vd
->sys
;
832 D3D11_MAPPED_SUBRESOURCE mapped
;
833 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexShaderConstants
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mapped
);
835 VS_PROJECTION_CONST
*dst_data
= mapped
.pData
;
836 getXRotMatrix(f_phi
, dst_data
->RotX
);
837 getYRotMatrix(f_teta
, dst_data
->RotY
);
838 getZRotMatrix(f_roll
, dst_data
->RotZ
);
839 getZoomMatrix(SPHERE_RADIUS
* f_z
, dst_data
->View
);
840 getProjectionMatrix(f_sar
, f_fovy
, dst_data
->Projection
);
842 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexShaderConstants
, 0);
846 static void CropStagingFormat(vout_display_t
*vd
, video_format_t
*backup_fmt
)
848 if ( vd
->sys
->stagingQuad
.pTexture
== NULL
)
851 video_format_Copy( backup_fmt
, &vd
->source
);
852 /* the texture we display is a cropped version of the source */
853 vd
->source
.i_x_offset
= 0;
854 vd
->source
.i_y_offset
= 0;
855 vd
->source
.i_width
= vd
->source
.i_visible_width
;
856 vd
->source
.i_height
= vd
->source
.i_visible_height
;
859 static void UncropStagingFormat(vout_display_t
*vd
, video_format_t
*backup_fmt
)
861 if ( vd
->sys
->stagingQuad
.pTexture
== NULL
)
863 video_format_Copy( &vd
->source
, backup_fmt
);
866 static int Control(vout_display_t
*vd
, int query
, va_list args
)
868 video_format_t core_source
;
869 CropStagingFormat( vd
, &core_source
);
870 int res
= CommonControl( vd
, query
, args
);
872 if (query
== VOUT_DISPLAY_CHANGE_VIEWPOINT
)
874 const vout_display_cfg_t
*cfg
= va_arg(args
, const vout_display_cfg_t
*);
875 if ( vd
->sys
->picQuad
.pVertexShaderConstants
)
877 SetQuadVSProjection( vd
, &vd
->sys
->picQuad
, &cfg
->viewpoint
);
882 UncropStagingFormat( vd
, &core_source
);
886 static void Manage(vout_display_t
*vd
)
888 vout_display_sys_t
*sys
= vd
->sys
;
889 RECT size_before
= sys
->rect_dest_clipped
;
891 video_format_t core_source
;
892 CropStagingFormat( vd
, &core_source
);
895 if (RECTWidth(size_before
) != RECTWidth(sys
->rect_dest_clipped
) ||
896 RECTHeight(size_before
) != RECTHeight(sys
->rect_dest_clipped
))
898 #if defined(HAVE_ID3D11VIDEODECODER)
899 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
901 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
904 msg_Dbg(vd
, "Manage detected size change %dx%d", RECTWidth(sys
->rect_dest_clipped
),
905 RECTHeight(sys
->rect_dest_clipped
));
907 UpdateBackBuffer(vd
);
909 UpdatePicQuadPosition(vd
);
910 #if defined(HAVE_ID3D11VIDEODECODER)
911 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
913 ReleaseMutex( sys
->context_lock
);
917 UncropStagingFormat( vd
, &core_source
);
920 static void Prepare(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
922 vout_display_sys_t
*sys
= vd
->sys
;
924 if ( !is_d3d11_opaque(picture
->format
.i_chroma
) &&
925 sys
->stagingQuad
.pTexture
!= NULL
)
927 Direct3D11UnmapTexture(picture
);
930 box
.left
= picture
->format
.i_x_offset
;
931 /* box.right = picture->format.i_x_offset + picture->format.i_visible_width; */
932 box
.top
= picture
->format
.i_y_offset
;
933 /* box.bottom = picture->format.i_y_offset + picture->format.i_visible_height; */
937 D3D11_TEXTURE2D_DESC dstDesc
;
938 ID3D11Texture2D_GetDesc(sys
->picQuad
.pTexture
, &dstDesc
);
939 box
.bottom
= box
.top
+ dstDesc
.Height
;
940 box
.right
= box
.left
+ dstDesc
.Width
;
942 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
943 (ID3D11Resource
*) sys
->picQuad
.pTexture
,
945 (ID3D11Resource
*) sys
->stagingQuad
.pTexture
,
949 #ifdef HAVE_ID3D11VIDEODECODER
950 if (is_d3d11_opaque(picture
->format
.i_chroma
)) {
951 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
953 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
956 picture_sys_t
*p_sys
= picture
->p_sys
;
957 D3D11_TEXTURE2D_DESC texDesc
;
958 ID3D11Texture2D_GetDesc( p_sys
->texture
, &texDesc
);
959 if (texDesc
.Format
== DXGI_FORMAT_NV12
|| texDesc
.Format
== DXGI_FORMAT_P010
)
961 box
.left
= (picture
->format
.i_x_offset
+ 1) & ~1;
962 box
.right
= (picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
) & ~1;
963 box
.top
= (picture
->format
.i_y_offset
+ 1) & ~1;
964 box
.bottom
= (picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
) & ~1;
968 box
.left
= picture
->format
.i_x_offset
;
969 box
.right
= picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
;
970 box
.top
= picture
->format
.i_y_offset
;
971 box
.bottom
= picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
;
976 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
977 (ID3D11Resource
*) sys
->picQuad
.pTexture
,
979 (ID3D11Resource
*) p_sys
->texture
,
980 p_sys
->slice_index
, &box
);
985 int subpicture_region_count
= 0;
986 picture_t
**subpicture_regions
= NULL
;
987 Direct3D11MapSubpicture(vd
, &subpicture_region_count
, &subpicture_regions
, subpicture
);
988 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
989 sys
->d3dregion_count
= subpicture_region_count
;
990 sys
->d3dregions
= subpicture_regions
;
994 static void DisplayD3DPicture(vout_display_sys_t
*sys
, d3d_quad_t
*quad
)
996 UINT stride
= sizeof(d3d_vertex_t
);
999 /* Render the quad */
1001 ID3D11DeviceContext_IASetVertexBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexBuffer
, &stride
, &offset
);
1002 ID3D11DeviceContext_IASetIndexBuffer(sys
->d3dcontext
, quad
->pIndexBuffer
, DXGI_FORMAT_R16_UINT
, 0);
1003 if ( quad
->pVertexShaderConstants
)
1004 ID3D11DeviceContext_VSSetConstantBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexShaderConstants
);
1006 ID3D11DeviceContext_VSSetShader(sys
->d3dcontext
, quad
->d3dvertexShader
, NULL
, 0);
1009 ID3D11DeviceContext_PSSetShader(sys
->d3dcontext
, quad
->d3dpixelShader
, NULL
, 0);
1011 ID3D11DeviceContext_PSSetConstantBuffers(sys
->d3dcontext
, 0, quad
->PSConstantsCount
, quad
->pPixelShaderConstants
);
1012 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 0, 1, &quad
->d3dresViewY
);
1013 if( quad
->d3dresViewUV
)
1014 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 1, 1, &quad
->d3dresViewUV
);
1016 ID3D11DeviceContext_RSSetViewports(sys
->d3dcontext
, 1, &quad
->cropViewport
);
1018 ID3D11DeviceContext_DrawIndexed(sys
->d3dcontext
, quad
->indexCount
, 0, 0);
1021 static void Display(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
1023 vout_display_sys_t
*sys
= vd
->sys
;
1025 FLOAT blackRGBA
[4] = {0.0f
, 0.0f
, 0.0f
, 1.0f
};
1026 ID3D11DeviceContext_ClearRenderTargetView(sys
->d3dcontext
, sys
->d3drenderTargetView
, blackRGBA
);
1028 /* no ID3D11Device operations should come here */
1030 ID3D11DeviceContext_OMSetRenderTargets(sys
->d3dcontext
, 1, &sys
->d3drenderTargetView
, sys
->d3ddepthStencilView
);
1032 ID3D11DeviceContext_ClearDepthStencilView(sys
->d3dcontext
, sys
->d3ddepthStencilView
, D3D11_CLEAR_DEPTH
| D3D11_CLEAR_STENCIL
, 1.0f
, 0);
1034 if ( !is_d3d11_opaque(picture
->format
.i_chroma
) &&
1035 sys
->stagingQuad
.pTexture
== NULL
)
1036 Direct3D11UnmapTexture(picture
);
1038 /* Render the quad */
1039 DisplayD3DPicture(sys
, &sys
->picQuad
);
1042 // draw the additional vertices
1043 for (int i
= 0; i
< sys
->d3dregion_count
; ++i
) {
1044 if (sys
->d3dregions
[i
])
1045 DisplayD3DPicture(sys
, (d3d_quad_t
*) sys
->d3dregions
[i
]->p_sys
);
1049 DXGI_PRESENT_PARAMETERS presentParams
;
1050 memset(&presentParams
, 0, sizeof(presentParams
));
1051 HRESULT hr
= IDXGISwapChain1_Present1(sys
->dxgiswapChain
, 0, 0, &presentParams
);
1052 if (hr
== DXGI_ERROR_DEVICE_REMOVED
|| hr
== DXGI_ERROR_DEVICE_RESET
)
1054 /* TODO device lost */
1055 msg_Dbg(vd
, "SwapChain Present failed. (hr=0x%lX)", hr
);
1057 #if defined(HAVE_ID3D11VIDEODECODER)
1058 if( is_d3d11_opaque(picture
->format
.i_chroma
) && sys
->context_lock
!= INVALID_HANDLE_VALUE
) {
1059 ReleaseMutex( sys
->context_lock
);
1063 picture_Release(picture
);
1065 subpicture_Delete(subpicture
);
1070 static void Direct3D11Destroy(vout_display_t
*vd
)
1072 #if !VLC_WINSTORE_APP
1073 vout_display_sys_t
*sys
= vd
->sys
;
1075 if (sys
->hd3d11_dll
)
1076 FreeLibrary(sys
->hd3d11_dll
);
1077 if (sys
->hd3dcompiler_dll
)
1078 FreeLibrary(sys
->hd3dcompiler_dll
);
1080 sys
->OurD3D11CreateDevice
= NULL
;
1081 sys
->OurD3D11CreateDeviceAndSwapChain
= NULL
;
1082 sys
->OurD3DCompile
= NULL
;
1083 sys
->hdxgi_dll
= NULL
;
1084 sys
->hd3d11_dll
= NULL
;
1085 sys
->hd3dcompiler_dll
= NULL
;
1091 #if !VLC_WINSTORE_APP
1092 static HINSTANCE
Direct3D11LoadShaderLibrary(void)
1094 HINSTANCE instance
= NULL
;
1095 /* d3dcompiler_47 is the latest on windows 8.1 */
1096 for (int i
= 47; i
> 41; --i
) {
1098 _sntprintf(filename
, 19, TEXT("D3DCOMPILER_%d.dll"), i
);
1099 instance
= LoadLibrary(filename
);
1100 if (instance
) break;
1107 static int Direct3D11Open(vout_display_t
*vd
, video_format_t
*fmt
)
1109 vout_display_sys_t
*sys
= vd
->sys
;
1112 #if !VLC_WINSTORE_APP
1114 UINT creationFlags
= 0;
1117 # if !defined(NDEBUG) && defined(_MSC_VER)
1118 creationFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
1121 DXGI_SWAP_CHAIN_DESC1 scd
;
1122 memset(&scd
, 0, sizeof(scd
));
1123 scd
.BufferCount
= 2;
1124 scd
.BufferUsage
= DXGI_USAGE_RENDER_TARGET_OUTPUT
;
1125 scd
.SampleDesc
.Count
= 1;
1126 scd
.SampleDesc
.Quality
= 0;
1127 scd
.Width
= fmt
->i_visible_width
;
1128 scd
.Height
= fmt
->i_visible_height
;
1129 switch(fmt
->i_chroma
)
1131 case VLC_CODEC_D3D11_OPAQUE_10B
:
1132 scd
.Format
= DXGI_FORMAT_R10G10B10A2_UNORM
;
1135 scd
.Format
= DXGI_FORMAT_R8G8B8A8_UNORM
; /* TODO: use DXGI_FORMAT_NV12 */
1138 //scd.Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
1139 scd
.SwapEffect
= DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
;
1141 IDXGIAdapter
*dxgiadapter
;
1142 static const D3D_FEATURE_LEVEL featureLevels
[] =
1144 0xc000 /* D3D_FEATURE_LEVEL_12_1 */,
1145 0xc100 /* D3D_FEATURE_LEVEL_12_0 */,
1146 D3D_FEATURE_LEVEL_11_1
,
1147 D3D_FEATURE_LEVEL_11_0
,
1148 D3D_FEATURE_LEVEL_10_1
,
1149 D3D_FEATURE_LEVEL_10_0
,
1150 D3D_FEATURE_LEVEL_9_3
,
1151 D3D_FEATURE_LEVEL_9_2
,
1152 D3D_FEATURE_LEVEL_9_1
,
1155 static const D3D_DRIVER_TYPE driverAttempts
[] = {
1156 D3D_DRIVER_TYPE_HARDWARE
,
1157 D3D_DRIVER_TYPE_WARP
,
1159 D3D_DRIVER_TYPE_REFERENCE
,
1163 for (UINT driver
= 0; driver
< ARRAYSIZE(driverAttempts
); driver
++) {
1164 D3D_FEATURE_LEVEL i_feature_level
;
1165 hr
= D3D11CreateDevice(NULL
, driverAttempts
[driver
], NULL
, creationFlags
,
1166 featureLevels
, 9, D3D11_SDK_VERSION
,
1167 &sys
->d3ddevice
, &i_feature_level
, &sys
->d3dcontext
);
1168 if (SUCCEEDED(hr
)) {
1170 msg_Dbg(vd
, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
1171 (void *)sys
->d3ddevice
, (void *)sys
->d3dcontext
,
1172 driverAttempts
[driver
], i_feature_level
);
1179 msg_Err(vd
, "Could not Create the D3D11 device. (hr=0x%lX)", hr
);
1180 return VLC_EGENERIC
;
1183 IDXGIDevice
*pDXGIDevice
= NULL
;
1184 hr
= ID3D11Device_QueryInterface(sys
->d3ddevice
, &IID_IDXGIDevice
, (void **)&pDXGIDevice
);
1186 msg_Err(vd
, "Could not Query DXGI Interface. (hr=0x%lX)", hr
);
1187 return VLC_EGENERIC
;
1190 hr
= IDXGIDevice_GetAdapter(pDXGIDevice
, &dxgiadapter
);
1191 IDXGIAdapter_Release(pDXGIDevice
);
1193 msg_Err(vd
, "Could not get the DXGI Adapter. (hr=0x%lX)", hr
);
1194 return VLC_EGENERIC
;
1197 hr
= IDXGIAdapter_GetParent(dxgiadapter
, &IID_IDXGIFactory2
, (void **)&sys
->dxgifactory
);
1198 IDXGIAdapter_Release(dxgiadapter
);
1200 msg_Err(vd
, "Could not get the DXGI Factory. (hr=0x%lX)", hr
);
1201 return VLC_EGENERIC
;
1204 hr
= IDXGIFactory2_CreateSwapChainForHwnd(sys
->dxgifactory
, (IUnknown
*)sys
->d3ddevice
,
1205 sys
->hvideownd
, &scd
, NULL
, NULL
, &sys
->dxgiswapChain
);
1206 IDXGIFactory2_Release(sys
->dxgifactory
);
1208 msg_Err(vd
, "Could not create the SwapChain. (hr=0x%lX)", hr
);
1209 return VLC_EGENERIC
;
1213 vlc_fourcc_t i_src_chroma
= fmt
->i_chroma
;
1216 // look for the requested pixel format first
1217 UINT i_quadSupportFlags
= D3D11_FORMAT_SUPPORT_TEXTURE2D
| D3D11_FORMAT_SUPPORT_SHADER_LOAD
;
1218 UINT i_formatSupport
;
1219 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1220 output_format
->name
!= NULL
; ++output_format
)
1222 if( i_src_chroma
== output_format
->fourcc
)
1224 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1225 output_format
->formatTexture
,
1226 &i_formatSupport
)) &&
1227 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
)
1229 msg_Dbg( vd
, "Using pixel format %s from chroma %4.4s", output_format
->name
,
1230 (char *)&i_src_chroma
);
1231 fmt
->i_chroma
= output_format
->fourcc
;
1232 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1233 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1234 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1235 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1241 // look for any pixel format that we can handle with enough pixels per channel
1242 if ( !fmt
->i_chroma
)
1244 uint8_t bits_per_channel
;
1245 switch (i_src_chroma
)
1247 case VLC_CODEC_D3D11_OPAQUE
:
1248 bits_per_channel
= 8;
1250 case VLC_CODEC_D3D11_OPAQUE_10B
:
1251 bits_per_channel
= 10;
1255 const vlc_chroma_description_t
*p_format
= vlc_fourcc_GetChromaDescription(i_src_chroma
);
1256 bits_per_channel
= p_format
== NULL
|| p_format
->pixel_bits
== 0 ? 8 : p_format
->pixel_bits
;
1261 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1262 output_format
->name
!= NULL
; ++output_format
)
1264 if( bits_per_channel
<= output_format
->bitsPerChannel
&&
1265 !is_d3d11_opaque(output_format
->fourcc
) )
1267 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1268 output_format
->formatTexture
,
1269 &i_formatSupport
)) &&
1270 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
)
1272 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", output_format
->name
,
1273 (char *)&i_src_chroma
);
1274 fmt
->i_chroma
= output_format
->fourcc
;
1275 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1276 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1277 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1278 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1284 // look for any pixel format that we can handle
1285 if ( !fmt
->i_chroma
)
1287 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1288 output_format
->name
!= NULL
; ++output_format
)
1290 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1291 output_format
->formatTexture
,
1292 &i_formatSupport
)) &&
1293 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
&&
1294 !is_d3d11_opaque(output_format
->fourcc
) )
1296 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", output_format
->name
,
1297 (char *)&i_src_chroma
);
1298 fmt
->i_chroma
= output_format
->fourcc
;
1299 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1300 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1301 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1302 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1307 if ( !fmt
->i_chroma
)
1309 msg_Err(vd
, "Could not get a suitable texture pixel format");
1310 return VLC_EGENERIC
;
1313 /* check the region pixel format */
1314 i_quadSupportFlags
|= D3D11_FORMAT_SUPPORT_BLENDABLE
;
1315 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1316 DXGI_FORMAT_R8G8B8A8_UNORM
,
1317 &i_formatSupport
)) &&
1318 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
) {
1319 sys
->d3dregion_format
= DXGI_FORMAT_R8G8B8A8_UNORM
;
1320 sys
->pSubpictureChromas
[0] = VLC_CODEC_RGBA
;
1321 sys
->pSubpictureChromas
[1] = 0;
1322 } else if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1323 DXGI_FORMAT_B8G8R8A8_UNORM
,
1324 &i_formatSupport
)) &&
1325 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
) {
1326 sys
->d3dregion_format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
1327 sys
->pSubpictureChromas
[0] = VLC_CODEC_BGRA
;
1328 sys
->pSubpictureChromas
[1] = 0;
1330 sys
->d3dregion_format
= DXGI_FORMAT_UNKNOWN
;
1333 if (sys
->picQuadConfig
.resourceFormatYRGB
== DXGI_FORMAT_R8_UNORM
||
1334 sys
->picQuadConfig
.resourceFormatYRGB
== DXGI_FORMAT_R16_UNORM
)
1335 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_2RGB
;
1337 if (fmt
->i_chroma
== VLC_CODEC_YUYV
)
1338 sys
->d3dPxShader
= globPixelShaderBiplanarYUYV_2RGB
;
1340 sys
->d3dPxShader
= globPixelShaderDefault
;
1342 if (sys
->d3dregion_format
!= DXGI_FORMAT_UNKNOWN
)
1343 sys
->psz_rgbaPxShader
= globPixelShaderDefault
;
1345 sys
->psz_rgbaPxShader
= NULL
;
1347 if ( fmt
->i_height
!= fmt
->i_visible_height
|| fmt
->i_width
!= fmt
->i_visible_width
)
1349 msg_Dbg( vd
, "use a staging texture to crop to visible size" );
1350 AllocQuad( vd
, fmt
, &sys
->stagingQuad
, &sys
->picQuadConfig
, NULL
, false,
1351 PROJECTION_MODE_RECTANGULAR
);
1354 video_format_t core_source
;
1355 CropStagingFormat( vd
, &core_source
);
1356 UpdateRects(vd
, NULL
, NULL
, true);
1357 UncropStagingFormat( vd
, &core_source
);
1359 #if defined(HAVE_ID3D11VIDEODECODER)
1360 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1362 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1365 if (Direct3D11CreateResources(vd
, fmt
)) {
1366 #if defined(HAVE_ID3D11VIDEODECODER)
1367 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1369 ReleaseMutex( sys
->context_lock
);
1372 msg_Err(vd
, "Failed to allocate resources");
1373 Direct3D11DestroyResources(vd
);
1374 return VLC_EGENERIC
;
1376 #if defined(HAVE_ID3D11VIDEODECODER)
1377 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1379 ReleaseMutex( sys
->context_lock
);
1383 #if !VLC_WINSTORE_APP
1384 EventThreadUpdateTitle(sys
->event
, VOUT_TITLE
" (Direct3D11 output)");
1387 msg_Dbg(vd
, "Direct3D11 device adapter successfully initialized");
1391 static void Direct3D11Close(vout_display_t
*vd
)
1393 vout_display_sys_t
*sys
= vd
->sys
;
1395 Direct3D11DestroyResources(vd
);
1396 if (sys
->d3dcontext
)
1398 ID3D11DeviceContext_Flush(sys
->d3dcontext
);
1399 ID3D11DeviceContext_Release(sys
->d3dcontext
);
1400 sys
->d3dcontext
= NULL
;
1404 ID3D11Device_Release(sys
->d3ddevice
);
1405 sys
->d3ddevice
= NULL
;
1407 if (sys
->dxgiswapChain
)
1409 IDXGISwapChain_Release(sys
->dxgiswapChain
);
1410 sys
->dxgiswapChain
= NULL
;
1413 msg_Dbg(vd
, "Direct3D11 device adapter closed");
1416 static void UpdatePicQuadPosition(vout_display_t
*vd
)
1418 vout_display_sys_t
*sys
= vd
->sys
;
1419 int i_width
= RECTWidth(sys
->rect_dest_clipped
);
1420 int i_height
= RECTHeight(sys
->rect_dest_clipped
);
1422 int i_top
= sys
->rect_src_clipped
.top
* i_height
;
1423 i_top
/= vd
->source
.i_visible_height
;
1424 i_top
-= sys
->rect_dest_clipped
.top
;
1425 int i_left
= sys
->rect_src_clipped
.left
* i_width
;
1426 i_left
/= vd
->source
.i_visible_width
;
1427 i_left
-= sys
->rect_dest_clipped
.left
;
1429 sys
->picQuad
.cropViewport
.Width
= (FLOAT
) vd
->source
.i_width
* i_width
/ vd
->source
.i_visible_width
;
1430 sys
->picQuad
.cropViewport
.Height
= (FLOAT
) vd
->source
.i_height
* i_height
/ vd
->source
.i_visible_height
;
1431 sys
->picQuad
.cropViewport
.TopLeftX
= -i_left
;
1432 sys
->picQuad
.cropViewport
.TopLeftY
= -i_top
;
1434 sys
->picQuad
.cropViewport
.MinDepth
= 0.0f
;
1435 sys
->picQuad
.cropViewport
.MaxDepth
= 1.0f
;
1437 SetQuadVSProjection(vd
, &sys
->picQuad
, &vd
->cfg
->viewpoint
);
1440 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
);
1444 /* TODO : handle errors better
1445 TODO : seperate out into smaller functions like createshaders */
1446 static int Direct3D11CreateResources(vout_display_t
*vd
, video_format_t
*fmt
)
1448 vout_display_sys_t
*sys
= vd
->sys
;
1451 #if defined(HAVE_ID3D11VIDEODECODER)
1452 sys
->context_lock
= CreateMutexEx( NULL
, NULL
, 0, SYNCHRONIZE
);
1453 ID3D11Device_SetPrivateData( sys
->d3ddevice
, &GUID_CONTEXT_MUTEX
, sizeof( sys
->context_lock
), &sys
->context_lock
);
1456 hr
= UpdateBackBuffer(vd
);
1458 msg_Err(vd
, "Could not update the backbuffer. (hr=0x%lX)", hr
);
1459 return VLC_EGENERIC
;
1462 ID3D11BlendState
*pSpuBlendState
;
1463 D3D11_BLEND_DESC spuBlendDesc
= { 0 };
1464 spuBlendDesc
.RenderTarget
[0].BlendEnable
= TRUE
;
1465 spuBlendDesc
.RenderTarget
[0].SrcBlend
= D3D11_BLEND_SRC_ALPHA
;
1466 spuBlendDesc
.RenderTarget
[0].DestBlend
= D3D11_BLEND_INV_SRC_ALPHA
;
1467 spuBlendDesc
.RenderTarget
[0].BlendOp
= D3D11_BLEND_OP_ADD
;
1469 spuBlendDesc
.RenderTarget
[0].SrcBlendAlpha
= D3D11_BLEND_ONE
;
1470 spuBlendDesc
.RenderTarget
[0].DestBlendAlpha
= D3D11_BLEND_ZERO
;
1471 spuBlendDesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
1473 spuBlendDesc
.RenderTarget
[0].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
1475 spuBlendDesc
.RenderTarget
[1].BlendEnable
= TRUE
;
1476 spuBlendDesc
.RenderTarget
[1].SrcBlend
= D3D11_BLEND_ONE
;
1477 spuBlendDesc
.RenderTarget
[1].DestBlend
= D3D11_BLEND_ZERO
;
1478 spuBlendDesc
.RenderTarget
[1].BlendOp
= D3D11_BLEND_OP_ADD
;
1480 spuBlendDesc
.RenderTarget
[1].SrcBlendAlpha
= D3D11_BLEND_ONE
;
1481 spuBlendDesc
.RenderTarget
[1].DestBlendAlpha
= D3D11_BLEND_ZERO
;
1482 spuBlendDesc
.RenderTarget
[1].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
1484 spuBlendDesc
.RenderTarget
[1].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
1485 hr
= ID3D11Device_CreateBlendState(sys
->d3ddevice
, &spuBlendDesc
, &pSpuBlendState
);
1487 msg_Err(vd
, "Could not create SPU blend state. (hr=0x%lX)", hr
);
1488 return VLC_EGENERIC
;
1490 ID3D11DeviceContext_OMSetBlendState(sys
->d3dcontext
, pSpuBlendState
, NULL
, 0xFFFFFFFF);
1491 ID3D11BlendState_Release(pSpuBlendState
);
1493 /* disable depth testing as we're only doing 2D
1494 * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
1495 * see http://rastertek.com/dx11tut11.html
1497 D3D11_DEPTH_STENCIL_DESC stencilDesc
;
1498 ZeroMemory(&stencilDesc
, sizeof(stencilDesc
));
1500 ID3D11DepthStencilState
*pDepthStencilState
;
1501 hr
= ID3D11Device_CreateDepthStencilState(sys
->d3ddevice
, &stencilDesc
, &pDepthStencilState
);
1502 if (SUCCEEDED(hr
)) {
1503 ID3D11DeviceContext_OMSetDepthStencilState(sys
->d3dcontext
, pDepthStencilState
, 0);
1504 ID3D11DepthStencilState_Release(pDepthStencilState
);
1507 ID3DBlob
* pVSBlob
= NULL
;
1508 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1509 hr
= D3DCompile(globVertexShaderFlat
, strlen(globVertexShaderFlat
),
1510 NULL
, NULL
, NULL
, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob
, NULL
);
1513 msg_Err(vd
, "The flat Vertex Shader is invalid. (hr=0x%lX)", hr
);
1514 return VLC_EGENERIC
;
1517 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1518 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &sys
->flatVSShader
);
1521 ID3D11Device_Release(pVSBlob
);
1522 msg_Err(vd
, "Failed to create the flat vertex shader. (hr=0x%lX)", hr
);
1523 return VLC_EGENERIC
;
1526 D3D11_INPUT_ELEMENT_DESC layout
[] = {
1527 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D11_APPEND_ALIGNED_ELEMENT
, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1528 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT
, 0, D3D11_APPEND_ALIGNED_ELEMENT
, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1531 ID3D11InputLayout
* pVertexLayout
= NULL
;
1532 hr
= ID3D11Device_CreateInputLayout(sys
->d3ddevice
, layout
, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1533 ID3D10Blob_GetBufferSize(pVSBlob
), &pVertexLayout
);
1535 ID3D10Blob_Release(pVSBlob
);
1538 msg_Err(vd
, "Failed to create the vertex input layout. (hr=0x%lX)", hr
);
1539 return VLC_EGENERIC
;
1541 ID3D11DeviceContext_IASetInputLayout(sys
->d3dcontext
, pVertexLayout
);
1542 ID3D11InputLayout_Release(pVertexLayout
);
1544 hr
= D3DCompile(globVertexShaderProjection
, strlen(globVertexShaderProjection
),
1545 NULL
, NULL
, NULL
, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob
, NULL
);
1548 msg_Err(vd
, "The projection Vertex Shader is invalid. (hr=0x%lX)", hr
);
1549 return VLC_EGENERIC
;
1552 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1553 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &sys
->projectionVSShader
);
1556 ID3D11Device_Release(pVSBlob
);
1557 msg_Err(vd
, "Failed to create the projection vertex shader. (hr=0x%lX)", hr
);
1558 return VLC_EGENERIC
;
1560 ID3D10Blob_Release(pVSBlob
);
1562 ID3D11DeviceContext_IASetPrimitiveTopology(sys
->d3dcontext
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
1564 ID3DBlob
* pPSBlob
= NULL
;
1566 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1567 hr
= D3DCompile(sys
->d3dPxShader
, strlen(sys
->d3dPxShader
),
1568 NULL
, NULL
, NULL
, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob
, NULL
);
1572 msg_Err(vd
, "The Pixel Shader is invalid. (hr=0x%lX)", hr
);
1573 return VLC_EGENERIC
;
1576 ID3D11PixelShader
*pPicQuadShader
;
1577 hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
1578 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, &pPicQuadShader
);
1580 ID3D10Blob_Release(pPSBlob
);
1583 msg_Err(vd
, "Failed to create the pixel shader. (hr=0x%lX)", hr
);
1584 return VLC_EGENERIC
;
1587 if (sys
->psz_rgbaPxShader
!= NULL
)
1589 hr
= D3DCompile(sys
->psz_rgbaPxShader
, strlen(sys
->psz_rgbaPxShader
),
1590 NULL
, NULL
, NULL
, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob
, NULL
);
1592 ID3D11PixelShader_Release(pPicQuadShader
);
1593 msg_Err(vd
, "The RGBA Pixel Shader is invalid. (hr=0x%lX)", hr
);
1594 return VLC_EGENERIC
;
1597 hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
1598 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, &sys
->pSPUPixelShader
);
1600 ID3D10Blob_Release(pPSBlob
);
1603 ID3D11PixelShader_Release(pPicQuadShader
);
1604 msg_Err(vd
, "Failed to create the SPU pixel shader. (hr=0x%lX)", hr
);
1605 return VLC_EGENERIC
;
1609 if (AllocQuad( vd
, fmt
, &sys
->picQuad
, &sys
->picQuadConfig
, pPicQuadShader
,
1610 true, vd
->fmt
.projection_mode
) != VLC_SUCCESS
) {
1611 ID3D11PixelShader_Release(pPicQuadShader
);
1612 msg_Err(vd
, "Could not Create the main quad picture. (hr=0x%lX)", hr
);
1613 return VLC_EGENERIC
;
1615 ID3D11PixelShader_Release(pPicQuadShader
);
1617 video_format_t core_source
;
1618 CropStagingFormat( vd
, &core_source
);
1619 UpdatePicQuadPosition(vd
);
1620 UncropStagingFormat( vd
, &core_source
);
1622 D3D11_SAMPLER_DESC sampDesc
;
1623 memset(&sampDesc
, 0, sizeof(sampDesc
));
1624 sampDesc
.Filter
= D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
;
1625 sampDesc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1626 sampDesc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1627 sampDesc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1628 sampDesc
.ComparisonFunc
= D3D11_COMPARISON_ALWAYS
;
1629 sampDesc
.MinLOD
= 0;
1630 sampDesc
.MaxLOD
= D3D11_FLOAT32_MAX
;
1632 ID3D11SamplerState
*d3dsampState
;
1633 hr
= ID3D11Device_CreateSamplerState(sys
->d3ddevice
, &sampDesc
, &d3dsampState
);
1636 msg_Err(vd
, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr
);
1637 return VLC_EGENERIC
;
1639 ID3D11DeviceContext_PSSetSamplers(sys
->d3dcontext
, 0, 1, &d3dsampState
);
1640 ID3D11SamplerState_Release(d3dsampState
);
1642 if (Direct3D11CreatePool(vd
, fmt
))
1644 msg_Err(vd
, "Direct3D picture pool initialization failed");
1645 return VLC_EGENERIC
;
1648 msg_Dbg(vd
, "Direct3D11 resources created");
1652 static int Direct3D11CreatePool(vout_display_t
*vd
, video_format_t
*fmt
)
1654 vout_display_sys_t
*sys
= vd
->sys
;
1656 if ( is_d3d11_opaque(fmt
->i_chroma
) )
1657 /* a D3D11VA pool will be created when needed */
1660 picture_sys_pool_t
*picsys
= calloc(1, sizeof(*picsys
));
1661 if (unlikely(picsys
== NULL
)) {
1665 if ( sys
->stagingQuad
.pTexture
!= NULL
)
1666 picsys
->texture
= sys
->stagingQuad
.pTexture
;
1668 picsys
->texture
= sys
->picQuad
.pTexture
;
1671 picture_resource_t resource
= {
1672 .p_sys
= (picture_sys_t
*) picsys
,
1673 .pf_destroy
= DestroyDisplayPicture
,
1676 picture_t
*picture
= picture_NewFromResource(fmt
, &resource
);
1681 ID3D11Texture2D_AddRef(picsys
->texture
);
1683 picture_pool_configuration_t pool_cfg
;
1684 memset(&pool_cfg
, 0, sizeof(pool_cfg
));
1685 pool_cfg
.picture_count
= 1;
1686 pool_cfg
.picture
= &picture
;
1687 pool_cfg
.lock
= Direct3D11MapTexture
;
1688 //pool_cfg.unlock = Direct3D11UnmapTexture;
1690 sys
->pool
= picture_pool_NewExtended(&pool_cfg
);
1692 picture_Release(picture
);
1699 static void Direct3D11DestroyPool(vout_display_t
*vd
)
1701 vout_display_sys_t
*sys
= vd
->sys
;
1704 picture_pool_Release(sys
->pool
);
1708 static void SetupQuadFlat(d3d_vertex_t
*dst_data
, WORD
*triangle_pos
)
1713 float bottom
= -1.0f
;
1716 dst_data
[0].position
.x
= left
;
1717 dst_data
[0].position
.y
= bottom
;
1718 dst_data
[0].position
.z
= 0.0f
;
1719 dst_data
[0].texture
.x
= 0.0f
;
1720 dst_data
[0].texture
.y
= 1.0f
;
1723 dst_data
[1].position
.x
= right
;
1724 dst_data
[1].position
.y
= bottom
;
1725 dst_data
[1].position
.z
= 0.0f
;
1726 dst_data
[1].texture
.x
= 1.0f
;
1727 dst_data
[1].texture
.y
= 1.0f
;
1730 dst_data
[2].position
.x
= right
;
1731 dst_data
[2].position
.y
= top
;
1732 dst_data
[2].position
.z
= 0.0f
;
1733 dst_data
[2].texture
.x
= 1.0f
;
1734 dst_data
[2].texture
.y
= 0.0f
;
1737 dst_data
[3].position
.x
= left
;
1738 dst_data
[3].position
.y
= top
;
1739 dst_data
[3].position
.z
= 0.0f
;
1740 dst_data
[3].texture
.x
= 0.0f
;
1741 dst_data
[3].texture
.y
= 0.0f
;
1743 triangle_pos
[0] = 3;
1744 triangle_pos
[1] = 1;
1745 triangle_pos
[2] = 0;
1747 triangle_pos
[3] = 2;
1748 triangle_pos
[4] = 1;
1749 triangle_pos
[5] = 3;
1752 #define SPHERE_SLICES 128
1753 #define nbLatBands SPHERE_SLICES
1754 #define nbLonBands SPHERE_SLICES
1756 static void SetupQuadSphere(d3d_vertex_t
*dst_data
, WORD
*triangle_pos
)
1758 for (unsigned lat
= 0; lat
<= nbLatBands
; lat
++) {
1759 float theta
= lat
* (float) M_PI
/ nbLatBands
;
1760 float sinTheta
, cosTheta
;
1762 sincosf(theta
, &sinTheta
, &cosTheta
);
1764 for (unsigned lon
= 0; lon
<= nbLonBands
; lon
++) {
1765 float phi
= lon
* 2 * (float) M_PI
/ nbLonBands
;
1766 float sinPhi
, cosPhi
;
1768 sincosf(phi
, &sinPhi
, &cosPhi
);
1770 float x
= cosPhi
* sinTheta
;
1772 float z
= sinPhi
* sinTheta
;
1774 unsigned off1
= lat
* (nbLonBands
+ 1) + lon
;
1775 dst_data
[off1
].position
.x
= SPHERE_RADIUS
* x
;
1776 dst_data
[off1
].position
.y
= SPHERE_RADIUS
* y
;
1777 dst_data
[off1
].position
.z
= SPHERE_RADIUS
* z
;
1779 dst_data
[off1
].texture
.x
= lon
/ (float) nbLonBands
; // 0(left) to 1(right)
1780 dst_data
[off1
].texture
.y
= lat
/ (float) nbLatBands
; // 0(top) to 1 (bottom)
1784 for (unsigned lat
= 0; lat
< nbLatBands
; lat
++) {
1785 for (unsigned lon
= 0; lon
< nbLonBands
; lon
++) {
1786 unsigned first
= (lat
* (nbLonBands
+ 1)) + lon
;
1787 unsigned second
= first
+ nbLonBands
+ 1;
1789 unsigned off
= (lat
* nbLatBands
+ lon
) * 3 * 2;
1791 triangle_pos
[off
] = first
;
1792 triangle_pos
[off
+ 1] = first
+ 1;
1793 triangle_pos
[off
+ 2] = second
;
1795 triangle_pos
[off
+ 3] = second
;
1796 triangle_pos
[off
+ 4] = first
+ 1;
1797 triangle_pos
[off
+ 5] = second
+ 1;
1802 static bool AllocQuadVertices(vout_display_t
*vd
, d3d_quad_t
*quad
, video_projection_mode_t projection
)
1805 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1806 vout_display_sys_t
*sys
= vd
->sys
;
1808 if (projection
== PROJECTION_MODE_RECTANGULAR
)
1810 quad
->vertexCount
= 4;
1811 quad
->indexCount
= 2 * 3;
1813 else if (projection
== PROJECTION_MODE_EQUIRECTANGULAR
)
1815 quad
->vertexCount
= (SPHERE_SLICES
+1) * (SPHERE_SLICES
+1);
1816 quad
->indexCount
= nbLatBands
* nbLonBands
* 2 * 3;
1821 D3D11_BUFFER_DESC bd
;
1822 memset(&bd
, 0, sizeof(bd
));
1823 bd
.Usage
= D3D11_USAGE_DYNAMIC
;
1824 bd
.ByteWidth
= sizeof(d3d_vertex_t
) * quad
->vertexCount
;
1825 bd
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
1826 bd
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
1828 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &bd
, NULL
, &quad
->pVertexBuffer
);
1830 msg_Err(vd
, "Failed to create vertex buffer. (hr=%lX)", hr
);
1834 /* create the index of the vertices */
1835 D3D11_BUFFER_DESC quadDesc
= {
1836 .Usage
= D3D11_USAGE_DYNAMIC
,
1837 .ByteWidth
= sizeof(WORD
) * quad
->indexCount
,
1838 .BindFlags
= D3D11_BIND_INDEX_BUFFER
,
1839 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
1842 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &quadDesc
, NULL
, &quad
->pIndexBuffer
);
1844 msg_Err(vd
, "Could not create the quad indices. (hr=0x%lX)", hr
);
1848 /* create the vertices */
1849 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
1851 msg_Err(vd
, "Failed to lock the vertex buffer (hr=0x%lX)", hr
);
1854 d3d_vertex_t
*dst_data
= mappedResource
.pData
;
1856 /* create the vertex indices */
1857 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
1859 msg_Err(vd
, "Failed to lock the index buffer (hr=0x%lX)", hr
);
1860 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
1863 WORD
*triangle_pos
= mappedResource
.pData
;
1865 if ( projection
== PROJECTION_MODE_RECTANGULAR
)
1866 SetupQuadFlat(dst_data
, triangle_pos
);
1868 SetupQuadSphere(dst_data
, triangle_pos
);
1870 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0);
1871 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
1876 static int AllocQuad(vout_display_t
*vd
, const video_format_t
*fmt
, d3d_quad_t
*quad
,
1877 d3d_quad_cfg_t
*cfg
, ID3D11PixelShader
*d3dpixelShader
, bool b_visible
,
1878 video_projection_mode_t projection
)
1880 vout_display_sys_t
*sys
= vd
->sys
;
1881 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1884 /* pixel shader constant buffer */
1885 PS_CONSTANT_BUFFER defaultConstants
= {
1888 static_assert((sizeof(PS_CONSTANT_BUFFER
)%16)==0,"Constant buffers require 16-byte alignment");
1889 D3D11_BUFFER_DESC constantDesc
= {
1890 .Usage
= D3D11_USAGE_DYNAMIC
,
1891 .ByteWidth
= sizeof(PS_CONSTANT_BUFFER
),
1892 .BindFlags
= D3D11_BIND_CONSTANT_BUFFER
,
1893 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
1895 D3D11_SUBRESOURCE_DATA constantInit
= { .pSysMem
= &defaultConstants
};
1896 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
[0]);
1898 msg_Err(vd
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
1902 static const FLOAT WHITE_POINT_D65
[4] = { -0.0625f
, -0.5f
, -0.5f
, 1.f
};
1904 static const FLOAT COLORSPACE_BT601_TO_FULL
[4*4] = {
1905 1.164383561643836f
, 0.f
, 1.596026785714286f
, 0.f
,
1906 1.164383561643836f
, -0.391762290094914f
, -0.812967647237771f
, 0.f
,
1907 1.164383561643836f
, 2.017232142857142f
, 0.f
, 0.f
,
1910 static const FLOAT COLORSPACE_BT709_TO_FULL
[4*4] = {
1911 1.164383561643836f
, 0.f
, 1.792741071428571f
, 0.f
,
1912 1.164383561643836f
, -0.213248614273730f
, -0.532909328559444f
, 0.f
,
1913 1.164383561643836f
, 2.112401785714286f
, 0.f
, 0.f
,
1916 /* RGB-709 to RGB-2020 based on https://www.researchgate.net/publication/258434326_Beyond_BT709 */
1917 static const FLOAT COLORSPACE_BT2020_TO_FULL
[4*4] = {
1918 1.163746465f
, -0.028815145f
, 2.823537589f
, 0.f
,
1919 1.164383561f
, -0.258509894f
, 0.379693635f
, 0.f
,
1920 1.164383561f
, 2.385315708f
, 0.021554502f
, 0.f
,
1924 PS_COLOR_TRANSFORM colorspace
;
1925 const FLOAT
*ppColorspace
;
1926 switch (fmt
->space
){
1927 case COLOR_SPACE_BT709
:
1928 ppColorspace
= COLORSPACE_BT709_TO_FULL
;
1930 case COLOR_SPACE_BT2020
:
1931 ppColorspace
= COLORSPACE_BT2020_TO_FULL
;
1933 case COLOR_SPACE_BT601
:
1934 ppColorspace
= COLORSPACE_BT601_TO_FULL
;
1936 case COLOR_SPACE_UNDEF
:
1937 if( fmt
->i_height
> 576 )
1938 ppColorspace
= COLORSPACE_BT709_TO_FULL
;
1940 ppColorspace
= COLORSPACE_BT601_TO_FULL
;
1943 memcpy(colorspace
.Colorspace
, ppColorspace
, sizeof(colorspace
.Colorspace
));
1944 memcpy(colorspace
.WhitePoint
, WHITE_POINT_D65
, sizeof(colorspace
.WhitePoint
));
1945 constantInit
.pSysMem
= &colorspace
;
1947 static_assert((sizeof(PS_COLOR_TRANSFORM
)%16)==0,"Constant buffers require 16-byte alignment");
1948 constantDesc
.ByteWidth
= sizeof(PS_COLOR_TRANSFORM
);
1949 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
[1]);
1951 msg_Err(vd
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
1954 quad
->PSConstantsCount
= 2;
1956 /* vertex shader constant buffer */
1957 if ( projection
== PROJECTION_MODE_EQUIRECTANGULAR
)
1959 constantDesc
.ByteWidth
= sizeof(VS_PROJECTION_CONST
);
1960 static_assert((sizeof(VS_PROJECTION_CONST
)%16)==0,"Constant buffers require 16-byte alignment");
1961 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, NULL
, &quad
->pVertexShaderConstants
);
1963 msg_Err(vd
, "Could not create the vertex shader constant buffer. (hr=0x%lX)", hr
);
1967 SetQuadVSProjection( vd
, quad
, &vd
->cfg
->viewpoint
);
1970 D3D11_TEXTURE2D_DESC texDesc
;
1971 memset(&texDesc
, 0, sizeof(texDesc
));
1972 texDesc
.Width
= b_visible
? fmt
->i_visible_width
: fmt
->i_width
;
1973 texDesc
.Height
= b_visible
? fmt
->i_visible_height
: fmt
->i_height
;
1974 texDesc
.MipLevels
= texDesc
.ArraySize
= 1;
1975 texDesc
.Format
= cfg
->textureFormat
;
1976 texDesc
.SampleDesc
.Count
= 1;
1977 texDesc
.Usage
= D3D11_USAGE_DYNAMIC
;
1978 texDesc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
1979 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
1980 texDesc
.MiscFlags
= 0;
1982 /* remove half pixels, we don't want green lines */
1983 const vlc_chroma_description_t
*p_chroma_desc
= vlc_fourcc_GetChromaDescription( fmt
->i_chroma
);
1984 for (unsigned plane
= 0; plane
< p_chroma_desc
->plane_count
; ++plane
)
1987 i_extra
= (texDesc
.Width
* p_chroma_desc
->p
[plane
].w
.num
) % p_chroma_desc
->p
[plane
].w
.den
;
1989 texDesc
.Width
-= p_chroma_desc
->p
[plane
].w
.den
/ p_chroma_desc
->p
[plane
].w
.num
- i_extra
;
1990 i_extra
= (texDesc
.Height
* p_chroma_desc
->p
[plane
].h
.num
) % p_chroma_desc
->p
[plane
].h
.den
;
1992 texDesc
.Height
-= p_chroma_desc
->p
[plane
].h
.den
/ p_chroma_desc
->p
[plane
].h
.num
- i_extra
;
1994 if (texDesc
.Format
== DXGI_FORMAT_NV12
|| texDesc
.Format
== DXGI_FORMAT_P010
)
1996 texDesc
.Width
&= ~1;
1997 texDesc
.Height
&= ~1;
2000 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &texDesc
, NULL
, &quad
->pTexture
);
2002 msg_Err(vd
, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr
);
2006 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pTexture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2008 msg_Err(vd
, "The texture cannot be mapped. (hr=0x%lX)", hr
);
2011 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pTexture
, 0);
2012 if (mappedResource
.RowPitch
< p_chroma_desc
->pixel_size
* texDesc
.Width
) {
2013 msg_Err( vd
, "The texture row pitch is too small (%d instead of %d)", mappedResource
.RowPitch
,
2014 p_chroma_desc
->pixel_size
* texDesc
.Width
);
2018 /* map texture planes to resource views */
2019 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc
;
2020 memset(&resviewDesc
, 0, sizeof(resviewDesc
));
2021 resviewDesc
.Format
= cfg
->resourceFormatYRGB
;
2022 resviewDesc
.ViewDimension
= D3D11_SRV_DIMENSION_TEXTURE2D
;
2023 resviewDesc
.Texture2D
.MipLevels
= texDesc
.MipLevels
;
2025 hr
= ID3D11Device_CreateShaderResourceView(sys
->d3ddevice
, (ID3D11Resource
*)quad
->pTexture
, &resviewDesc
, &quad
->d3dresViewY
);
2027 msg_Err(vd
, "Could not Create the Y/RGB D3d11 Texture ResourceView. (hr=0x%lX)", hr
);
2031 if( cfg
->resourceFormatUV
)
2033 resviewDesc
.Format
= cfg
->resourceFormatUV
;
2034 hr
= ID3D11Device_CreateShaderResourceView(sys
->d3ddevice
, (ID3D11Resource
*)quad
->pTexture
, &resviewDesc
, &quad
->d3dresViewUV
);
2036 msg_Err(vd
, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr
);
2041 if ( d3dpixelShader
!= NULL
)
2043 if (!AllocQuadVertices(vd
, quad
, projection
))
2046 if (projection
== PROJECTION_MODE_RECTANGULAR
)
2047 quad
->d3dvertexShader
= sys
->flatVSShader
;
2049 quad
->d3dvertexShader
= sys
->projectionVSShader
;
2051 quad
->d3dpixelShader
= d3dpixelShader
;
2052 ID3D11PixelShader_AddRef(quad
->d3dpixelShader
);
2059 return VLC_EGENERIC
;
2062 static void ReleaseQuad(d3d_quad_t
*quad
)
2064 if (quad
->pPixelShaderConstants
[0])
2066 ID3D11Buffer_Release(quad
->pPixelShaderConstants
[0]);
2067 quad
->pPixelShaderConstants
[0] = NULL
;
2069 if (quad
->pPixelShaderConstants
[1])
2071 ID3D11Buffer_Release(quad
->pPixelShaderConstants
[1]);
2072 quad
->pPixelShaderConstants
[1] = NULL
;
2074 if (quad
->pVertexBuffer
)
2076 ID3D11Buffer_Release(quad
->pVertexBuffer
);
2077 quad
->pVertexBuffer
= NULL
;
2079 quad
->d3dvertexShader
= NULL
;
2080 if (quad
->pIndexBuffer
)
2082 ID3D11Buffer_Release(quad
->pIndexBuffer
);
2083 quad
->pIndexBuffer
= NULL
;
2085 if (quad
->pVertexShaderConstants
)
2087 ID3D11Buffer_Release(quad
->pVertexShaderConstants
);
2088 quad
->pVertexShaderConstants
= NULL
;
2092 ID3D11Texture2D_Release(quad
->pTexture
);
2093 quad
->pTexture
= NULL
;
2095 if (quad
->d3dresViewY
)
2097 ID3D11ShaderResourceView_Release(quad
->d3dresViewY
);
2098 quad
->d3dresViewY
= NULL
;
2100 if (quad
->d3dresViewUV
)
2102 ID3D11ShaderResourceView_Release(quad
->d3dresViewUV
);
2103 quad
->d3dresViewUV
= NULL
;
2105 if (quad
->d3dpixelShader
)
2107 ID3D11VertexShader_Release(quad
->d3dpixelShader
);
2108 quad
->d3dpixelShader
= NULL
;
2112 static void Direct3D11DestroyResources(vout_display_t
*vd
)
2114 vout_display_sys_t
*sys
= vd
->sys
;
2116 Direct3D11DestroyPool(vd
);
2118 if ( sys
->stagingQuad
.pTexture
)
2119 ReleaseQuad(&sys
->stagingQuad
);
2120 ReleaseQuad(&sys
->picQuad
);
2121 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
2122 sys
->d3dregion_count
= 0;
2124 if (sys
->flatVSShader
)
2126 ID3D11VertexShader_Release(sys
->flatVSShader
);
2127 sys
->flatVSShader
= NULL
;
2129 if (sys
->projectionVSShader
)
2131 ID3D11VertexShader_Release(sys
->projectionVSShader
);
2132 sys
->projectionVSShader
= NULL
;
2134 if (sys
->d3drenderTargetView
)
2136 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
2137 sys
->d3drenderTargetView
= NULL
;
2139 if (sys
->d3ddepthStencilView
)
2141 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
2142 sys
->d3ddepthStencilView
= NULL
;
2144 if (sys
->pSPUPixelShader
)
2146 ID3D11VertexShader_Release(sys
->pSPUPixelShader
);
2147 sys
->pSPUPixelShader
= NULL
;
2149 #if defined(HAVE_ID3D11VIDEODECODER)
2150 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
2152 CloseHandle( sys
->context_lock
);
2153 sys
->context_lock
= INVALID_HANDLE_VALUE
;
2157 msg_Dbg(vd
, "Direct3D11 resources destroyed");
2160 static int Direct3D11MapTexture(picture_t
*picture
)
2162 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*) picture
->p_sys
;
2163 vout_display_t
*vd
= p_sys
->vd
;
2164 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2166 hr
= ID3D11DeviceContext_Map(vd
->sys
->d3dcontext
, (ID3D11Resource
*)p_sys
->texture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2169 msg_Dbg( vd
, "failed to map the texture (hr=0x%lX)", hr
);
2170 return VLC_EGENERIC
;
2172 return CommonUpdatePicture(picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
2175 static int Direct3D11UnmapTexture(picture_t
*picture
)
2177 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*)picture
->p_sys
;
2178 vout_display_t
*vd
= p_sys
->vd
;
2179 ID3D11DeviceContext_Unmap(vd
->sys
->d3dcontext
, (ID3D11Resource
*)p_sys
->texture
, 0);
2183 static void Direct3D11DeleteRegions(int count
, picture_t
**region
)
2185 for (int i
= 0; i
< count
; ++i
) {
2187 picture_Release(region
[i
]);
2193 static void DestroyPictureQuad(picture_t
*p_picture
)
2195 ReleaseQuad( (d3d_quad_t
*) p_picture
->p_sys
);
2199 static void UpdateQuadOpacity(vout_display_t
*vd
, const d3d_quad_t
*quad
, float opacity
)
2201 vout_display_sys_t
*sys
= vd
->sys
;
2202 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2204 HRESULT hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
[0], 0, D3D11_MAP_WRITE_NO_OVERWRITE
, 0, &mappedResource
);
2205 if (SUCCEEDED(hr
)) {
2206 FLOAT
*dst_data
= mappedResource
.pData
;
2207 *dst_data
= opacity
;
2208 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
[0], 0);
2211 msg_Err(vd
, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr
);
2215 static int Direct3D11MapSubpicture(vout_display_t
*vd
, int *subpicture_region_count
,
2216 picture_t
***region
, subpicture_t
*subpicture
)
2218 vout_display_sys_t
*sys
= vd
->sys
;
2219 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2220 D3D11_TEXTURE2D_DESC texDesc
;
2225 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
)
2228 *region
= calloc(count
, sizeof(picture_t
*));
2229 if (unlikely(*region
==NULL
))
2231 *subpicture_region_count
= count
;
2234 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
, i
++) {
2235 if (!r
->fmt
.i_width
|| !r
->fmt
.i_height
)
2236 continue; // won't render anything, keep the cache for later
2238 for (int j
= 0; j
< sys
->d3dregion_count
; j
++) {
2239 picture_t
*cache
= sys
->d3dregions
[j
];
2240 if (cache
!= NULL
&& ((d3d_quad_t
*) cache
->p_sys
)->pTexture
) {
2241 ID3D11Texture2D_GetDesc( ((d3d_quad_t
*) cache
->p_sys
)->pTexture
, &texDesc
);
2242 if (texDesc
.Format
== sys
->d3dregion_format
&&
2243 texDesc
.Width
== r
->fmt
.i_visible_width
&&
2244 texDesc
.Height
== r
->fmt
.i_visible_height
) {
2245 (*region
)[i
] = cache
;
2246 memset(&sys
->d3dregions
[j
], 0, sizeof(cache
)); // do not reuse this cached value
2252 picture_t
*quad_picture
= (*region
)[i
];
2253 if (quad_picture
== NULL
) {
2254 d3d_quad_t
*d3dquad
= calloc(1, sizeof(*d3dquad
));
2255 if (unlikely(d3dquad
==NULL
)) {
2258 d3d_quad_cfg_t rgbaCfg
= {
2259 .textureFormat
= sys
->d3dregion_format
,
2260 .resourceFormatYRGB
= sys
->d3dregion_format
,
2262 err
= AllocQuad( vd
, &r
->fmt
, d3dquad
, &rgbaCfg
, sys
->pSPUPixelShader
,
2263 false, PROJECTION_MODE_RECTANGULAR
);
2264 if (err
!= VLC_SUCCESS
) {
2265 msg_Err(vd
, "Failed to create %dx%d texture for OSD",
2266 r
->fmt
.i_visible_width
, r
->fmt
.i_visible_height
);
2270 picture_resource_t picres
= {
2271 .p_sys
= (picture_sys_t
*) d3dquad
,
2272 .pf_destroy
= DestroyPictureQuad
,
2274 (*region
)[i
] = picture_NewFromResource(&r
->fmt
, &picres
);
2275 if ((*region
)[i
] == NULL
) {
2276 msg_Err(vd
, "Failed to create %dx%d picture for OSD",
2277 r
->fmt
.i_width
, r
->fmt
.i_height
);
2278 ReleaseQuad(d3dquad
);
2281 quad_picture
= (*region
)[i
];
2284 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)((d3d_quad_t
*) quad_picture
->p_sys
)->pTexture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2285 if( SUCCEEDED(hr
) ) {
2286 err
= CommonUpdatePicture(quad_picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
2287 if (err
!= VLC_SUCCESS
) {
2288 msg_Err(vd
, "Failed to set the buffer on the SPU picture" );
2289 picture_Release(quad_picture
);
2293 picture_CopyPixels(quad_picture
, r
->p_picture
);
2295 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)((d3d_quad_t
*) quad_picture
->p_sys
)->pTexture
, 0);
2297 msg_Err(vd
, "Failed to map the SPU texture (hr=0x%lX)", hr
);
2298 picture_Release(quad_picture
);
2302 d3d_quad_t
*quad
= (d3d_quad_t
*) quad_picture
->p_sys
;
2304 quad
->cropViewport
.Width
= (FLOAT
) r
->fmt
.i_visible_width
* RECTWidth(sys
->rect_dest
) / subpicture
->i_original_picture_width
;
2305 quad
->cropViewport
.Height
= (FLOAT
) r
->fmt
.i_visible_height
* RECTHeight(sys
->rect_dest
) / subpicture
->i_original_picture_height
;
2306 quad
->cropViewport
.MinDepth
= 0.0f
;
2307 quad
->cropViewport
.MaxDepth
= 1.0f
;
2308 quad
->cropViewport
.TopLeftX
= sys
->rect_dest
.left
+ (FLOAT
) r
->i_x
* RECTWidth(sys
->rect_dest
) / subpicture
->i_original_picture_width
;
2309 quad
->cropViewport
.TopLeftY
= sys
->rect_dest
.top
+ (FLOAT
) r
->i_y
* RECTHeight(sys
->rect_dest
) / subpicture
->i_original_picture_height
;
2311 UpdateQuadOpacity(vd
, quad
, r
->i_alpha
/ 255.0f
);