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>
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"
53 # define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
55 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
57 # define D3DCompile(args...) sys->OurD3DCompile(args)
60 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH
, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
61 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT
, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
62 DEFINE_GUID(GUID_CONTEXT_MUTEX
, 0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
64 static int Open(vlc_object_t
*);
65 static void Close(vlc_object_t
*);
67 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
68 #define HW_BLENDING_TEXT N_("Use hardware blending support")
69 #define HW_BLENDING_LONGTEXT N_(\
70 "Try to use hardware acceleration for subtitle/OSD blending.")
73 set_shortname("Direct3D11")
74 set_description(N_("Direct3D11 video output"))
76 set_category(CAT_VIDEO
)
77 set_subcategory(SUBCAT_VIDEO_VOUT
)
79 add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT
, HW_BLENDING_LONGTEXT
, true)
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
{
125 } PS_CONSTANT_BUFFER
;
132 FLOAT Projection
[16];
133 } VS_PROJECTION_CONST
;
135 #define SPHERE_RADIUS 1.f
137 #define RECTWidth(r) (int)((r).right - (r).left)
138 #define RECTHeight(r) (int)((r).bottom - (r).top)
140 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned count
);
142 static void Prepare(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
143 static void Display(vout_display_t
*, picture_t
*, subpicture_t
*subpicture
);
145 static HINSTANCE
Direct3D11LoadShaderLibrary(void);
146 static void Direct3D11Destroy(vout_display_t
*);
148 static int Direct3D11Open (vout_display_t
*, video_format_t
*);
149 static void Direct3D11Close(vout_display_t
*);
151 static int Direct3D11CreateResources (vout_display_t
*, video_format_t
*);
152 static void Direct3D11DestroyResources(vout_display_t
*);
154 static int Direct3D11CreatePool (vout_display_t
*, video_format_t
*);
155 static void Direct3D11DestroyPool(vout_display_t
*);
157 static void DestroyDisplayPicture(picture_t
*);
158 static void DestroyDisplayPoolPicture(picture_t
*);
159 static int Direct3D11MapTexture(picture_t
*);
160 static int Direct3D11UnmapTexture(picture_t
*);
161 static void Direct3D11DeleteRegions(int, picture_t
**);
162 static int Direct3D11MapSubpicture(vout_display_t
*, int *, picture_t
***, subpicture_t
*);
164 static int AllocQuad(vout_display_t
*, const video_format_t
*, d3d_quad_t
*,
165 d3d_quad_cfg_t
*, ID3D11PixelShader
*, bool b_visible
,
166 video_projection_mode_t
);
167 static void ReleaseQuad(d3d_quad_t
*);
168 static void UpdatePicQuadPosition(vout_display_t
*);
169 static void UpdateQuadOpacity(vout_display_t
*, const d3d_quad_t
*, float);
171 static int Control(vout_display_t
*vd
, int query
, va_list args
);
172 static void Manage(vout_display_t
*vd
);
174 /* All the #if USE_DXGI contain an alternative method to setup dx11
175 They both need to be benchmarked to see which performs better */
177 /* I have no idea why MS decided dxgi headers do not define this
178 As they do have prototypes for d3d11 functions */
179 typedef HRESULT(WINAPI
*PFN_CREATE_DXGI_FACTORY
)(REFIID riid
, void **ppFactory
);
182 /* TODO: Move to a direct3d11_shaders header */
183 static const char* globVertexShaderFlat
= "\
186 float4 Position : POSITION;\
187 float2 Texture : TEXCOORD0;\
192 float4 Position : SV_POSITION;\
193 float2 Texture : TEXCOORD0;\
196 VS_OUTPUT VS( VS_INPUT In )\
202 static const char* globVertexShaderProjection
= "\
203 cbuffer VS_PROJECTION_CONST : register(b0)\
209 float4x4 Projection;\
213 float4 Position : POSITION;\
214 float2 Texture : TEXCOORD0;\
219 float4 Position : SV_POSITION;\
220 float2 Texture : TEXCOORD0;\
223 VS_OUTPUT VS( VS_INPUT In )\
226 float4 pos = In.Position;\
227 pos = mul(RotY, pos);\
228 pos = mul(RotX, pos);\
229 pos = mul(RotZ, pos);\
230 pos = mul(View, pos);\
231 pos = mul(Projection, pos);\
232 Output.Position = pos;\
233 Output.Texture = In.Texture;\
238 static const char* globPixelShaderDefault
= "\
239 cbuffer PS_CONSTANT_BUFFER : register(b0)\
246 Texture2D shaderTexture;\
247 SamplerState SampleType;\
251 float4 Position : SV_POSITION;\
252 float2 Texture : TEXCOORD0;\
255 float4 PS( PS_INPUT In ) : SV_TARGET\
259 rgba = shaderTexture.Sample(SampleType, In.Texture);\
260 rgba.a = rgba.a * Opacity;\
265 static const char *globPixelShaderBiplanarYUV_BT601_2RGB
= "\
266 cbuffer PS_CONSTANT_BUFFER : register(b0)\
273 Texture2D shaderTextureY;\
274 Texture2D shaderTextureUV;\
275 SamplerState SampleType;\
279 float4 Position : SV_POSITION;\
280 float2 Texture : TEXCOORD0;\
283 float4 PS( PS_INPUT In ) : SV_TARGET\
287 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
288 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
289 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
290 yuv.y = yuv.y - 0.5;\
291 yuv.z = yuv.z - 0.5;\
292 rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
293 rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
294 rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
300 static const char *globPixelShaderBiplanarYUV_BT709_2RGB
= "\
301 cbuffer PS_CONSTANT_BUFFER : register(b0)\
308 Texture2D shaderTextureY;\
309 Texture2D shaderTextureUV;\
310 SamplerState SampleType;\
314 float4 Position : SV_POSITION;\
315 float2 Texture : TEXCOORD0;\
318 float4 PS( PS_INPUT In ) : SV_TARGET\
322 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
323 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
324 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
325 yuv.y = yuv.y - 0.5;\
326 yuv.z = yuv.z - 0.5;\
327 rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
328 rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
329 rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
335 /* RGB-709 to RGB-2020 based on https://www.researchgate.net/publication/258434326_Beyond_BT709 */
336 static const char *globPixelShaderBiplanarYUV_BT2020_2RGB
= "\
337 cbuffer PS_CONSTANT_BUFFER : register(b0)\
344 Texture2D shaderTextureY;\
345 Texture2D shaderTextureUV;\
346 SamplerState SampleType;\
350 float4 Position : SV_POSITION;\
351 float2 Texture : TEXCOORD0;\
354 float4 PS( PS_INPUT In ) : SV_TARGET\
358 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
359 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
360 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
361 yuv.y = yuv.y - 0.5;\
362 yuv.z = yuv.z - 0.5;\
363 rgba.x = yuv.x + 1.792741071428571 * yuv.z;\
364 rgba.y = yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y;\
365 rgba.z = yuv.x + 2.112401785714286 * yuv.y;\
366 rgba.x = saturate( 1.661 * rgba.x - 0.588 * rgba.y - 0.073 * rgba.z);\
367 rgba.y = saturate(-0.125 * rgba.x + 1.133 * rgba.y - 0.008 * rgba.z);\
368 rgba.z = saturate(-0.018 * rgba.x - 0.101 * rgba.y + 1.119 * rgba.z);\
374 static const char *globPixelShaderBiplanarYUYV_BT709_2RGB
= "\
375 cbuffer PS_CONSTANT_BUFFER : register(b0)\
382 Texture2D shaderTextureYUYV;\
383 SamplerState SampleType;\
387 float4 Position : SV_POSITION;\
388 float2 Texture : TEXCOORD0;\
391 float4 PS( PS_INPUT In ) : SV_TARGET\
395 yuv.x = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
396 yuv.y = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
397 yuv.z = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
398 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
399 yuv.y = yuv.y - 0.5;\
400 yuv.z = yuv.z - 0.5;\
401 rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
402 rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
403 rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
409 static const char *globPixelShaderBiplanarYUYV_BT601_2RGB
= "\
410 cbuffer PS_CONSTANT_BUFFER : register(b0)\
417 Texture2D shaderTextureYUYV;\
418 SamplerState SampleType;\
422 float4 Position : SV_POSITION;\
423 float2 Texture : TEXCOORD0;\
426 float4 PS( PS_INPUT In ) : SV_TARGET\
430 yuv.x = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
431 yuv.y = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
432 yuv.z = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
433 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
434 yuv.y = yuv.y - 0.5;\
435 yuv.z = yuv.z - 0.5;\
436 rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
437 rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
438 rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
444 #if !VLC_WINSTORE_APP
445 static int OpenHwnd(vout_display_t
*vd
)
447 HINSTANCE hd3d11_dll
= LoadLibrary(TEXT("D3D11.DLL"));
449 msg_Warn(vd
, "cannot load d3d11.dll, aborting");
453 HINSTANCE hd3dcompiler_dll
= Direct3D11LoadShaderLibrary();
454 if (!hd3dcompiler_dll
) {
455 msg_Err(vd
, "cannot load d3dcompiler.dll, aborting");
456 Direct3D11Destroy(vd
);
461 HINSTANCE hdxgi_dll
= LoadLibrary(TEXT("DXGI.DLL"));
463 msg_Warn(vd
, "cannot load dxgi.dll, aborting");
464 Direct3D11Destroy(vd
);
469 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
473 sys
->hd3d11_dll
= hd3d11_dll
;
474 sys
->hd3dcompiler_dll
= hd3dcompiler_dll
;
476 sys
->OurD3DCompile
= (void *)GetProcAddress(sys
->hd3dcompiler_dll
, "D3DCompile");
477 if (!sys
->OurD3DCompile
) {
478 msg_Err(vd
, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
479 Direct3D11Destroy(vd
);
484 sys
->hdxgi_dll
= hdxgi_dll
;
486 /* TODO : enable all dxgi versions from 1.3 -> 1.1 */
487 PFN_CREATE_DXGI_FACTORY OurCreateDXGIFactory
=
488 (void *)GetProcAddress(hdxgi_dll
, "CreateDXGIFactory");
489 if (!OurCreateDXGIFactory
) {
490 msg_Err(vd
, "Cannot locate reference to CreateDXGIFactory in dxgi DLL");
491 Direct3D11Destroy(vd
);
495 UINT i_factory_flags
= 0;
497 i_factory_flags
|= DXGI_CREATE_FACTORY_DEBUG
;
500 /* TODO : detect the directx version supported and use IID_IDXGIFactory3 or 2 */
501 HRESULT hr
= OurCreateDXGIFactory(&IID_IDXGIFactory2
, (void **)&sys
->dxgifactory
);
503 msg_Err(vd
, "Could not create dxgi factory. (hr=0x%lX)", hr
);
504 Direct3D11Destroy(vd
);
508 sys
->OurD3D11CreateDeviceAndSwapChain
=
509 (void *)GetProcAddress(hd3d11_dll
, "D3D11CreateDeviceAndSwapChain");
510 if (!sys
->OurD3D11CreateDeviceAndSwapChain
) {
511 msg_Err(vd
, "Cannot locate reference to D3D11CreateDeviceAndSwapChain in d3d11 DLL");
512 Direct3D11Destroy(vd
);
517 sys
->OurD3D11CreateDevice
=
518 (void *)GetProcAddress(hd3d11_dll
, "D3D11CreateDevice");
519 if (!sys
->OurD3D11CreateDevice
) {
520 msg_Err(vd
, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
521 Direct3D11Destroy(vd
);
528 static int OpenCoreW(vout_display_t
*vd
)
530 IDXGISwapChain1
* dxgiswapChain
= var_InheritInteger(vd
, "winrt-swapchain");
533 ID3D11DeviceContext
* d3dcontext
= var_InheritInteger(vd
, "winrt-d3dcontext");
536 ID3D11Device
* d3ddevice
= NULL
;
537 ID3D11DeviceContext_GetDevice(d3dcontext
, &d3ddevice
);
541 vout_display_sys_t
*sys
= vd
->sys
= calloc(1, sizeof(vout_display_sys_t
));
545 sys
->dxgiswapChain
= dxgiswapChain
;
546 sys
->d3ddevice
= d3ddevice
;
547 sys
->d3dcontext
= d3dcontext
;
548 IDXGISwapChain_AddRef (sys
->dxgiswapChain
);
549 ID3D11Device_AddRef (sys
->d3ddevice
);
550 ID3D11DeviceContext_AddRef(sys
->d3dcontext
);
556 static bool is_d3d11_opaque(vlc_fourcc_t chroma
)
560 case VLC_CODEC_D3D11_OPAQUE
:
561 case VLC_CODEC_D3D11_OPAQUE_10B
:
568 static int Open(vlc_object_t
*object
)
570 vout_display_t
*vd
= (vout_display_t
*)object
;
572 #if !VLC_WINSTORE_APP
573 int ret
= OpenHwnd(vd
);
575 int ret
= OpenCoreW(vd
);
578 if (ret
!= VLC_SUCCESS
)
585 if (Direct3D11Open(vd
, &fmt
)) {
586 msg_Err(vd
, "Direct3D11 could not be opened");
590 vout_display_info_t info
= vd
->info
;
591 info
.is_slow
= !is_d3d11_opaque(fmt
.i_chroma
);
592 info
.has_double_click
= true;
593 info
.has_hide_mouse
= false;
594 info
.has_event_thread
= true;
595 info
.has_pictures_invalid
= !is_d3d11_opaque(fmt
.i_chroma
);
597 if (var_InheritBool(vd
, "direct3d11-hw-blending") &&
598 vd
->sys
->d3dregion_format
!= DXGI_FORMAT_UNKNOWN
)
599 info
.subpicture_chromas
= vd
->sys
->pSubpictureChromas
;
601 info
.subpicture_chromas
= NULL
;
603 video_format_Clean(&vd
->fmt
);
604 video_format_Copy(&vd
->fmt
, &fmt
);
608 vd
->prepare
= Prepare
;
609 vd
->display
= Display
;
610 vd
->control
= Control
;
613 msg_Dbg(vd
, "Direct3D11 Open Succeeded");
622 static void Close(vlc_object_t
*object
)
624 vout_display_t
* vd
= (vout_display_t
*)object
;
628 Direct3D11Destroy(vd
);
632 static picture_pool_t
*Pool(vout_display_t
*vd
, unsigned pool_size
)
634 if ( vd
->sys
->pool
!= NULL
)
635 return vd
->sys
->pool
;
637 if (pool_size
> 30) {
638 msg_Err(vd
, "Avoid crashing when using ID3D11VideoDecoderOutputView with too many slices");
642 #ifdef HAVE_ID3D11VIDEODECODER
643 picture_t
** pictures
= NULL
;
644 unsigned picture_count
= 0;
647 ID3D10Multithread
*pMultithread
;
648 hr
= ID3D11Device_QueryInterface( vd
->sys
->d3ddevice
, &IID_ID3D10Multithread
, (void **)&pMultithread
);
650 ID3D10Multithread_SetMultithreadProtected(pMultithread
, TRUE
);
651 ID3D10Multithread_Release(pMultithread
);
654 pictures
= calloc(pool_size
, sizeof(*pictures
));
658 D3D11_TEXTURE2D_DESC texDesc
;
659 ZeroMemory(&texDesc
, sizeof(texDesc
));
660 texDesc
.Width
= vd
->fmt
.i_width
;
661 texDesc
.Height
= vd
->fmt
.i_height
;
662 texDesc
.MipLevels
= 1;
663 texDesc
.Format
= vd
->sys
->picQuadConfig
.textureFormat
;
664 texDesc
.SampleDesc
.Count
= 1;
665 texDesc
.MiscFlags
= 0; //D3D11_RESOURCE_MISC_SHARED;
666 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
667 texDesc
.BindFlags
= D3D11_BIND_DECODER
;
668 texDesc
.CPUAccessFlags
= 0;
670 texDesc
.ArraySize
= pool_size
;
672 ID3D11Texture2D
*texture
;
673 hr
= ID3D11Device_CreateTexture2D( vd
->sys
->d3ddevice
, &texDesc
, NULL
, &texture
);
675 msg_Err(vd
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
679 for (picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
680 picture_sys_t
*picsys
= calloc(1, sizeof(*picsys
));
681 if (unlikely(picsys
== NULL
))
684 ID3D11Texture2D_AddRef(texture
);
685 picsys
->texture
= texture
;
686 picsys
->slice_index
= picture_count
;
687 picsys
->context
= vd
->sys
->d3dcontext
;
689 picture_resource_t resource
= {
691 .pf_destroy
= DestroyDisplayPoolPicture
,
694 picture_t
*picture
= picture_NewFromResource(&vd
->fmt
, &resource
);
695 if (unlikely(picture
== NULL
)) {
697 msg_Err( vd
, "Failed to create picture %d in the pool.", picture_count
);
701 pictures
[picture_count
] = picture
;
702 /* each picture_t holds a ref to the context and release it on Destroy */
703 ID3D11DeviceContext_AddRef(picsys
->context
);
705 ID3D11Texture2D_Release(texture
);
707 msg_Dbg(vd
, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d) texture 0x%p context 0x%p",
708 pool_size
, vd
->fmt
.i_width
, vd
->fmt
.i_height
, texture
, vd
->sys
->d3dcontext
);
710 picture_pool_configuration_t pool_cfg
;
711 memset(&pool_cfg
, 0, sizeof(pool_cfg
));
712 pool_cfg
.picture_count
= pool_size
;
713 pool_cfg
.picture
= pictures
;
715 vd
->sys
->pool
= picture_pool_NewExtended( &pool_cfg
);
718 if (vd
->sys
->pool
==NULL
&& pictures
) {
719 msg_Dbg(vd
, "Failed to create the picture d3d11 pool");
720 for (unsigned i
=0;i
<picture_count
; ++i
)
721 DestroyDisplayPoolPicture(pictures
[i
]);
724 /* create an empty pool to avoid crashing */
725 picture_pool_configuration_t pool_cfg
;
726 memset( &pool_cfg
, 0, sizeof( pool_cfg
) );
727 pool_cfg
.picture_count
= 0;
729 vd
->sys
->pool
= picture_pool_NewExtended( &pool_cfg
);
732 return vd
->sys
->pool
;
735 #ifdef HAVE_ID3D11VIDEODECODER
736 static void DestroyDisplayPoolPicture(picture_t
*picture
)
738 picture_sys_t
*p_sys
= (picture_sys_t
*) picture
->p_sys
;
741 ID3D11Texture2D_Release(p_sys
->texture
);
743 ID3D11DeviceContext_Release(p_sys
->context
);
750 static void DestroyDisplayPicture(picture_t
*picture
)
752 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*) picture
->p_sys
;
755 ID3D11Texture2D_Release(p_sys
->texture
);
761 static HRESULT
UpdateBackBuffer(vout_display_t
*vd
)
763 vout_display_sys_t
*sys
= vd
->sys
;
765 ID3D11Texture2D
* pDepthStencil
;
766 ID3D11Texture2D
* pBackBuffer
;
767 uint32_t i_width
= RECTWidth(sys
->rect_dest_clipped
);
768 uint32_t i_height
= RECTHeight(sys
->rect_dest_clipped
);
770 UINT dataSize
= sizeof(i_width
);
771 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_WIDTH
, &dataSize
, &i_width
);
773 msg_Err(vd
, "Can't get swapchain width, size %d. (hr=0x%lX)", hr
, dataSize
);
776 dataSize
= sizeof(i_height
);
777 hr
= IDXGISwapChain_GetPrivateData(sys
->dxgiswapChain
, &GUID_SWAPCHAIN_HEIGHT
, &dataSize
, &i_height
);
779 msg_Err(vd
, "Can't get swapchain height, size %d. (hr=0x%lX)", hr
, dataSize
);
784 if (sys
->d3drenderTargetView
) {
785 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
786 sys
->d3drenderTargetView
= NULL
;
788 if (sys
->d3ddepthStencilView
) {
789 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
790 sys
->d3ddepthStencilView
= NULL
;
793 hr
= IDXGISwapChain_ResizeBuffers(sys
->dxgiswapChain
, 0, i_width
, i_height
,
794 DXGI_FORMAT_UNKNOWN
, 0);
796 msg_Err(vd
, "Failed to resize the backbuffer. (hr=0x%lX)", hr
);
800 hr
= IDXGISwapChain_GetBuffer(sys
->dxgiswapChain
, 0, &IID_ID3D11Texture2D
, (LPVOID
*)&pBackBuffer
);
802 msg_Err(vd
, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr
);
806 hr
= ID3D11Device_CreateRenderTargetView(sys
->d3ddevice
, (ID3D11Resource
*)pBackBuffer
, NULL
, &sys
->d3drenderTargetView
);
807 ID3D11Texture2D_Release(pBackBuffer
);
809 msg_Err(vd
, "Failed to create the target view. (hr=0x%lX)", hr
);
813 D3D11_TEXTURE2D_DESC deptTexDesc
;
814 memset(&deptTexDesc
, 0,sizeof(deptTexDesc
));
815 deptTexDesc
.ArraySize
= 1;
816 deptTexDesc
.BindFlags
= D3D11_BIND_DEPTH_STENCIL
;
817 deptTexDesc
.CPUAccessFlags
= 0;
818 deptTexDesc
.Format
= DXGI_FORMAT_D24_UNORM_S8_UINT
;
819 deptTexDesc
.Width
= i_width
;
820 deptTexDesc
.Height
= i_height
;
821 deptTexDesc
.MipLevels
= 1;
822 deptTexDesc
.MiscFlags
= 0;
823 deptTexDesc
.SampleDesc
.Count
= 1;
824 deptTexDesc
.SampleDesc
.Quality
= 0;
825 deptTexDesc
.Usage
= D3D11_USAGE_DEFAULT
;
827 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &deptTexDesc
, NULL
, &pDepthStencil
);
829 msg_Err(vd
, "Could not create the depth stencil texture. (hr=0x%lX)", hr
);
833 D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc
;
834 memset(&depthViewDesc
, 0, sizeof(depthViewDesc
));
836 depthViewDesc
.Format
= deptTexDesc
.Format
;
837 depthViewDesc
.ViewDimension
= D3D11_DSV_DIMENSION_TEXTURE2D
;
838 depthViewDesc
.Texture2D
.MipSlice
= 0;
840 hr
= ID3D11Device_CreateDepthStencilView(sys
->d3ddevice
, (ID3D11Resource
*)pDepthStencil
, &depthViewDesc
, &sys
->d3ddepthStencilView
);
841 ID3D11Texture2D_Release(pDepthStencil
);
844 msg_Err(vd
, "Could not create the depth stencil view. (hr=0x%lX)", hr
);
851 /* rotation around the Z axis */
852 static void getZRotMatrix(float theta
, FLOAT matrix
[static 16])
856 sincosf(theta
, &st
, &ct
);
866 memcpy(matrix
, m
, sizeof(m
));
869 /* rotation around the Y axis */
870 static void getYRotMatrix(float theta
, FLOAT matrix
[static 16])
874 sincosf(theta
, &st
, &ct
);
884 memcpy(matrix
, m
, sizeof(m
));
887 /* rotation around the X axis */
888 static void getXRotMatrix(float phi
, FLOAT matrix
[static 16])
892 sincosf(phi
, &sp
, &cp
);
902 memcpy(matrix
, m
, sizeof(m
));
905 static void getZoomMatrix(float zoom
, FLOAT matrix
[static 16]) {
909 1.0f
, 0.0f
, 0.0f
, 0.0f
,
910 0.0f
, 1.0f
, 0.0f
, 0.0f
,
911 0.0f
, 0.0f
, 1.0f
, 0.0f
,
912 0.0f
, 0.0f
, zoom
, 1.0f
915 memcpy(matrix
, m
, sizeof(m
));
918 /* perspective matrix see https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml */
919 static void getProjectionMatrix(float sar
, float fovy
, FLOAT matrix
[static 16]) {
924 float f
= 1.f
/ tanf(fovy
/ 2.f
);
927 f
/ sar
, 0.f
, 0.f
, 0.f
,
929 0.f
, 0.f
, -(zNear
+ zFar
) / (zNear
- zFar
), 1.f
,
930 0.f
, 0.f
, (2 * zNear
* zFar
) / (zNear
- zFar
), 0.f
};
932 memcpy(matrix
, m
, sizeof(m
));
935 static void SetQuadVSProjection(vout_display_t
*vd
, d3d_quad_t
*quad
, const vlc_viewpoint_t
*p_vp
)
937 vout_display_sys_t
*sys
= vd
->sys
;
939 D3D11_MAPPED_SUBRESOURCE mapped
;
940 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexShaderConstants
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mapped
);
942 VS_PROJECTION_CONST
*dst_data
= mapped
.pData
;
943 #define RAD(d) ((float) ((d) * M_PI / 180.f))
944 getXRotMatrix(-RAD(p_vp
->pitch
), dst_data
->RotX
);
945 getYRotMatrix(-RAD(p_vp
->yaw
), dst_data
->RotY
);
946 getZRotMatrix(-RAD(p_vp
->roll
), dst_data
->RotZ
);
947 getZoomMatrix(SPHERE_RADIUS
, dst_data
->View
); /* FIXME */
948 float sar
= (float) vd
->cfg
->display
.width
/ vd
->cfg
->display
.height
;
949 getProjectionMatrix(sar
, RAD(p_vp
->fov
), dst_data
->Projection
);
952 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexShaderConstants
, 0);
955 static void CropStagingFormat(vout_display_t
*vd
, video_format_t
*backup_fmt
)
957 if ( vd
->sys
->stagingQuad
.pTexture
== NULL
)
960 video_format_Copy( backup_fmt
, &vd
->source
);
961 /* the texture we display is a cropped version of the source */
962 vd
->source
.i_x_offset
= 0;
963 vd
->source
.i_y_offset
= 0;
964 vd
->source
.i_width
= vd
->source
.i_visible_width
;
965 vd
->source
.i_height
= vd
->source
.i_visible_height
;
968 static void UncropStagingFormat(vout_display_t
*vd
, video_format_t
*backup_fmt
)
970 if ( vd
->sys
->stagingQuad
.pTexture
== NULL
)
972 video_format_Copy( &vd
->source
, backup_fmt
);
975 static int Control(vout_display_t
*vd
, int query
, va_list args
)
977 video_format_t core_source
;
978 CropStagingFormat( vd
, &core_source
);
979 int res
= CommonControl( vd
, query
, args
);
981 if (query
== VOUT_DISPLAY_CHANGE_VIEWPOINT
)
983 const vout_display_cfg_t
*cfg
= va_arg(args
, const vout_display_cfg_t
*);
984 if ( vd
->sys
->picQuad
.pVertexShaderConstants
)
986 SetQuadVSProjection( vd
, &vd
->sys
->picQuad
, &cfg
->viewpoint
);
991 UncropStagingFormat( vd
, &core_source
);
995 static void Manage(vout_display_t
*vd
)
997 vout_display_sys_t
*sys
= vd
->sys
;
998 RECT size_before
= sys
->rect_dest_clipped
;
1000 video_format_t core_source
;
1001 CropStagingFormat( vd
, &core_source
);
1004 if (RECTWidth(size_before
) != RECTWidth(sys
->rect_dest_clipped
) ||
1005 RECTHeight(size_before
) != RECTHeight(sys
->rect_dest_clipped
))
1007 #if defined(HAVE_ID3D11VIDEODECODER)
1008 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1010 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1013 msg_Dbg(vd
, "Manage detected size change %dx%d", RECTWidth(sys
->rect_dest_clipped
),
1014 RECTHeight(sys
->rect_dest_clipped
));
1016 UpdateBackBuffer(vd
);
1018 UpdatePicQuadPosition(vd
);
1019 #if defined(HAVE_ID3D11VIDEODECODER)
1020 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1022 ReleaseMutex( sys
->context_lock
);
1026 UncropStagingFormat( vd
, &core_source
);
1029 static void Prepare(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
1031 vout_display_sys_t
*sys
= vd
->sys
;
1033 if ( !is_d3d11_opaque(picture
->format
.i_chroma
) &&
1034 sys
->stagingQuad
.pTexture
!= NULL
)
1036 Direct3D11UnmapTexture(picture
);
1039 box
.left
= picture
->format
.i_x_offset
;
1040 /* box.right = picture->format.i_x_offset + picture->format.i_visible_width; */
1041 box
.top
= picture
->format
.i_y_offset
;
1042 /* box.bottom = picture->format.i_y_offset + picture->format.i_visible_height; */
1046 D3D11_TEXTURE2D_DESC dstDesc
;
1047 ID3D11Texture2D_GetDesc(sys
->picQuad
.pTexture
, &dstDesc
);
1048 box
.bottom
= box
.top
+ dstDesc
.Height
;
1049 box
.right
= box
.left
+ dstDesc
.Width
;
1051 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
1052 (ID3D11Resource
*) sys
->picQuad
.pTexture
,
1054 (ID3D11Resource
*) sys
->stagingQuad
.pTexture
,
1058 #ifdef HAVE_ID3D11VIDEODECODER
1059 if (is_d3d11_opaque(picture
->format
.i_chroma
)) {
1060 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1062 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1065 picture_sys_t
*p_sys
= picture
->p_sys
;
1066 D3D11_TEXTURE2D_DESC texDesc
;
1067 ID3D11Texture2D_GetDesc( p_sys
->texture
, &texDesc
);
1068 if (texDesc
.Format
== DXGI_FORMAT_NV12
|| texDesc
.Format
== DXGI_FORMAT_P010
)
1070 box
.left
= (picture
->format
.i_x_offset
+ 1) & ~1;
1071 box
.right
= (picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
) & ~1;
1072 box
.top
= (picture
->format
.i_y_offset
+ 1) & ~1;
1073 box
.bottom
= (picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
) & ~1;
1077 box
.left
= picture
->format
.i_x_offset
;
1078 box
.right
= picture
->format
.i_x_offset
+ picture
->format
.i_visible_width
;
1079 box
.top
= picture
->format
.i_y_offset
;
1080 box
.bottom
= picture
->format
.i_y_offset
+ picture
->format
.i_visible_height
;
1085 ID3D11DeviceContext_CopySubresourceRegion(sys
->d3dcontext
,
1086 (ID3D11Resource
*) sys
->picQuad
.pTexture
,
1088 (ID3D11Resource
*) p_sys
->texture
,
1089 p_sys
->slice_index
, &box
);
1094 int subpicture_region_count
= 0;
1095 picture_t
**subpicture_regions
= NULL
;
1096 Direct3D11MapSubpicture(vd
, &subpicture_region_count
, &subpicture_regions
, subpicture
);
1097 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
1098 sys
->d3dregion_count
= subpicture_region_count
;
1099 sys
->d3dregions
= subpicture_regions
;
1103 static void DisplayD3DPicture(vout_display_sys_t
*sys
, d3d_quad_t
*quad
)
1105 UINT stride
= sizeof(d3d_vertex_t
);
1108 /* Render the quad */
1110 ID3D11DeviceContext_IASetVertexBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexBuffer
, &stride
, &offset
);
1111 ID3D11DeviceContext_IASetIndexBuffer(sys
->d3dcontext
, quad
->pIndexBuffer
, DXGI_FORMAT_R16_UINT
, 0);
1112 if ( quad
->pVertexShaderConstants
)
1113 ID3D11DeviceContext_VSSetConstantBuffers(sys
->d3dcontext
, 0, 1, &quad
->pVertexShaderConstants
);
1115 ID3D11DeviceContext_VSSetShader(sys
->d3dcontext
, quad
->d3dvertexShader
, NULL
, 0);
1118 ID3D11DeviceContext_PSSetShader(sys
->d3dcontext
, quad
->d3dpixelShader
, NULL
, 0);
1120 ID3D11DeviceContext_PSSetConstantBuffers(sys
->d3dcontext
, 0, 1, &quad
->pPixelShaderConstants
);
1121 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 0, 1, &quad
->d3dresViewY
);
1122 if( quad
->d3dresViewUV
)
1123 ID3D11DeviceContext_PSSetShaderResources(sys
->d3dcontext
, 1, 1, &quad
->d3dresViewUV
);
1125 ID3D11DeviceContext_RSSetViewports(sys
->d3dcontext
, 1, &quad
->cropViewport
);
1127 ID3D11DeviceContext_DrawIndexed(sys
->d3dcontext
, quad
->indexCount
, 0, 0);
1130 static void Display(vout_display_t
*vd
, picture_t
*picture
, subpicture_t
*subpicture
)
1132 vout_display_sys_t
*sys
= vd
->sys
;
1134 FLOAT blackRGBA
[4] = {0.0f
, 0.0f
, 0.0f
, 1.0f
};
1135 ID3D11DeviceContext_ClearRenderTargetView(sys
->d3dcontext
, sys
->d3drenderTargetView
, blackRGBA
);
1137 /* no ID3D11Device operations should come here */
1139 ID3D11DeviceContext_OMSetRenderTargets(sys
->d3dcontext
, 1, &sys
->d3drenderTargetView
, sys
->d3ddepthStencilView
);
1141 ID3D11DeviceContext_ClearDepthStencilView(sys
->d3dcontext
, sys
->d3ddepthStencilView
, D3D11_CLEAR_DEPTH
| D3D11_CLEAR_STENCIL
, 1.0f
, 0);
1143 if ( !is_d3d11_opaque(picture
->format
.i_chroma
) &&
1144 sys
->stagingQuad
.pTexture
== NULL
)
1145 Direct3D11UnmapTexture(picture
);
1147 /* Render the quad */
1148 DisplayD3DPicture(sys
, &sys
->picQuad
);
1151 // draw the additional vertices
1152 for (int i
= 0; i
< sys
->d3dregion_count
; ++i
) {
1153 if (sys
->d3dregions
[i
])
1154 DisplayD3DPicture(sys
, (d3d_quad_t
*) sys
->d3dregions
[i
]->p_sys
);
1158 DXGI_PRESENT_PARAMETERS presentParams
;
1159 memset(&presentParams
, 0, sizeof(presentParams
));
1160 HRESULT hr
= IDXGISwapChain1_Present1(sys
->dxgiswapChain
, 0, 0, &presentParams
);
1161 if (hr
== DXGI_ERROR_DEVICE_REMOVED
|| hr
== DXGI_ERROR_DEVICE_RESET
)
1163 /* TODO device lost */
1164 msg_Dbg(vd
, "SwapChain Present failed. (hr=0x%lX)", hr
);
1166 #if defined(HAVE_ID3D11VIDEODECODER)
1167 if( is_d3d11_opaque(picture
->format
.i_chroma
) && sys
->context_lock
!= INVALID_HANDLE_VALUE
) {
1168 ReleaseMutex( sys
->context_lock
);
1172 picture_Release(picture
);
1174 subpicture_Delete(subpicture
);
1179 static void Direct3D11Destroy(vout_display_t
*vd
)
1181 #if !VLC_WINSTORE_APP
1182 vout_display_sys_t
*sys
= vd
->sys
;
1186 FreeLibrary(sys
->hdxgi_dll
);
1189 if (sys
->hd3d11_dll
)
1190 FreeLibrary(sys
->hd3d11_dll
);
1191 if (sys
->hd3dcompiler_dll
)
1192 FreeLibrary(sys
->hd3dcompiler_dll
);
1194 sys
->OurD3D11CreateDevice
= NULL
;
1195 sys
->OurD3D11CreateDeviceAndSwapChain
= NULL
;
1196 sys
->OurD3DCompile
= NULL
;
1197 sys
->hdxgi_dll
= NULL
;
1198 sys
->hd3d11_dll
= NULL
;
1199 sys
->hd3dcompiler_dll
= NULL
;
1205 #if !VLC_WINSTORE_APP
1206 static HINSTANCE
Direct3D11LoadShaderLibrary(void)
1208 HINSTANCE instance
= NULL
;
1209 /* d3dcompiler_47 is the latest on windows 8.1 */
1210 for (int i
= 47; i
> 41; --i
) {
1212 _sntprintf(filename
, 19, TEXT("D3DCOMPILER_%d.dll"), i
);
1213 instance
= LoadLibrary(filename
);
1214 if (instance
) break;
1221 static int Direct3D11Open(vout_display_t
*vd
, video_format_t
*fmt
)
1223 vout_display_sys_t
*sys
= vd
->sys
;
1226 #if !VLC_WINSTORE_APP
1228 UINT creationFlags
= 0;
1231 # if !defined(NDEBUG) && defined(_MSC_VER)
1232 creationFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
1235 DXGI_SWAP_CHAIN_DESC1 scd
;
1236 memset(&scd
, 0, sizeof(scd
));
1237 scd
.BufferCount
= 2;
1238 scd
.BufferUsage
= DXGI_USAGE_RENDER_TARGET_OUTPUT
;
1239 scd
.SampleDesc
.Count
= 1;
1240 scd
.SampleDesc
.Quality
= 0;
1241 scd
.Width
= fmt
->i_visible_width
;
1242 scd
.Height
= fmt
->i_visible_height
;
1243 switch(fmt
->i_chroma
)
1245 case VLC_CODEC_D3D11_OPAQUE_10B
:
1246 scd
.Format
= DXGI_FORMAT_R10G10B10A2_UNORM
;
1249 scd
.Format
= DXGI_FORMAT_R8G8B8A8_UNORM
; /* TODO: use DXGI_FORMAT_NV12 */
1252 //scd.Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
1253 scd
.SwapEffect
= DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
;
1255 IDXGIAdapter
*dxgiadapter
;
1256 static const D3D_FEATURE_LEVEL featureLevels
[] =
1258 0xc000 /* D3D_FEATURE_LEVEL_12_1 */,
1259 0xc100 /* D3D_FEATURE_LEVEL_12_0 */,
1260 D3D_FEATURE_LEVEL_11_1
,
1261 D3D_FEATURE_LEVEL_11_0
,
1262 D3D_FEATURE_LEVEL_10_1
,
1263 D3D_FEATURE_LEVEL_10_0
,
1264 D3D_FEATURE_LEVEL_9_3
,
1265 D3D_FEATURE_LEVEL_9_2
,
1266 D3D_FEATURE_LEVEL_9_1
,
1270 /* TODO : list adapters for the user to choose from */
1271 hr
= IDXGIFactory2_EnumAdapters(sys
->dxgifactory
, 0, &dxgiadapter
);
1273 msg_Err(vd
, "Could not create find factory. (hr=0x%lX)", hr
);
1274 return VLC_EGENERIC
;
1277 IDXGIOutput
* output
;
1278 hr
= IDXGIAdapter_EnumOutputs(dxgiadapter
, 0, &output
);
1280 msg_Err(vd
, "Could not Enumerate DXGI Outputs. (hr=0x%lX)", hr
);
1281 IDXGIAdapter_Release(dxgiadapter
);
1282 return VLC_EGENERIC
;
1286 memset(&md
, 0, sizeof(md
));
1287 md
.Width
= fmt
->i_visible_width
;
1288 md
.Height
= fmt
->i_visible_height
;
1289 md
.Format
= scd
.BufferDesc
.Format
;
1290 md
.Scaling
= DXGI_MODE_SCALING_UNSPECIFIED
;
1292 hr
= IDXGIOutput_FindClosestMatchingMode(output
, &md
, &scd
.BufferDesc
, NULL
);
1294 msg_Err(vd
, "Failed to find a supported video mode. (hr=0x%lX)", hr
);
1295 IDXGIAdapter_Release(dxgiadapter
);
1296 return VLC_EGENERIC
;
1299 /* mode desc doesn't carry over the width and height*/
1300 scd
.BufferDesc
.Width
= fmt
->i_visible_width
;
1301 scd
.BufferDesc
.Height
= fmt
->i_visible_height
;
1303 hr
= D3D11CreateDeviceAndSwapChain(dxgiadapter
,
1304 D3D_DRIVER_TYPE_UNKNOWN
, NULL
, creationFlags
,
1305 featureLevels
, ARRAYSIZE(featureLevels
),
1306 D3D11_SDK_VERSION
, &scd
, &sys
->dxgiswapChain
,
1307 &sys
->d3ddevice
, NULL
, &sys
->d3dcontext
);
1308 IDXGIAdapter_Release(dxgiadapter
);
1310 msg_Err(vd
, "Could not Create the D3D11 device and SwapChain. (hr=0x%lX)", hr
);
1311 return VLC_EGENERIC
;
1316 static const D3D_DRIVER_TYPE driverAttempts
[] = {
1317 D3D_DRIVER_TYPE_HARDWARE
,
1318 D3D_DRIVER_TYPE_WARP
,
1320 D3D_DRIVER_TYPE_REFERENCE
,
1324 for (UINT driver
= 0; driver
< ARRAYSIZE(driverAttempts
); driver
++) {
1325 D3D_FEATURE_LEVEL i_feature_level
;
1326 hr
= D3D11CreateDevice(NULL
, driverAttempts
[driver
], NULL
, creationFlags
,
1327 featureLevels
, 9, D3D11_SDK_VERSION
,
1328 &sys
->d3ddevice
, &i_feature_level
, &sys
->d3dcontext
);
1329 if (SUCCEEDED(hr
)) {
1331 msg_Dbg(vd
, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
1332 (void *)sys
->d3ddevice
, (void *)sys
->d3dcontext
,
1333 driverAttempts
[driver
], i_feature_level
);
1340 msg_Err(vd
, "Could not Create the D3D11 device. (hr=0x%lX)", hr
);
1341 return VLC_EGENERIC
;
1344 IDXGIDevice
*pDXGIDevice
= NULL
;
1345 hr
= ID3D11Device_QueryInterface(sys
->d3ddevice
, &IID_IDXGIDevice
, (void **)&pDXGIDevice
);
1347 msg_Err(vd
, "Could not Query DXGI Interface. (hr=0x%lX)", hr
);
1348 return VLC_EGENERIC
;
1351 hr
= IDXGIDevice_GetAdapter(pDXGIDevice
, &dxgiadapter
);
1352 IDXGIAdapter_Release(pDXGIDevice
);
1354 msg_Err(vd
, "Could not get the DXGI Adapter. (hr=0x%lX)", hr
);
1355 return VLC_EGENERIC
;
1358 hr
= IDXGIAdapter_GetParent(dxgiadapter
, &IID_IDXGIFactory2
, (void **)&sys
->dxgifactory
);
1359 IDXGIAdapter_Release(dxgiadapter
);
1361 msg_Err(vd
, "Could not get the DXGI Factory. (hr=0x%lX)", hr
);
1362 return VLC_EGENERIC
;
1365 hr
= IDXGIFactory2_CreateSwapChainForHwnd(sys
->dxgifactory
, (IUnknown
*)sys
->d3ddevice
,
1366 sys
->hvideownd
, &scd
, NULL
, NULL
, &sys
->dxgiswapChain
);
1367 IDXGIFactory2_Release(sys
->dxgifactory
);
1369 msg_Err(vd
, "Could not create the SwapChain. (hr=0x%lX)", hr
);
1370 return VLC_EGENERIC
;
1376 vlc_fourcc_t i_src_chroma
= fmt
->i_chroma
;
1379 // look for the requested pixel format first
1380 UINT i_quadSupportFlags
= D3D11_FORMAT_SUPPORT_TEXTURE2D
| D3D11_FORMAT_SUPPORT_SHADER_LOAD
;
1381 UINT i_formatSupport
;
1382 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1383 output_format
->name
!= NULL
; ++output_format
)
1385 if( i_src_chroma
== output_format
->fourcc
)
1387 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1388 output_format
->formatTexture
,
1389 &i_formatSupport
)) &&
1390 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
)
1392 msg_Dbg( vd
, "Using pixel format %s from chroma %4.4s", output_format
->name
,
1393 (char *)&i_src_chroma
);
1394 fmt
->i_chroma
= output_format
->fourcc
;
1395 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1396 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1397 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1398 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1404 // look for any pixel format that we can handle with enough pixels per channel
1405 if ( !fmt
->i_chroma
)
1407 uint8_t bits_per_channel
;
1408 switch (i_src_chroma
)
1410 case VLC_CODEC_D3D11_OPAQUE
:
1411 bits_per_channel
= 8;
1413 case VLC_CODEC_D3D11_OPAQUE_10B
:
1414 bits_per_channel
= 10;
1418 const vlc_chroma_description_t
*p_format
= vlc_fourcc_GetChromaDescription(i_src_chroma
);
1419 bits_per_channel
= p_format
== NULL
|| p_format
->pixel_bits
== 0 ? 8 : p_format
->pixel_bits
;
1424 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1425 output_format
->name
!= NULL
; ++output_format
)
1427 if( bits_per_channel
<= output_format
->bitsPerChannel
&&
1428 !is_d3d11_opaque(output_format
->fourcc
) )
1430 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1431 output_format
->formatTexture
,
1432 &i_formatSupport
)) &&
1433 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
)
1435 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", output_format
->name
,
1436 (char *)&i_src_chroma
);
1437 fmt
->i_chroma
= output_format
->fourcc
;
1438 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1439 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1440 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1441 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1447 // look for any pixel format that we can handle
1448 if ( !fmt
->i_chroma
)
1450 for (const d3d_format_t
*output_format
= GetRenderFormatList();
1451 output_format
->name
!= NULL
; ++output_format
)
1453 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1454 output_format
->formatTexture
,
1455 &i_formatSupport
)) &&
1456 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
&&
1457 !is_d3d11_opaque(output_format
->fourcc
) )
1459 msg_Dbg( vd
, "Using pixel format %s for chroma %4.4s", output_format
->name
,
1460 (char *)&i_src_chroma
);
1461 fmt
->i_chroma
= output_format
->fourcc
;
1462 DxgiFormatMask( output_format
->formatTexture
, fmt
);
1463 sys
->picQuadConfig
.textureFormat
= output_format
->formatTexture
;
1464 sys
->picQuadConfig
.resourceFormatYRGB
= output_format
->formatY
;
1465 sys
->picQuadConfig
.resourceFormatUV
= output_format
->formatUV
;
1470 if ( !fmt
->i_chroma
)
1472 msg_Err(vd
, "Could not get a suitable texture pixel format");
1473 return VLC_EGENERIC
;
1476 /* check the region pixel format */
1477 i_quadSupportFlags
|= D3D11_FORMAT_SUPPORT_BLENDABLE
;
1478 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1479 DXGI_FORMAT_R8G8B8A8_UNORM
,
1480 &i_formatSupport
)) &&
1481 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
) {
1482 sys
->d3dregion_format
= DXGI_FORMAT_R8G8B8A8_UNORM
;
1483 sys
->pSubpictureChromas
[0] = VLC_CODEC_RGBA
;
1484 sys
->pSubpictureChromas
[1] = 0;
1485 } else if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys
->d3ddevice
,
1486 DXGI_FORMAT_B8G8R8A8_UNORM
,
1487 &i_formatSupport
)) &&
1488 ( i_formatSupport
& i_quadSupportFlags
) == i_quadSupportFlags
) {
1489 sys
->d3dregion_format
= DXGI_FORMAT_B8G8R8A8_UNORM
;
1490 sys
->pSubpictureChromas
[0] = VLC_CODEC_BGRA
;
1491 sys
->pSubpictureChromas
[1] = 0;
1493 sys
->d3dregion_format
= DXGI_FORMAT_UNKNOWN
;
1496 if (sys
->picQuadConfig
.resourceFormatYRGB
== DXGI_FORMAT_R8_UNORM
||
1497 sys
->picQuadConfig
.resourceFormatYRGB
== DXGI_FORMAT_R16_UNORM
)
1499 if (vd
->fmt
.space
== COLOR_SPACE_BT2020
)
1500 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT2020_2RGB
;
1501 else if (vd
->fmt
.space
== COLOR_SPACE_BT709
)
1502 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT709_2RGB
;
1503 else if (vd
->fmt
.space
== COLOR_SPACE_BT601
)
1504 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT601_2RGB
;
1505 else if( fmt
->i_height
> 576 )
1506 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT709_2RGB
;
1508 sys
->d3dPxShader
= globPixelShaderBiplanarYUV_BT601_2RGB
;
1511 if (fmt
->i_chroma
== VLC_CODEC_YUYV
)
1513 if( fmt
->i_height
> 576 )
1514 sys
->d3dPxShader
= globPixelShaderBiplanarYUYV_BT709_2RGB
;
1516 sys
->d3dPxShader
= globPixelShaderBiplanarYUYV_BT601_2RGB
;
1519 sys
->d3dPxShader
= globPixelShaderDefault
;
1521 if (sys
->d3dregion_format
!= DXGI_FORMAT_UNKNOWN
)
1522 sys
->psz_rgbaPxShader
= globPixelShaderDefault
;
1524 sys
->psz_rgbaPxShader
= NULL
;
1526 if ( fmt
->i_height
!= fmt
->i_visible_height
|| fmt
->i_width
!= fmt
->i_visible_width
)
1528 msg_Dbg( vd
, "use a staging texture to crop to visible size" );
1529 AllocQuad( vd
, fmt
, &sys
->stagingQuad
, &sys
->picQuadConfig
, NULL
, false,
1530 PROJECTION_MODE_RECTANGULAR
);
1533 video_format_t core_source
;
1534 CropStagingFormat( vd
, &core_source
);
1535 UpdateRects(vd
, NULL
, NULL
, true);
1536 UncropStagingFormat( vd
, &core_source
);
1538 #if defined(HAVE_ID3D11VIDEODECODER)
1539 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1541 WaitForSingleObjectEx( sys
->context_lock
, INFINITE
, FALSE
);
1544 if (Direct3D11CreateResources(vd
, fmt
)) {
1545 #if defined(HAVE_ID3D11VIDEODECODER)
1546 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1548 ReleaseMutex( sys
->context_lock
);
1551 msg_Err(vd
, "Failed to allocate resources");
1552 Direct3D11DestroyResources(vd
);
1553 return VLC_EGENERIC
;
1555 #if defined(HAVE_ID3D11VIDEODECODER)
1556 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
1558 ReleaseMutex( sys
->context_lock
);
1562 #if !VLC_WINSTORE_APP
1563 EventThreadUpdateTitle(sys
->event
, VOUT_TITLE
" (Direct3D11 output)");
1566 msg_Dbg(vd
, "Direct3D11 device adapter successfully initialized");
1570 static void Direct3D11Close(vout_display_t
*vd
)
1572 vout_display_sys_t
*sys
= vd
->sys
;
1574 Direct3D11DestroyResources(vd
);
1575 if (sys
->d3dcontext
)
1577 ID3D11DeviceContext_Flush(sys
->d3dcontext
);
1578 ID3D11DeviceContext_Release(sys
->d3dcontext
);
1579 sys
->d3dcontext
= NULL
;
1583 ID3D11Device_Release(sys
->d3ddevice
);
1584 sys
->d3ddevice
= NULL
;
1586 if (sys
->dxgiswapChain
)
1588 IDXGISwapChain_Release(sys
->dxgiswapChain
);
1589 sys
->dxgiswapChain
= NULL
;
1592 msg_Dbg(vd
, "Direct3D11 device adapter closed");
1595 static void UpdatePicQuadPosition(vout_display_t
*vd
)
1597 vout_display_sys_t
*sys
= vd
->sys
;
1598 int i_width
= RECTWidth(sys
->rect_dest_clipped
);
1599 int i_height
= RECTHeight(sys
->rect_dest_clipped
);
1601 int i_top
= sys
->rect_src_clipped
.top
* i_height
;
1602 i_top
/= vd
->source
.i_visible_height
;
1603 i_top
-= sys
->rect_dest_clipped
.top
;
1604 int i_left
= sys
->rect_src_clipped
.left
* i_width
;
1605 i_left
/= vd
->source
.i_visible_width
;
1606 i_left
-= sys
->rect_dest_clipped
.left
;
1608 sys
->picQuad
.cropViewport
.Width
= (FLOAT
) vd
->source
.i_width
* i_width
/ vd
->source
.i_visible_width
;
1609 sys
->picQuad
.cropViewport
.Height
= (FLOAT
) vd
->source
.i_height
* i_height
/ vd
->source
.i_visible_height
;
1610 sys
->picQuad
.cropViewport
.TopLeftX
= -i_left
;
1611 sys
->picQuad
.cropViewport
.TopLeftY
= -i_top
;
1613 sys
->picQuad
.cropViewport
.MinDepth
= 0.0f
;
1614 sys
->picQuad
.cropViewport
.MaxDepth
= 1.0f
;
1617 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
);
1621 /* TODO : handle errors better
1622 TODO : seperate out into smaller functions like createshaders */
1623 static int Direct3D11CreateResources(vout_display_t
*vd
, video_format_t
*fmt
)
1625 vout_display_sys_t
*sys
= vd
->sys
;
1628 #if defined(HAVE_ID3D11VIDEODECODER)
1629 sys
->context_lock
= CreateMutexEx( NULL
, NULL
, 0, SYNCHRONIZE
);
1630 ID3D11Device_SetPrivateData( sys
->d3ddevice
, &GUID_CONTEXT_MUTEX
, sizeof( sys
->context_lock
), &sys
->context_lock
);
1633 hr
= UpdateBackBuffer(vd
);
1635 msg_Err(vd
, "Could not update the backbuffer. (hr=0x%lX)", hr
);
1636 return VLC_EGENERIC
;
1639 ID3D11BlendState
*pSpuBlendState
;
1640 D3D11_BLEND_DESC spuBlendDesc
= { 0 };
1641 spuBlendDesc
.RenderTarget
[0].BlendEnable
= TRUE
;
1642 spuBlendDesc
.RenderTarget
[0].SrcBlend
= D3D11_BLEND_SRC_ALPHA
;
1643 spuBlendDesc
.RenderTarget
[0].DestBlend
= D3D11_BLEND_INV_SRC_ALPHA
;
1644 spuBlendDesc
.RenderTarget
[0].BlendOp
= D3D11_BLEND_OP_ADD
;
1646 spuBlendDesc
.RenderTarget
[0].SrcBlendAlpha
= D3D11_BLEND_ONE
;
1647 spuBlendDesc
.RenderTarget
[0].DestBlendAlpha
= D3D11_BLEND_ZERO
;
1648 spuBlendDesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
1650 spuBlendDesc
.RenderTarget
[0].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
1652 spuBlendDesc
.RenderTarget
[1].BlendEnable
= TRUE
;
1653 spuBlendDesc
.RenderTarget
[1].SrcBlend
= D3D11_BLEND_ONE
;
1654 spuBlendDesc
.RenderTarget
[1].DestBlend
= D3D11_BLEND_ZERO
;
1655 spuBlendDesc
.RenderTarget
[1].BlendOp
= D3D11_BLEND_OP_ADD
;
1657 spuBlendDesc
.RenderTarget
[1].SrcBlendAlpha
= D3D11_BLEND_ONE
;
1658 spuBlendDesc
.RenderTarget
[1].DestBlendAlpha
= D3D11_BLEND_ZERO
;
1659 spuBlendDesc
.RenderTarget
[1].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
1661 spuBlendDesc
.RenderTarget
[1].RenderTargetWriteMask
= D3D11_COLOR_WRITE_ENABLE_ALL
;
1662 hr
= ID3D11Device_CreateBlendState(sys
->d3ddevice
, &spuBlendDesc
, &pSpuBlendState
);
1664 msg_Err(vd
, "Could not create SPU blend state. (hr=0x%lX)", hr
);
1665 return VLC_EGENERIC
;
1667 ID3D11DeviceContext_OMSetBlendState(sys
->d3dcontext
, pSpuBlendState
, NULL
, 0xFFFFFFFF);
1668 ID3D11BlendState_Release(pSpuBlendState
);
1670 /* disable depth testing as we're only doing 2D
1671 * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
1672 * see http://rastertek.com/dx11tut11.html
1674 D3D11_DEPTH_STENCIL_DESC stencilDesc
;
1675 ZeroMemory(&stencilDesc
, sizeof(stencilDesc
));
1677 ID3D11DepthStencilState
*pDepthStencilState
;
1678 hr
= ID3D11Device_CreateDepthStencilState(sys
->d3ddevice
, &stencilDesc
, &pDepthStencilState
);
1679 if (SUCCEEDED(hr
)) {
1680 ID3D11DeviceContext_OMSetDepthStencilState(sys
->d3dcontext
, pDepthStencilState
, 0);
1681 ID3D11DepthStencilState_Release(pDepthStencilState
);
1684 ID3DBlob
* pVSBlob
= NULL
;
1685 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1686 hr
= D3DCompile(globVertexShaderFlat
, strlen(globVertexShaderFlat
),
1687 NULL
, NULL
, NULL
, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob
, NULL
);
1690 msg_Err(vd
, "The flat Vertex Shader is invalid. (hr=0x%lX)", hr
);
1691 return VLC_EGENERIC
;
1694 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1695 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &sys
->flatVSShader
);
1698 ID3D11Device_Release(pVSBlob
);
1699 msg_Err(vd
, "Failed to create the flat vertex shader. (hr=0x%lX)", hr
);
1700 return VLC_EGENERIC
;
1703 D3D11_INPUT_ELEMENT_DESC layout
[] = {
1704 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D11_APPEND_ALIGNED_ELEMENT
, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1705 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT
, 0, D3D11_APPEND_ALIGNED_ELEMENT
, D3D11_INPUT_PER_VERTEX_DATA
, 0},
1708 ID3D11InputLayout
* pVertexLayout
= NULL
;
1709 hr
= ID3D11Device_CreateInputLayout(sys
->d3ddevice
, layout
, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1710 ID3D10Blob_GetBufferSize(pVSBlob
), &pVertexLayout
);
1712 ID3D10Blob_Release(pVSBlob
);
1715 msg_Err(vd
, "Failed to create the vertex input layout. (hr=0x%lX)", hr
);
1716 return VLC_EGENERIC
;
1718 ID3D11DeviceContext_IASetInputLayout(sys
->d3dcontext
, pVertexLayout
);
1719 ID3D11InputLayout_Release(pVertexLayout
);
1721 hr
= D3DCompile(globVertexShaderProjection
, strlen(globVertexShaderProjection
),
1722 NULL
, NULL
, NULL
, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob
, NULL
);
1725 msg_Err(vd
, "The projection Vertex Shader is invalid. (hr=0x%lX)", hr
);
1726 return VLC_EGENERIC
;
1729 hr
= ID3D11Device_CreateVertexShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pVSBlob
),
1730 ID3D10Blob_GetBufferSize(pVSBlob
), NULL
, &sys
->projectionVSShader
);
1733 ID3D11Device_Release(pVSBlob
);
1734 msg_Err(vd
, "Failed to create the projection vertex shader. (hr=0x%lX)", hr
);
1735 return VLC_EGENERIC
;
1737 ID3D10Blob_Release(pVSBlob
);
1739 ID3D11DeviceContext_IASetPrimitiveTopology(sys
->d3dcontext
, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
1741 ID3DBlob
* pPSBlob
= NULL
;
1743 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1744 hr
= D3DCompile(sys
->d3dPxShader
, strlen(sys
->d3dPxShader
),
1745 NULL
, NULL
, NULL
, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob
, NULL
);
1749 msg_Err(vd
, "The Pixel Shader is invalid. (hr=0x%lX)", hr
);
1750 return VLC_EGENERIC
;
1753 ID3D11PixelShader
*pPicQuadShader
;
1754 hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
1755 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, &pPicQuadShader
);
1757 ID3D10Blob_Release(pPSBlob
);
1760 msg_Err(vd
, "Failed to create the pixel shader. (hr=0x%lX)", hr
);
1761 return VLC_EGENERIC
;
1764 if (sys
->psz_rgbaPxShader
!= NULL
)
1766 hr
= D3DCompile(sys
->psz_rgbaPxShader
, strlen(sys
->psz_rgbaPxShader
),
1767 NULL
, NULL
, NULL
, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob
, NULL
);
1769 ID3D11PixelShader_Release(pPicQuadShader
);
1770 msg_Err(vd
, "The RGBA Pixel Shader is invalid. (hr=0x%lX)", hr
);
1771 return VLC_EGENERIC
;
1774 hr
= ID3D11Device_CreatePixelShader(sys
->d3ddevice
, (void *)ID3D10Blob_GetBufferPointer(pPSBlob
),
1775 ID3D10Blob_GetBufferSize(pPSBlob
), NULL
, &sys
->pSPUPixelShader
);
1777 ID3D10Blob_Release(pPSBlob
);
1780 ID3D11PixelShader_Release(pPicQuadShader
);
1781 msg_Err(vd
, "Failed to create the SPU pixel shader. (hr=0x%lX)", hr
);
1782 return VLC_EGENERIC
;
1786 if (AllocQuad( vd
, fmt
, &sys
->picQuad
, &sys
->picQuadConfig
, pPicQuadShader
,
1787 true, vd
->fmt
.projection_mode
) != VLC_SUCCESS
) {
1788 ID3D11PixelShader_Release(pPicQuadShader
);
1789 msg_Err(vd
, "Could not Create the main quad picture. (hr=0x%lX)", hr
);
1790 return VLC_EGENERIC
;
1792 ID3D11PixelShader_Release(pPicQuadShader
);
1794 video_format_t core_source
;
1795 CropStagingFormat( vd
, &core_source
);
1796 UpdatePicQuadPosition(vd
);
1797 UncropStagingFormat( vd
, &core_source
);
1799 D3D11_SAMPLER_DESC sampDesc
;
1800 memset(&sampDesc
, 0, sizeof(sampDesc
));
1801 sampDesc
.Filter
= D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT
;
1802 sampDesc
.AddressU
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1803 sampDesc
.AddressV
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1804 sampDesc
.AddressW
= D3D11_TEXTURE_ADDRESS_CLAMP
;
1805 sampDesc
.ComparisonFunc
= D3D11_COMPARISON_ALWAYS
;
1806 sampDesc
.MinLOD
= 0;
1807 sampDesc
.MaxLOD
= D3D11_FLOAT32_MAX
;
1809 ID3D11SamplerState
*d3dsampState
;
1810 hr
= ID3D11Device_CreateSamplerState(sys
->d3ddevice
, &sampDesc
, &d3dsampState
);
1813 msg_Err(vd
, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr
);
1814 return VLC_EGENERIC
;
1816 ID3D11DeviceContext_PSSetSamplers(sys
->d3dcontext
, 0, 1, &d3dsampState
);
1817 ID3D11SamplerState_Release(d3dsampState
);
1819 if (Direct3D11CreatePool(vd
, fmt
))
1821 msg_Err(vd
, "Direct3D picture pool initialization failed");
1822 return VLC_EGENERIC
;
1825 msg_Dbg(vd
, "Direct3D11 resources created");
1829 static int Direct3D11CreatePool(vout_display_t
*vd
, video_format_t
*fmt
)
1831 vout_display_sys_t
*sys
= vd
->sys
;
1833 if ( is_d3d11_opaque(fmt
->i_chroma
) )
1834 /* a D3D11VA pool will be created when needed */
1837 picture_sys_pool_t
*picsys
= calloc(1, sizeof(*picsys
));
1838 if (unlikely(picsys
== NULL
)) {
1842 if ( sys
->stagingQuad
.pTexture
!= NULL
)
1843 picsys
->texture
= sys
->stagingQuad
.pTexture
;
1845 picsys
->texture
= sys
->picQuad
.pTexture
;
1848 picture_resource_t resource
= {
1849 .p_sys
= (picture_sys_t
*) picsys
,
1850 .pf_destroy
= DestroyDisplayPicture
,
1853 picture_t
*picture
= picture_NewFromResource(fmt
, &resource
);
1858 ID3D11Texture2D_AddRef(picsys
->texture
);
1860 picture_pool_configuration_t pool_cfg
;
1861 memset(&pool_cfg
, 0, sizeof(pool_cfg
));
1862 pool_cfg
.picture_count
= 1;
1863 pool_cfg
.picture
= &picture
;
1864 pool_cfg
.lock
= Direct3D11MapTexture
;
1865 //pool_cfg.unlock = Direct3D11UnmapTexture;
1867 sys
->pool
= picture_pool_NewExtended(&pool_cfg
);
1869 picture_Release(picture
);
1876 static void Direct3D11DestroyPool(vout_display_t
*vd
)
1878 vout_display_sys_t
*sys
= vd
->sys
;
1881 picture_pool_Release(sys
->pool
);
1885 static void SetupQuadFlat(d3d_vertex_t
*dst_data
, WORD
*triangle_pos
)
1890 float bottom
= -1.0f
;
1893 dst_data
[0].position
.x
= left
;
1894 dst_data
[0].position
.y
= bottom
;
1895 dst_data
[0].position
.z
= 0.0f
;
1896 dst_data
[0].texture
.x
= 0.0f
;
1897 dst_data
[0].texture
.y
= 1.0f
;
1900 dst_data
[1].position
.x
= right
;
1901 dst_data
[1].position
.y
= bottom
;
1902 dst_data
[1].position
.z
= 0.0f
;
1903 dst_data
[1].texture
.x
= 1.0f
;
1904 dst_data
[1].texture
.y
= 1.0f
;
1907 dst_data
[2].position
.x
= right
;
1908 dst_data
[2].position
.y
= top
;
1909 dst_data
[2].position
.z
= 0.0f
;
1910 dst_data
[2].texture
.x
= 1.0f
;
1911 dst_data
[2].texture
.y
= 0.0f
;
1914 dst_data
[3].position
.x
= left
;
1915 dst_data
[3].position
.y
= top
;
1916 dst_data
[3].position
.z
= 0.0f
;
1917 dst_data
[3].texture
.x
= 0.0f
;
1918 dst_data
[3].texture
.y
= 0.0f
;
1920 triangle_pos
[0] = 3;
1921 triangle_pos
[1] = 1;
1922 triangle_pos
[2] = 0;
1924 triangle_pos
[3] = 2;
1925 triangle_pos
[4] = 1;
1926 triangle_pos
[5] = 3;
1929 #define SPHERE_SLICES 128
1930 #define nbLatBands SPHERE_SLICES
1931 #define nbLonBands SPHERE_SLICES
1933 static void SetupQuadSphere(d3d_vertex_t
*dst_data
, WORD
*triangle_pos
)
1935 for (unsigned lat
= 0; lat
<= nbLatBands
; lat
++) {
1936 float theta
= lat
* (float) M_PI
/ nbLatBands
;
1937 float sinTheta
, cosTheta
;
1939 sincosf(theta
, &sinTheta
, &cosTheta
);
1941 for (unsigned lon
= 0; lon
<= nbLonBands
; lon
++) {
1942 float phi
= lon
* 2 * (float) M_PI
/ nbLonBands
;
1943 float sinPhi
, cosPhi
;
1945 sincosf(phi
, &sinPhi
, &cosPhi
);
1947 float x
= cosPhi
* sinTheta
;
1949 float z
= sinPhi
* sinTheta
;
1951 unsigned off1
= lat
* (nbLonBands
+ 1) + lon
;
1952 dst_data
[off1
].position
.x
= SPHERE_RADIUS
* x
;
1953 dst_data
[off1
].position
.y
= SPHERE_RADIUS
* y
;
1954 dst_data
[off1
].position
.z
= SPHERE_RADIUS
* z
;
1956 dst_data
[off1
].texture
.x
= lon
/ (float) nbLonBands
; // 0(left) to 1(right)
1957 dst_data
[off1
].texture
.y
= lat
/ (float) nbLatBands
; // 0(top) to 1 (bottom)
1961 for (unsigned lat
= 0; lat
< nbLatBands
; lat
++) {
1962 for (unsigned lon
= 0; lon
< nbLonBands
; lon
++) {
1963 unsigned first
= (lat
* (nbLonBands
+ 1)) + lon
;
1964 unsigned second
= first
+ nbLonBands
+ 1;
1966 unsigned off
= (lat
* nbLatBands
+ lon
) * 3 * 2;
1968 triangle_pos
[off
] = first
;
1969 triangle_pos
[off
+ 1] = second
;
1970 triangle_pos
[off
+ 2] = first
+ 1;
1972 triangle_pos
[off
+ 3] = second
;
1973 triangle_pos
[off
+ 4] = second
+ 1;
1974 triangle_pos
[off
+ 5] = first
+ 1;
1979 static bool AllocQuadVertices(vout_display_t
*vd
, d3d_quad_t
*quad
, video_projection_mode_t projection
)
1982 D3D11_MAPPED_SUBRESOURCE mappedResource
;
1983 vout_display_sys_t
*sys
= vd
->sys
;
1985 if (projection
== PROJECTION_MODE_RECTANGULAR
)
1987 quad
->vertexCount
= 4;
1988 quad
->indexCount
= 2 * 3;
1990 else if (projection
== PROJECTION_MODE_EQUIRECTANGULAR
)
1992 quad
->vertexCount
= (SPHERE_SLICES
+1) * (SPHERE_SLICES
+1);
1993 quad
->indexCount
= nbLatBands
* nbLonBands
* 2 * 3;
1998 D3D11_BUFFER_DESC bd
;
1999 memset(&bd
, 0, sizeof(bd
));
2000 bd
.Usage
= D3D11_USAGE_DYNAMIC
;
2001 bd
.ByteWidth
= sizeof(d3d_vertex_t
) * quad
->vertexCount
;
2002 bd
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
2003 bd
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
2005 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &bd
, NULL
, &quad
->pVertexBuffer
);
2007 msg_Err(vd
, "Failed to create vertex buffer. (hr=%lX)", hr
);
2011 /* create the index of the vertices */
2012 D3D11_BUFFER_DESC quadDesc
= {
2013 .Usage
= D3D11_USAGE_DYNAMIC
,
2014 .ByteWidth
= sizeof(WORD
) * quad
->indexCount
,
2015 .BindFlags
= D3D11_BIND_INDEX_BUFFER
,
2016 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
2019 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &quadDesc
, NULL
, &quad
->pIndexBuffer
);
2021 msg_Err(vd
, "Could not create the quad indices. (hr=0x%lX)", hr
);
2025 /* create the vertices */
2026 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2028 msg_Err(vd
, "Failed to lock the vertex buffer (hr=0x%lX)", hr
);
2031 d3d_vertex_t
*dst_data
= mappedResource
.pData
;
2033 /* create the vertex indices */
2034 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2036 msg_Err(vd
, "Failed to lock the index buffer (hr=0x%lX)", hr
);
2037 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
2040 WORD
*triangle_pos
= mappedResource
.pData
;
2042 if ( projection
== PROJECTION_MODE_RECTANGULAR
)
2043 SetupQuadFlat(dst_data
, triangle_pos
);
2045 SetupQuadSphere(dst_data
, triangle_pos
);
2047 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pIndexBuffer
, 0);
2048 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pVertexBuffer
, 0);
2053 static int AllocQuad(vout_display_t
*vd
, const video_format_t
*fmt
, d3d_quad_t
*quad
,
2054 d3d_quad_cfg_t
*cfg
, ID3D11PixelShader
*d3dpixelShader
, bool b_visible
,
2055 video_projection_mode_t projection
)
2057 vout_display_sys_t
*sys
= vd
->sys
;
2058 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2061 /* pixel shader constant buffer */
2062 PS_CONSTANT_BUFFER defaultConstants
= {
2065 static_assert((sizeof(defaultConstants
)%16)==0,"Constant buffers require 16-byte alignment");
2066 D3D11_BUFFER_DESC constantDesc
= {
2067 .Usage
= D3D11_USAGE_DYNAMIC
,
2068 .ByteWidth
= sizeof(defaultConstants
),
2069 .BindFlags
= D3D11_BIND_CONSTANT_BUFFER
,
2070 .CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
,
2072 D3D11_SUBRESOURCE_DATA constantInit
= { .pSysMem
= &defaultConstants
};
2073 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, &constantInit
, &quad
->pPixelShaderConstants
);
2075 msg_Err(vd
, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr
);
2079 /* vertex shader constant buffer */
2080 if ( projection
== PROJECTION_MODE_EQUIRECTANGULAR
)
2082 constantDesc
.ByteWidth
= sizeof(VS_PROJECTION_CONST
);
2083 static_assert((sizeof(VS_PROJECTION_CONST
)%16)==0,"Constant buffers require 16-byte alignment");
2084 hr
= ID3D11Device_CreateBuffer(sys
->d3ddevice
, &constantDesc
, NULL
, &quad
->pVertexShaderConstants
);
2086 msg_Err(vd
, "Could not create the vertex shader constant buffer. (hr=0x%lX)", hr
);
2090 SetQuadVSProjection( vd
, quad
, &vd
->cfg
->viewpoint
);
2093 D3D11_TEXTURE2D_DESC texDesc
;
2094 memset(&texDesc
, 0, sizeof(texDesc
));
2095 texDesc
.Width
= b_visible
? fmt
->i_visible_width
: fmt
->i_width
;
2096 texDesc
.Height
= b_visible
? fmt
->i_visible_height
: fmt
->i_height
;
2097 texDesc
.MipLevels
= texDesc
.ArraySize
= 1;
2098 texDesc
.Format
= cfg
->textureFormat
;
2099 texDesc
.SampleDesc
.Count
= 1;
2100 texDesc
.Usage
= D3D11_USAGE_DYNAMIC
;
2101 texDesc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
2102 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
2103 texDesc
.MiscFlags
= 0;
2105 /* remove half pixels, we don't want green lines */
2106 const vlc_chroma_description_t
*p_chroma_desc
= vlc_fourcc_GetChromaDescription( fmt
->i_chroma
);
2107 for (unsigned plane
= 0; plane
< p_chroma_desc
->plane_count
; ++plane
)
2110 i_extra
= (texDesc
.Width
* p_chroma_desc
->p
[plane
].w
.num
) % p_chroma_desc
->p
[plane
].w
.den
;
2112 texDesc
.Width
-= p_chroma_desc
->p
[plane
].w
.den
/ p_chroma_desc
->p
[plane
].w
.num
- i_extra
;
2113 i_extra
= (texDesc
.Height
* p_chroma_desc
->p
[plane
].h
.num
) % p_chroma_desc
->p
[plane
].h
.den
;
2115 texDesc
.Height
-= p_chroma_desc
->p
[plane
].h
.den
/ p_chroma_desc
->p
[plane
].h
.num
- i_extra
;
2117 if (texDesc
.Format
== DXGI_FORMAT_NV12
|| texDesc
.Format
== DXGI_FORMAT_P010
)
2119 texDesc
.Width
&= ~1;
2120 texDesc
.Height
&= ~1;
2123 hr
= ID3D11Device_CreateTexture2D(sys
->d3ddevice
, &texDesc
, NULL
, &quad
->pTexture
);
2125 msg_Err(vd
, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr
);
2129 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pTexture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2131 msg_Err(vd
, "The texture cannot be mapped. (hr=0x%lX)", hr
);
2134 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pTexture
, 0);
2135 if (mappedResource
.RowPitch
< p_chroma_desc
->pixel_size
* texDesc
.Width
) {
2136 msg_Err( vd
, "The texture row pitch is too small (%d instead of %d)", mappedResource
.RowPitch
,
2137 p_chroma_desc
->pixel_size
* texDesc
.Width
);
2141 /* map texture planes to resource views */
2142 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc
;
2143 memset(&resviewDesc
, 0, sizeof(resviewDesc
));
2144 resviewDesc
.Format
= cfg
->resourceFormatYRGB
;
2145 resviewDesc
.ViewDimension
= D3D11_SRV_DIMENSION_TEXTURE2D
;
2146 resviewDesc
.Texture2D
.MipLevels
= texDesc
.MipLevels
;
2148 hr
= ID3D11Device_CreateShaderResourceView(sys
->d3ddevice
, (ID3D11Resource
*)quad
->pTexture
, &resviewDesc
, &quad
->d3dresViewY
);
2150 msg_Err(vd
, "Could not Create the Y/RGB D3d11 Texture ResourceView. (hr=0x%lX)", hr
);
2154 if( cfg
->resourceFormatUV
)
2156 resviewDesc
.Format
= cfg
->resourceFormatUV
;
2157 hr
= ID3D11Device_CreateShaderResourceView(sys
->d3ddevice
, (ID3D11Resource
*)quad
->pTexture
, &resviewDesc
, &quad
->d3dresViewUV
);
2159 msg_Err(vd
, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr
);
2164 if ( d3dpixelShader
!= NULL
)
2166 if (!AllocQuadVertices(vd
, quad
, projection
))
2169 if (projection
== PROJECTION_MODE_RECTANGULAR
)
2170 quad
->d3dvertexShader
= sys
->flatVSShader
;
2172 quad
->d3dvertexShader
= sys
->projectionVSShader
;
2174 quad
->d3dpixelShader
= d3dpixelShader
;
2175 ID3D11PixelShader_AddRef(quad
->d3dpixelShader
);
2182 return VLC_EGENERIC
;
2185 static void ReleaseQuad(d3d_quad_t
*quad
)
2187 if (quad
->pPixelShaderConstants
)
2189 ID3D11Buffer_Release(quad
->pPixelShaderConstants
);
2190 quad
->pPixelShaderConstants
= NULL
;
2192 if (quad
->pVertexBuffer
)
2194 ID3D11Buffer_Release(quad
->pVertexBuffer
);
2195 quad
->pVertexBuffer
= NULL
;
2197 quad
->d3dvertexShader
= NULL
;
2198 if (quad
->pIndexBuffer
)
2200 ID3D11Buffer_Release(quad
->pIndexBuffer
);
2201 quad
->pIndexBuffer
= NULL
;
2203 if (quad
->pVertexShaderConstants
)
2205 ID3D11Buffer_Release(quad
->pVertexShaderConstants
);
2206 quad
->pVertexShaderConstants
= NULL
;
2210 ID3D11Texture2D_Release(quad
->pTexture
);
2211 quad
->pTexture
= NULL
;
2213 if (quad
->d3dresViewY
)
2215 ID3D11ShaderResourceView_Release(quad
->d3dresViewY
);
2216 quad
->d3dresViewY
= NULL
;
2218 if (quad
->d3dresViewUV
)
2220 ID3D11ShaderResourceView_Release(quad
->d3dresViewUV
);
2221 quad
->d3dresViewUV
= NULL
;
2223 if (quad
->d3dpixelShader
)
2225 ID3D11VertexShader_Release(quad
->d3dpixelShader
);
2226 quad
->d3dpixelShader
= NULL
;
2230 static void Direct3D11DestroyResources(vout_display_t
*vd
)
2232 vout_display_sys_t
*sys
= vd
->sys
;
2234 Direct3D11DestroyPool(vd
);
2236 if ( sys
->stagingQuad
.pTexture
)
2237 ReleaseQuad(&sys
->stagingQuad
);
2238 ReleaseQuad(&sys
->picQuad
);
2239 Direct3D11DeleteRegions(sys
->d3dregion_count
, sys
->d3dregions
);
2240 sys
->d3dregion_count
= 0;
2242 if (sys
->flatVSShader
)
2244 ID3D11VertexShader_Release(sys
->flatVSShader
);
2245 sys
->flatVSShader
= NULL
;
2247 if (sys
->projectionVSShader
)
2249 ID3D11VertexShader_Release(sys
->projectionVSShader
);
2250 sys
->projectionVSShader
= NULL
;
2252 if (sys
->d3drenderTargetView
)
2254 ID3D11RenderTargetView_Release(sys
->d3drenderTargetView
);
2255 sys
->d3drenderTargetView
= NULL
;
2257 if (sys
->d3ddepthStencilView
)
2259 ID3D11DepthStencilView_Release(sys
->d3ddepthStencilView
);
2260 sys
->d3ddepthStencilView
= NULL
;
2262 if (sys
->pSPUPixelShader
)
2264 ID3D11VertexShader_Release(sys
->pSPUPixelShader
);
2265 sys
->pSPUPixelShader
= NULL
;
2267 #if defined(HAVE_ID3D11VIDEODECODER)
2268 if( sys
->context_lock
!= INVALID_HANDLE_VALUE
)
2270 CloseHandle( sys
->context_lock
);
2271 sys
->context_lock
= INVALID_HANDLE_VALUE
;
2275 msg_Dbg(vd
, "Direct3D11 resources destroyed");
2278 static int Direct3D11MapTexture(picture_t
*picture
)
2280 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*) picture
->p_sys
;
2281 vout_display_t
*vd
= p_sys
->vd
;
2282 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2284 hr
= ID3D11DeviceContext_Map(vd
->sys
->d3dcontext
, (ID3D11Resource
*)p_sys
->texture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2287 msg_Dbg( vd
, "failed to map the texture (hr=0x%lX)", hr
);
2288 return VLC_EGENERIC
;
2290 return CommonUpdatePicture(picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
2293 static int Direct3D11UnmapTexture(picture_t
*picture
)
2295 picture_sys_pool_t
*p_sys
= (picture_sys_pool_t
*)picture
->p_sys
;
2296 vout_display_t
*vd
= p_sys
->vd
;
2297 ID3D11DeviceContext_Unmap(vd
->sys
->d3dcontext
, (ID3D11Resource
*)p_sys
->texture
, 0);
2301 static void Direct3D11DeleteRegions(int count
, picture_t
**region
)
2303 for (int i
= 0; i
< count
; ++i
) {
2305 picture_Release(region
[i
]);
2311 static void DestroyPictureQuad(picture_t
*p_picture
)
2313 ReleaseQuad( (d3d_quad_t
*) p_picture
->p_sys
);
2317 static void UpdateQuadOpacity(vout_display_t
*vd
, const d3d_quad_t
*quad
, float opacity
)
2319 vout_display_sys_t
*sys
= vd
->sys
;
2320 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2322 HRESULT hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
, 0, D3D11_MAP_WRITE_NO_OVERWRITE
, 0, &mappedResource
);
2323 if (SUCCEEDED(hr
)) {
2324 FLOAT
*dst_data
= mappedResource
.pData
;
2325 *dst_data
= opacity
;
2326 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)quad
->pPixelShaderConstants
, 0);
2329 msg_Err(vd
, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr
);
2333 static int Direct3D11MapSubpicture(vout_display_t
*vd
, int *subpicture_region_count
,
2334 picture_t
***region
, subpicture_t
*subpicture
)
2336 vout_display_sys_t
*sys
= vd
->sys
;
2337 D3D11_MAPPED_SUBRESOURCE mappedResource
;
2338 D3D11_TEXTURE2D_DESC texDesc
;
2343 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
)
2346 *region
= calloc(count
, sizeof(picture_t
*));
2347 if (unlikely(*region
==NULL
))
2349 *subpicture_region_count
= count
;
2352 for (subpicture_region_t
*r
= subpicture
->p_region
; r
; r
= r
->p_next
, i
++) {
2353 if (!r
->fmt
.i_width
|| !r
->fmt
.i_height
)
2354 continue; // won't render anything, keep the cache for later
2356 for (int j
= 0; j
< sys
->d3dregion_count
; j
++) {
2357 picture_t
*cache
= sys
->d3dregions
[j
];
2358 if (cache
!= NULL
&& ((d3d_quad_t
*) cache
->p_sys
)->pTexture
) {
2359 ID3D11Texture2D_GetDesc( ((d3d_quad_t
*) cache
->p_sys
)->pTexture
, &texDesc
);
2360 if (texDesc
.Format
== sys
->d3dregion_format
&&
2361 texDesc
.Width
== r
->fmt
.i_visible_width
&&
2362 texDesc
.Height
== r
->fmt
.i_visible_height
) {
2363 (*region
)[i
] = cache
;
2364 memset(&sys
->d3dregions
[j
], 0, sizeof(cache
)); // do not reuse this cached value
2370 picture_t
*quad_picture
= (*region
)[i
];
2371 if (quad_picture
== NULL
) {
2372 d3d_quad_t
*d3dquad
= calloc(1, sizeof(*d3dquad
));
2373 if (unlikely(d3dquad
==NULL
)) {
2376 d3d_quad_cfg_t rgbaCfg
= {
2377 .textureFormat
= sys
->d3dregion_format
,
2378 .resourceFormatYRGB
= sys
->d3dregion_format
,
2380 err
= AllocQuad( vd
, &r
->fmt
, d3dquad
, &rgbaCfg
, sys
->pSPUPixelShader
,
2381 false, PROJECTION_MODE_RECTANGULAR
);
2382 if (err
!= VLC_SUCCESS
) {
2383 msg_Err(vd
, "Failed to create %dx%d texture for OSD",
2384 r
->fmt
.i_visible_width
, r
->fmt
.i_visible_height
);
2388 picture_resource_t picres
= {
2389 .p_sys
= (picture_sys_t
*) d3dquad
,
2390 .pf_destroy
= DestroyPictureQuad
,
2392 (*region
)[i
] = picture_NewFromResource(&r
->fmt
, &picres
);
2393 if ((*region
)[i
] == NULL
) {
2394 msg_Err(vd
, "Failed to create %dx%d picture for OSD",
2395 r
->fmt
.i_width
, r
->fmt
.i_height
);
2396 ReleaseQuad(d3dquad
);
2399 quad_picture
= (*region
)[i
];
2402 hr
= ID3D11DeviceContext_Map(sys
->d3dcontext
, (ID3D11Resource
*)((d3d_quad_t
*) quad_picture
->p_sys
)->pTexture
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
2403 if( SUCCEEDED(hr
) ) {
2404 err
= CommonUpdatePicture(quad_picture
, NULL
, mappedResource
.pData
, mappedResource
.RowPitch
);
2405 if (err
!= VLC_SUCCESS
) {
2406 msg_Err(vd
, "Failed to set the buffer on the SPU picture" );
2407 picture_Release(quad_picture
);
2411 picture_CopyPixels(quad_picture
, r
->p_picture
);
2413 ID3D11DeviceContext_Unmap(sys
->d3dcontext
, (ID3D11Resource
*)((d3d_quad_t
*) quad_picture
->p_sys
)->pTexture
, 0);
2415 msg_Err(vd
, "Failed to map the SPU texture (hr=0x%lX)", hr
);
2416 picture_Release(quad_picture
);
2420 d3d_quad_t
*quad
= (d3d_quad_t
*) quad_picture
->p_sys
;
2422 quad
->cropViewport
.Width
= (FLOAT
) r
->fmt
.i_visible_width
* RECTWidth(sys
->rect_dest
) / subpicture
->i_original_picture_width
;
2423 quad
->cropViewport
.Height
= (FLOAT
) r
->fmt
.i_visible_height
* RECTHeight(sys
->rect_dest
) / subpicture
->i_original_picture_height
;
2424 quad
->cropViewport
.MinDepth
= 0.0f
;
2425 quad
->cropViewport
.MaxDepth
= 1.0f
;
2426 quad
->cropViewport
.TopLeftX
= sys
->rect_dest
.left
+ (FLOAT
) r
->i_x
* RECTWidth(sys
->rect_dest
) / subpicture
->i_original_picture_width
;
2427 quad
->cropViewport
.TopLeftY
= sys
->rect_dest
.top
+ (FLOAT
) r
->i_y
* RECTHeight(sys
->rect_dest
) / subpicture
->i_original_picture_height
;
2429 UpdateQuadOpacity(vd
, quad
, r
->i_alpha
/ 255.0f
);