core: remove the 360 video viewpoint zoom
[vlc.git] / modules / video_output / win32 / direct3d11.c
blobf720da46adca440133234caee661edef05397e57
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
25 # undef _WIN32_WINNT
26 # define _WIN32_WINNT 0x601
27 #endif
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout_display.h>
37 #include <assert.h>
38 #include <math.h>
40 #define COBJMACROS
41 #define INITGUID
42 #include <d3d11.h>
44 /* avoided until we can pass ISwapchainPanel without c++/cx mode
45 # include <windows.ui.xaml.media.dxinterop.h> */
47 #include "common.h"
49 #include "../../video_chroma/dxgi_fmt.h"
51 #if !VLC_WINSTORE_APP
52 # if USE_DXGI
53 # define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
54 # else
55 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
56 # endif
57 # define D3DCompile(args...) sys->OurD3DCompile(args)
58 #endif
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.")
72 vlc_module_begin ()
73 set_shortname("Direct3D11")
74 set_description(N_("Direct3D11 video output"))
75 set_help(D3D11_HELP)
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)
81 #if VLC_WINSTORE_APP
82 add_integer("winrt-d3dcontext", 0x0, NULL, NULL, true); /* ID3D11DeviceContext* */
83 add_integer("winrt-swapchain", 0x0, NULL, NULL, true); /* IDXGISwapChain1* */
84 #endif
86 set_capability("vout display", 240)
87 add_shortcut("direct3d11")
88 set_callbacks(Open, Close)
89 vlc_module_end ()
91 #ifdef HAVE_ID3D11VIDEODECODER
92 /* VLC_CODEC_D3D11_OPAQUE */
93 struct picture_sys_t
95 ID3D11VideoDecoderOutputView *decoder; /* may be NULL for pictures from the pool */
96 ID3D11Texture2D *texture;
97 ID3D11DeviceContext *context;
98 unsigned slice_index;
100 #endif
102 /* internal picture_t pool */
103 typedef struct
105 ID3D11Texture2D *texture;
106 vout_display_t *vd;
107 } picture_sys_pool_t;
109 /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
110 typedef struct d3d_vertex_t {
111 struct {
112 FLOAT x;
113 FLOAT y;
114 FLOAT z;
115 } position;
116 struct {
117 FLOAT x;
118 FLOAT y;
119 } texture;
120 } d3d_vertex_t;
122 typedef struct {
123 FLOAT Opacity;
124 FLOAT padding[3];
125 } PS_CONSTANT_BUFFER;
127 typedef struct {
128 FLOAT RotX[16];
129 FLOAT RotY[16];
130 FLOAT RotZ[16];
131 FLOAT View[16];
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 */
176 #if USE_DXGI
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);
180 #endif
182 /* TODO: Move to a direct3d11_shaders header */
183 static const char* globVertexShaderFlat = "\
184 struct VS_INPUT\
186 float4 Position : POSITION;\
187 float2 Texture : TEXCOORD0;\
190 struct VS_OUTPUT\
192 float4 Position : SV_POSITION;\
193 float2 Texture : TEXCOORD0;\
196 VS_OUTPUT VS( VS_INPUT In )\
198 return In;\
202 static const char* globVertexShaderProjection = "\
203 cbuffer VS_PROJECTION_CONST : register(b0)\
205 float4x4 RotX;\
206 float4x4 RotY;\
207 float4x4 RotZ;\
208 float4x4 View;\
209 float4x4 Projection;\
211 struct VS_INPUT\
213 float4 Position : POSITION;\
214 float2 Texture : TEXCOORD0;\
217 struct VS_OUTPUT\
219 float4 Position : SV_POSITION;\
220 float2 Texture : TEXCOORD0;\
223 VS_OUTPUT VS( VS_INPUT In )\
225 VS_OUTPUT Output;\
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;\
234 return Output;\
238 static const char* globPixelShaderDefault = "\
239 cbuffer PS_CONSTANT_BUFFER : register(b0)\
241 float Opacity;\
242 float ignoreA;\
243 float ignoreB;\
244 float ignoreC;\
246 Texture2D shaderTexture;\
247 SamplerState SampleType;\
249 struct PS_INPUT\
251 float4 Position : SV_POSITION;\
252 float2 Texture : TEXCOORD0;\
255 float4 PS( PS_INPUT In ) : SV_TARGET\
257 float4 rgba; \
259 rgba = shaderTexture.Sample(SampleType, In.Texture);\
260 rgba.a = rgba.a * Opacity;\
261 return rgba; \
265 static const char *globPixelShaderBiplanarYUV_BT601_2RGB = "\
266 cbuffer PS_CONSTANT_BUFFER : register(b0)\
268 float Opacity;\
269 float ignoreA;\
270 float ignoreB;\
271 float ignoreC;\
273 Texture2D shaderTextureY;\
274 Texture2D shaderTextureUV;\
275 SamplerState SampleType;\
277 struct PS_INPUT\
279 float4 Position : SV_POSITION;\
280 float2 Texture : TEXCOORD0;\
283 float4 PS( PS_INPUT In ) : SV_TARGET\
285 float3 yuv;\
286 float4 rgba;\
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);\
295 rgba.a = Opacity;\
296 return rgba;\
300 static const char *globPixelShaderBiplanarYUV_BT709_2RGB = "\
301 cbuffer PS_CONSTANT_BUFFER : register(b0)\
303 float Opacity;\
304 float ignoreA;\
305 float ignoreB;\
306 float ignoreC;\
308 Texture2D shaderTextureY;\
309 Texture2D shaderTextureUV;\
310 SamplerState SampleType;\
312 struct PS_INPUT\
314 float4 Position : SV_POSITION;\
315 float2 Texture : TEXCOORD0;\
318 float4 PS( PS_INPUT In ) : SV_TARGET\
320 float3 yuv;\
321 float4 rgba;\
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);\
330 rgba.a = Opacity;\
331 return rgba;\
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)\
339 float Opacity;\
340 float ignoreA;\
341 float ignoreB;\
342 float ignoreC;\
344 Texture2D shaderTextureY;\
345 Texture2D shaderTextureUV;\
346 SamplerState SampleType;\
348 struct PS_INPUT\
350 float4 Position : SV_POSITION;\
351 float2 Texture : TEXCOORD0;\
354 float4 PS( PS_INPUT In ) : SV_TARGET\
356 float3 yuv;\
357 float4 rgba;\
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);\
369 rgba.a = Opacity;\
370 return rgba;\
374 static const char *globPixelShaderBiplanarYUYV_BT709_2RGB = "\
375 cbuffer PS_CONSTANT_BUFFER : register(b0)\
377 float Opacity;\
378 float ignoreA;\
379 float ignoreB;\
380 float ignoreC;\
382 Texture2D shaderTextureYUYV;\
383 SamplerState SampleType;\
385 struct PS_INPUT\
387 float4 Position : SV_POSITION;\
388 float2 Texture : TEXCOORD0;\
391 float4 PS( PS_INPUT In ) : SV_TARGET\
393 float3 yuv;\
394 float4 rgba;\
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);\
404 rgba.a = Opacity;\
405 return rgba;\
409 static const char *globPixelShaderBiplanarYUYV_BT601_2RGB = "\
410 cbuffer PS_CONSTANT_BUFFER : register(b0)\
412 float Opacity;\
413 float ignoreA;\
414 float ignoreB;\
415 float ignoreC;\
417 Texture2D shaderTextureYUYV;\
418 SamplerState SampleType;\
420 struct PS_INPUT\
422 float4 Position : SV_POSITION;\
423 float2 Texture : TEXCOORD0;\
426 float4 PS( PS_INPUT In ) : SV_TARGET\
428 float3 yuv;\
429 float4 rgba;\
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);\
439 rgba.a = Opacity;\
440 return rgba;\
444 #if !VLC_WINSTORE_APP
445 static int OpenHwnd(vout_display_t *vd)
447 HINSTANCE hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
448 if (!hd3d11_dll) {
449 msg_Warn(vd, "cannot load d3d11.dll, aborting");
450 return VLC_EGENERIC;
453 HINSTANCE hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
454 if (!hd3dcompiler_dll) {
455 msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
456 Direct3D11Destroy(vd);
457 return VLC_EGENERIC;
460 # if USE_DXGI
461 HINSTANCE hdxgi_dll = LoadLibrary(TEXT("DXGI.DLL"));
462 if (!hdxgi_dll) {
463 msg_Warn(vd, "cannot load dxgi.dll, aborting");
464 Direct3D11Destroy(vd);
465 return VLC_EGENERIC;
467 # endif
469 vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
470 if (!sys)
471 return VLC_ENOMEM;
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);
480 return VLC_EGENERIC;
483 # if USE_DXGI
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);
492 return VLC_EGENERIC;
495 UINT i_factory_flags = 0;
496 #ifndef NDEBUG
497 i_factory_flags |= DXGI_CREATE_FACTORY_DEBUG;
498 #endif
500 /* TODO : detect the directx version supported and use IID_IDXGIFactory3 or 2 */
501 HRESULT hr = OurCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&sys->dxgifactory);
502 if (FAILED(hr)) {
503 msg_Err(vd, "Could not create dxgi factory. (hr=0x%lX)", hr);
504 Direct3D11Destroy(vd);
505 return VLC_EGENERIC;
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);
513 return VLC_EGENERIC;
516 # else
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);
522 return VLC_EGENERIC;
524 # endif
525 return VLC_SUCCESS;
527 #else
528 static int OpenCoreW(vout_display_t *vd)
530 IDXGISwapChain1* dxgiswapChain = var_InheritInteger(vd, "winrt-swapchain");
531 if (!dxgiswapChain)
532 return VLC_EGENERIC;
533 ID3D11DeviceContext* d3dcontext = var_InheritInteger(vd, "winrt-d3dcontext");
534 if (!d3dcontext)
535 return VLC_EGENERIC;
536 ID3D11Device* d3ddevice = NULL;
537 ID3D11DeviceContext_GetDevice(d3dcontext, &d3ddevice);
538 if (!d3ddevice)
539 return VLC_EGENERIC;
541 vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
542 if (!sys)
543 return VLC_ENOMEM;
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);
552 return VLC_SUCCESS;
554 #endif
556 static bool is_d3d11_opaque(vlc_fourcc_t chroma)
558 switch (chroma)
560 case VLC_CODEC_D3D11_OPAQUE:
561 case VLC_CODEC_D3D11_OPAQUE_10B:
562 return true;
563 default:
564 return false;
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);
574 #else
575 int ret = OpenCoreW(vd);
576 #endif
578 if (ret != VLC_SUCCESS)
579 return ret;
581 if (CommonInit(vd))
582 goto error;
584 video_format_t fmt;
585 if (Direct3D11Open(vd, &fmt)) {
586 msg_Err(vd, "Direct3D11 could not be opened");
587 goto error;
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;
600 else
601 info.subpicture_chromas = NULL;
603 video_format_Clean(&vd->fmt);
604 video_format_Copy(&vd->fmt, &fmt);
605 vd->info = info;
607 vd->pool = Pool;
608 vd->prepare = Prepare;
609 vd->display = Display;
610 vd->control = Control;
611 vd->manage = Manage;
613 msg_Dbg(vd, "Direct3D11 Open Succeeded");
615 return VLC_SUCCESS;
617 error:
618 Close(object);
619 return VLC_EGENERIC;
622 static void Close(vlc_object_t *object)
624 vout_display_t * vd = (vout_display_t *)object;
626 Direct3D11Close(vd);
627 CommonClean(vd);
628 Direct3D11Destroy(vd);
629 free(vd->sys);
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");
639 return NULL;
642 #ifdef HAVE_ID3D11VIDEODECODER
643 picture_t** pictures = NULL;
644 unsigned picture_count = 0;
645 HRESULT hr;
647 ID3D10Multithread *pMultithread;
648 hr = ID3D11Device_QueryInterface( vd->sys->d3ddevice, &IID_ID3D10Multithread, (void **)&pMultithread);
649 if (SUCCEEDED(hr)) {
650 ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
651 ID3D10Multithread_Release(pMultithread);
654 pictures = calloc(pool_size, sizeof(*pictures));
655 if (!pictures)
656 goto error;
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 );
674 if (FAILED(hr)) {
675 msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
676 goto error;
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))
682 goto error;
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 = {
690 .p_sys = picsys,
691 .pf_destroy = DestroyDisplayPoolPicture,
694 picture_t *picture = picture_NewFromResource(&vd->fmt, &resource);
695 if (unlikely(picture == NULL)) {
696 free(picsys);
697 msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
698 goto error;
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 );
717 error:
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]);
722 free(pictures);
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 );
731 #endif
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;
740 if (p_sys->texture)
741 ID3D11Texture2D_Release(p_sys->texture);
742 if (p_sys->context)
743 ID3D11DeviceContext_Release(p_sys->context);
745 free(p_sys);
746 free(picture);
748 #endif
750 static void DestroyDisplayPicture(picture_t *picture)
752 picture_sys_pool_t *p_sys = (picture_sys_pool_t*) picture->p_sys;
754 if (p_sys->texture)
755 ID3D11Texture2D_Release(p_sys->texture);
757 free(p_sys);
758 free(picture);
761 static HRESULT UpdateBackBuffer(vout_display_t *vd)
763 vout_display_sys_t *sys = vd->sys;
764 HRESULT hr;
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);
769 #if VLC_WINSTORE_APP
770 UINT dataSize = sizeof(i_width);
771 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, &i_width);
772 if (FAILED(hr)) {
773 msg_Err(vd, "Can't get swapchain width, size %d. (hr=0x%lX)", hr, dataSize);
774 return hr;
776 dataSize = sizeof(i_height);
777 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, &i_height);
778 if (FAILED(hr)) {
779 msg_Err(vd, "Can't get swapchain height, size %d. (hr=0x%lX)", hr, dataSize);
780 return hr;
782 #endif
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);
795 if (FAILED(hr)) {
796 msg_Err(vd, "Failed to resize the backbuffer. (hr=0x%lX)", hr);
797 return hr;
800 hr = IDXGISwapChain_GetBuffer(sys->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *)&pBackBuffer);
801 if (FAILED(hr)) {
802 msg_Err(vd, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr);
803 return hr;
806 hr = ID3D11Device_CreateRenderTargetView(sys->d3ddevice, (ID3D11Resource *)pBackBuffer, NULL, &sys->d3drenderTargetView);
807 ID3D11Texture2D_Release(pBackBuffer);
808 if (FAILED(hr)) {
809 msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
810 return 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);
828 if (FAILED(hr)) {
829 msg_Err(vd, "Could not create the depth stencil texture. (hr=0x%lX)", hr);
830 return 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);
843 if (FAILED(hr)) {
844 msg_Err(vd, "Could not create the depth stencil view. (hr=0x%lX)", hr);
845 return hr;
848 return S_OK;
851 /* rotation around the Z axis */
852 static void getZRotMatrix(float theta, FLOAT matrix[static 16])
854 float st, ct;
856 sincosf(theta, &st, &ct);
858 const FLOAT m[] = {
859 /* x y z w */
860 ct, -st, 0.f, 0.f,
861 st, ct, 0.f, 0.f,
862 0.f, 0.f, 1.f, 0.f,
863 0.f, 0.f, 0.f, 1.f
866 memcpy(matrix, m, sizeof(m));
869 /* rotation around the Y axis */
870 static void getYRotMatrix(float theta, FLOAT matrix[static 16])
872 float st, ct;
874 sincosf(theta, &st, &ct);
876 const FLOAT m[] = {
877 /* x y z w */
878 ct, 0.f, -st, 0.f,
879 0.f, 1.f, 0.f, 0.f,
880 st, 0.f, ct, 0.f,
881 0.f, 0.f, 0.f, 1.f
884 memcpy(matrix, m, sizeof(m));
887 /* rotation around the X axis */
888 static void getXRotMatrix(float phi, FLOAT matrix[static 16])
890 float sp, cp;
892 sincosf(phi, &sp, &cp);
894 const FLOAT m[] = {
895 /* x y z w */
896 1.f, 0.f, 0.f, 0.f,
897 0.f, cp, sp, 0.f,
898 0.f, -sp, cp, 0.f,
899 0.f, 0.f, 0.f, 1.f
902 memcpy(matrix, m, sizeof(m));
905 static void getZoomMatrix(float zoom, FLOAT matrix[static 16]) {
907 const FLOAT m[] = {
908 /* x y z w */
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]) {
921 float zFar = 1000;
922 float zNear = 0.01;
924 float f = 1.f / tanf(fovy / 2.f);
926 const FLOAT m[] = {
927 f / sar, 0.f, 0.f, 0.f,
928 0.f, 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;
938 HRESULT hr;
939 D3D11_MAPPED_SUBRESOURCE mapped;
940 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pVertexShaderConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
941 if (SUCCEEDED(hr)) {
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);
950 #undef RAD
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 )
958 return;
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 )
971 return;
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 );
987 res = VLC_SUCCESS;
991 UncropStagingFormat( vd, &core_source );
992 return res;
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 );
1002 CommonManage(vd);
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 );
1012 #endif
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 );
1024 #endif
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);
1038 D3D11_BOX box;
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; */
1043 box.back = 1;
1044 box.front = 0;
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,
1053 0, 0, 0, 0,
1054 (ID3D11Resource*) sys->stagingQuad.pTexture,
1055 0, &box);
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 );
1064 D3D11_BOX box;
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;
1075 else
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;
1082 box.back = 1;
1083 box.front = 0;
1085 ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
1086 (ID3D11Resource*) sys->picQuad.pTexture,
1087 0, 0, 0, 0,
1088 (ID3D11Resource*) p_sys->texture,
1089 p_sys->slice_index, &box);
1091 #endif
1093 if (subpicture) {
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);
1106 UINT offset = 0;
1108 /* Render the quad */
1109 /* vertex shader */
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);
1117 /* pixel shader */
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);
1150 if (subpicture) {
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 );
1170 #endif
1172 picture_Release(picture);
1173 if (subpicture)
1174 subpicture_Delete(subpicture);
1176 CommonDisplay(vd);
1179 static void Direct3D11Destroy(vout_display_t *vd)
1181 #if !VLC_WINSTORE_APP
1182 vout_display_sys_t *sys = vd->sys;
1184 # if USE_DXGI
1185 if (sys->hdxgi_dll)
1186 FreeLibrary(sys->hdxgi_dll);
1187 # endif
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;
1200 #else
1201 VLC_UNUSED(vd);
1202 #endif
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) {
1211 TCHAR filename[19];
1212 _sntprintf(filename, 19, TEXT("D3DCOMPILER_%d.dll"), i);
1213 instance = LoadLibrary(filename);
1214 if (instance) break;
1216 return instance;
1218 #endif
1221 static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
1223 vout_display_sys_t *sys = vd->sys;
1224 *fmt = vd->source;
1226 #if !VLC_WINSTORE_APP
1228 UINT creationFlags = 0;
1229 HRESULT hr = S_OK;
1231 # if !defined(NDEBUG) && defined(_MSC_VER)
1232 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
1233 # endif
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;
1247 break;
1248 default:
1249 scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; /* TODO: use DXGI_FORMAT_NV12 */
1250 break;
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,
1269 # if USE_DXGI
1270 /* TODO : list adapters for the user to choose from */
1271 hr = IDXGIFactory2_EnumAdapters(sys->dxgifactory, 0, &dxgiadapter);
1272 if (FAILED(hr)) {
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);
1279 if (FAILED(hr)) {
1280 msg_Err(vd, "Could not Enumerate DXGI Outputs. (hr=0x%lX)", hr);
1281 IDXGIAdapter_Release(dxgiadapter);
1282 return VLC_EGENERIC;
1285 DXGI_MODE_DESC md;
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);
1293 if (FAILED(hr)) {
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);
1309 if (FAILED(hr)) {
1310 msg_Err(vd, "Could not Create the D3D11 device and SwapChain. (hr=0x%lX)", hr);
1311 return VLC_EGENERIC;
1314 # else
1316 static const D3D_DRIVER_TYPE driverAttempts[] = {
1317 D3D_DRIVER_TYPE_HARDWARE,
1318 D3D_DRIVER_TYPE_WARP,
1319 #ifndef NDEBUG
1320 D3D_DRIVER_TYPE_REFERENCE,
1321 #endif
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)) {
1330 #ifndef NDEBUG
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);
1334 #endif
1335 break;
1339 if (FAILED(hr)) {
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);
1346 if (FAILED(hr)) {
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);
1353 if (FAILED(hr)) {
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);
1360 if (FAILED(hr)) {
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);
1368 if (FAILED(hr)) {
1369 msg_Err(vd, "Could not create the SwapChain. (hr=0x%lX)", hr);
1370 return VLC_EGENERIC;
1373 # endif
1374 #endif
1376 vlc_fourcc_t i_src_chroma = fmt->i_chroma;
1377 fmt->i_chroma = 0;
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;
1399 break;
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;
1412 break;
1413 case VLC_CODEC_D3D11_OPAQUE_10B:
1414 bits_per_channel = 10;
1415 break;
1416 default:
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;
1421 break;
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;
1442 break;
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;
1466 break;
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;
1492 } else {
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;
1507 else
1508 sys->d3dPxShader = globPixelShaderBiplanarYUV_BT601_2RGB;
1510 else
1511 if (fmt->i_chroma == VLC_CODEC_YUYV)
1513 if( fmt->i_height > 576 )
1514 sys->d3dPxShader = globPixelShaderBiplanarYUYV_BT709_2RGB;
1515 else
1516 sys->d3dPxShader = globPixelShaderBiplanarYUYV_BT601_2RGB;
1518 else
1519 sys->d3dPxShader = globPixelShaderDefault;
1521 if (sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
1522 sys->psz_rgbaPxShader = globPixelShaderDefault;
1523 else
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 );
1543 #endif
1544 if (Direct3D11CreateResources(vd, fmt)) {
1545 #if defined(HAVE_ID3D11VIDEODECODER)
1546 if( sys->context_lock != INVALID_HANDLE_VALUE )
1548 ReleaseMutex( sys->context_lock );
1550 #endif
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 );
1560 #endif
1562 #if !VLC_WINSTORE_APP
1563 EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
1564 #endif
1566 msg_Dbg(vd, "Direct3D11 device adapter successfully initialized");
1567 return VLC_SUCCESS;
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;
1581 if (sys->d3ddevice)
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;
1616 #ifndef NDEBUG
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 );
1618 #endif
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;
1626 HRESULT hr;
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 );
1631 #endif
1633 hr = UpdateBackBuffer(vd);
1634 if (FAILED(hr)) {
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);
1663 if (FAILED(hr)) {
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);
1689 if( FAILED(hr)) {
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);
1697 if(FAILED(hr)) {
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);
1714 if(FAILED(hr)) {
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);
1724 if( FAILED(hr)) {
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);
1732 if(FAILED(hr)) {
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);
1748 if( FAILED(hr)) {
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);
1759 if(FAILED(hr)) {
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);
1768 if( FAILED(hr)) {
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);
1779 if(FAILED(hr)) {
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);
1812 if (FAILED(hr)) {
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");
1826 return VLC_SUCCESS;
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 */
1835 return VLC_SUCCESS;
1837 picture_sys_pool_t *picsys = calloc(1, sizeof(*picsys));
1838 if (unlikely(picsys == NULL)) {
1839 return VLC_ENOMEM;
1842 if ( sys->stagingQuad.pTexture != NULL )
1843 picsys->texture = sys->stagingQuad.pTexture;
1844 else
1845 picsys->texture = sys->picQuad.pTexture;
1846 picsys->vd = vd;
1848 picture_resource_t resource = {
1849 .p_sys = (picture_sys_t*) picsys,
1850 .pf_destroy = DestroyDisplayPicture,
1853 picture_t *picture = picture_NewFromResource(fmt, &resource);
1854 if (!picture) {
1855 free(picsys);
1856 return VLC_ENOMEM;
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);
1868 if (!sys->pool) {
1869 picture_Release(picture);
1870 return VLC_ENOMEM;
1873 return VLC_SUCCESS;
1876 static void Direct3D11DestroyPool(vout_display_t *vd)
1878 vout_display_sys_t *sys = vd->sys;
1880 if (sys->pool)
1881 picture_pool_Release(sys->pool);
1882 sys->pool = NULL;
1885 static void SetupQuadFlat(d3d_vertex_t *dst_data, WORD *triangle_pos)
1887 float right = 1.0f;
1888 float left = -1.0f;
1889 float top = 1.0f;
1890 float bottom = -1.0f;
1892 // bottom left
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;
1899 // bottom right
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;
1906 // top right
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;
1913 // top left
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;
1948 float y = cosTheta;
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)
1981 HRESULT hr;
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;
1995 else
1996 return false;
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);
2006 if(FAILED(hr)) {
2007 msg_Err(vd, "Failed to create vertex buffer. (hr=%lX)", hr);
2008 return false;
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);
2020 if(FAILED(hr)) {
2021 msg_Err(vd, "Could not create the quad indices. (hr=0x%lX)", hr);
2022 return false;
2025 /* create the vertices */
2026 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
2027 if (FAILED(hr)) {
2028 msg_Err(vd, "Failed to lock the vertex buffer (hr=0x%lX)", hr);
2029 return false;
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);
2035 if (FAILED(hr)) {
2036 msg_Err(vd, "Failed to lock the index buffer (hr=0x%lX)", hr);
2037 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
2038 return false;
2040 WORD *triangle_pos = mappedResource.pData;
2042 if ( projection == PROJECTION_MODE_RECTANGULAR )
2043 SetupQuadFlat(dst_data, triangle_pos);
2044 else
2045 SetupQuadSphere(dst_data, triangle_pos);
2047 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pIndexBuffer, 0);
2048 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
2050 return true;
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;
2059 HRESULT hr;
2061 /* pixel shader constant buffer */
2062 PS_CONSTANT_BUFFER defaultConstants = {
2063 .Opacity = 1,
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);
2074 if(FAILED(hr)) {
2075 msg_Err(vd, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr);
2076 goto error;
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);
2085 if(FAILED(hr)) {
2086 msg_Err(vd, "Could not create the vertex shader constant buffer. (hr=0x%lX)", hr);
2087 goto error;
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)
2109 unsigned i_extra;
2110 i_extra = (texDesc.Width * p_chroma_desc->p[plane].w.num) % p_chroma_desc->p[plane].w.den;
2111 if ( i_extra )
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;
2114 if ( i_extra )
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);
2124 if (FAILED(hr)) {
2125 msg_Err(vd, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr);
2126 goto error;
2129 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
2130 if( FAILED(hr) ) {
2131 msg_Err(vd, "The texture cannot be mapped. (hr=0x%lX)", hr);
2132 goto error;
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 );
2138 goto error;
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);
2149 if (FAILED(hr)) {
2150 msg_Err(vd, "Could not Create the Y/RGB D3d11 Texture ResourceView. (hr=0x%lX)", hr);
2151 goto error;
2154 if( cfg->resourceFormatUV )
2156 resviewDesc.Format = cfg->resourceFormatUV;
2157 hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)quad->pTexture, &resviewDesc, &quad->d3dresViewUV);
2158 if (FAILED(hr)) {
2159 msg_Err(vd, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr);
2160 goto error;
2164 if ( d3dpixelShader != NULL )
2166 if (!AllocQuadVertices(vd, quad, projection))
2167 goto error;
2169 if (projection == PROJECTION_MODE_RECTANGULAR)
2170 quad->d3dvertexShader = sys->flatVSShader;
2171 else
2172 quad->d3dvertexShader = sys->projectionVSShader;
2174 quad->d3dpixelShader = d3dpixelShader;
2175 ID3D11PixelShader_AddRef(quad->d3dpixelShader);
2178 return VLC_SUCCESS;
2180 error:
2181 ReleaseQuad(quad);
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;
2208 if (quad->pTexture)
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;
2273 #endif
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;
2283 HRESULT hr;
2284 hr = ID3D11DeviceContext_Map(vd->sys->d3dcontext, (ID3D11Resource *)p_sys->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
2285 if( FAILED(hr) )
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);
2298 return VLC_SUCCESS;
2301 static void Direct3D11DeleteRegions(int count, picture_t **region)
2303 for (int i = 0; i < count; ++i) {
2304 if (region[i]) {
2305 picture_Release(region[i]);
2308 free(region);
2311 static void DestroyPictureQuad(picture_t *p_picture)
2313 ReleaseQuad( (d3d_quad_t *) p_picture->p_sys );
2314 free( p_picture );
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);
2328 else {
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;
2339 HRESULT hr;
2340 int err;
2342 int count = 0;
2343 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
2344 count++;
2346 *region = calloc(count, sizeof(picture_t *));
2347 if (unlikely(*region==NULL))
2348 return VLC_ENOMEM;
2349 *subpicture_region_count = count;
2351 int i = 0;
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
2365 break;
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)) {
2374 continue;
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);
2385 free(d3dquad);
2386 continue;
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);
2397 continue;
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);
2408 continue;
2411 picture_CopyPixels(quad_picture, r->p_picture);
2413 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0);
2414 } else {
2415 msg_Err(vd, "Failed to map the SPU texture (hr=0x%lX)", hr );
2416 picture_Release(quad_picture);
2417 continue;
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 );
2431 return VLC_SUCCESS;