]> git.sesse.net Git - vlc/blob - modules/video_output/msw/direct3d11.c
direct3d11: support more pixel formats
[vlc] / modules / video_output / msw / direct3d11.c
1 /*****************************************************************************
2  * direct3d11.c: Windows Direct3D11 video output module
3  *****************************************************************************
4  * Copyright (C) 2014-2015 VLC authors and VideoLAN
5  *
6  * Authors: Martell Malone <martellmalone@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_plugin.h>
29 #include <vlc_vout_display.h>
30
31 #define COBJMACROS
32 #define INITGUID
33 #include <d3d11.h>
34
35 /* avoided until we can pass ISwapchainPanel without c++/cx mode
36 # include <windows.ui.xaml.media.dxinterop.h> */
37
38 #include "common.h"
39
40 #if !VLC_WINSTORE_APP
41 # define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
42 # define D3D11CreateDevice(args...)             sys->OurD3D11CreateDevice(args)
43 # define D3DCompile(args...)                    sys->OurD3DCompile(args)
44 #else
45 # define IDXGISwapChain_Present(args...)        IDXGISwapChain_Present1(args)
46 # define IDXGIFactory_CreateSwapChain(a,b,c,d)  IDXGIFactory2_CreateSwapChainForComposition(a,b,c,NULL,d)
47 # define DXGI_SWAP_CHAIN_DESC                   DXGI_SWAP_CHAIN_DESC1
48 #endif
49
50 static int  Open(vlc_object_t *);
51 static void Close(vlc_object_t *);
52
53 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
54
55 vlc_module_begin ()
56     set_shortname("Direct3D11")
57     set_description(N_("Direct3D11 video output"))
58     set_help(D3D11_HELP)
59     set_category(CAT_VIDEO)
60     set_subcategory(SUBCAT_VIDEO_VOUT)
61     set_capability("vout display", 240)
62     add_shortcut("direct3d11")
63     set_callbacks(Open, Close)
64 vlc_module_end ()
65
66 typedef struct
67 {
68     const char   *name;
69     DXGI_FORMAT  formatTexture;
70     vlc_fourcc_t fourcc;
71     DXGI_FORMAT  formatY;
72     DXGI_FORMAT  formatUV;
73 } d3d_format_t;
74
75 static const d3d_format_t d3d_formats[] = {
76     { "NV12",     DXGI_FORMAT_NV12,           VLC_CODEC_NV12,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
77 #ifdef BROKEN_PIXEL
78     { "YUY2",     DXGI_FORMAT_YUY2,           VLC_CODEC_I422,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
79     { "AYUV",     DXGI_FORMAT_AYUV,           VLC_CODEC_YUVA,     DXGI_FORMAT_R8G8B8A8_UNORM,     0 },
80     { "Y416",     DXGI_FORMAT_Y416,           VLC_CODEC_I444_16L, DXGI_FORMAT_R16G16B16A16_UINT,  0 },
81 #endif
82 #ifdef UNTESTED
83     { "P010",     DXGI_FORMAT_P010,           VLC_CODEC_I420_10L, DXGI_FORMAT_R16_UNORM,          DXGI_FORMAT_R16_UNORM },
84     { "Y210",     DXGI_FORMAT_Y210,           VLC_CODEC_I422_10L, DXGI_FORMAT_R16G16B16A16_UNORM, 0 },
85     { "Y410",     DXGI_FORMAT_Y410,           VLC_CODEC_I444_10L, DXGI_FORMAT_R10G10B10A2_UNORM,  0 },
86     { "NV11",     DXGI_FORMAT_NV11,           VLC_CODEC_I411,     DXGI_FORMAT_R8_UNORM,           DXGI_FORMAT_R8G8_UNORM },
87 #endif
88     { "R8G8B8X8", DXGI_FORMAT_B8G8R8X8_UNORM, VLC_CODEC_RGB32,    DXGI_FORMAT_B8G8R8X8_UNORM,     0 },
89     { "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA,     DXGI_FORMAT_B8G8R8A8_UNORM,     0 },
90     { "B5G6R5",   DXGI_FORMAT_B5G6R5_UNORM,   VLC_CODEC_RGB16,    DXGI_FORMAT_B5G6R5_UNORM,       0 },
91
92     { NULL, 0, 0, 0, 0}
93 };
94
95 static const vlc_fourcc_t d3d_subpicture_chromas[] = {
96     VLC_CODEC_RGBA,
97     0
98 };
99
100 struct picture_sys_t
101 {
102     ID3D11Texture2D     *texture;
103     ID3D11DeviceContext *context;
104     vout_display_t      *vd;
105 };
106
107 static int  Open(vlc_object_t *);
108 static void Close(vlc_object_t *object);
109
110 static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
111 static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
112
113 static HINSTANCE Direct3D11LoadShaderLibrary(void);
114 static void Direct3D11Destroy(vout_display_t *);
115
116 static int  Direct3D11Open (vout_display_t *, video_format_t *);
117 static void Direct3D11Close(vout_display_t *);
118
119 static int  Direct3D11CreateResources (vout_display_t *, video_format_t *);
120 static void Direct3D11DestroyResources(vout_display_t *);
121
122 static int  Direct3D11MapTexture(picture_t *);
123
124 /* All the #if USE_DXGI contain an alternative method to setup dx11
125    They both need to be benchmarked to see which performs better */
126 #if USE_DXGI
127 /* I have no idea why MS decided dxgi headers do not define this
128    As they do have prototypes for d3d11 functions */
129 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
130 #endif
131
132 /* TODO: Move to a direct3d11_shaders header */
133 static const char* globVertexShaderDefault = "\
134   struct VS_INPUT\
135   {\
136     float4 Position   : POSITION;\
137     float2 Texture    : TEXCOORD0;\
138   };\
139   \
140   struct VS_OUTPUT\
141   {\
142     float4 Position   : SV_POSITION;\
143     float2 Texture    : TEXCOORD0;\
144   };\
145   \
146   VS_OUTPUT VS( VS_INPUT In )\
147   {\
148     VS_OUTPUT Output;\
149     Output.Position = float4(In.Position.xy, 0.0f, 1.0f);\
150     Output.Texture = In.Texture;\
151     return Output;\
152   }\
153 ";
154
155 static const char* globPixelShaderDefault = "\
156   Texture2D shaderTexture;\
157   SamplerState SampleType;\
158   \
159   struct PS_INPUT\
160   {\
161     float4 Position   : SV_POSITION;\
162     float2 Texture    : TEXCOORD0;\
163   };\
164   \
165   float4 PS( PS_INPUT In ) : SV_TARGET\
166   {\
167     return shaderTexture.Sample(SampleType, In.Texture);\
168   }\
169 ";
170
171 static const char* globPixelShaderBiplanarYUV2RGB = "\
172   Texture2D shaderTextureY;\
173   Texture2D shaderTextureUV;\
174   SamplerState SampleType;\
175   \
176   struct PS_INPUT\
177   {\
178     float4 Position   : SV_POSITION;\
179     float2 Texture    : TEXCOORD0;\
180   };\
181   \
182   float4 PS( PS_INPUT In ) : SV_TARGET\
183   {\
184     float3 yuv;\
185     float4 rgba;\
186     yuv.x  = shaderTextureY.Sample(SampleType, In.Texture).x;\
187     yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
188     yuv.x  = 1.164 * (yuv.x-0.0625);\
189     yuv.y  = yuv.y - 0.5;\
190     yuv.z  = yuv.z - 0.5;\
191     rgba.x = saturate(yuv.x + 1.596 * yuv.z);\
192     rgba.y = saturate(yuv.x - 0.813 * yuv.z - 0.391 * yuv.y);\
193     rgba.z = saturate(yuv.x + 2.018 * yuv.y);\
194     rgba.w = 1.0;\
195     return rgba;\
196   }\
197 ";
198
199
200 static int Open(vlc_object_t *object)
201 {
202     vout_display_t *vd = (vout_display_t *)object;
203
204 #if !VLC_WINSTORE_APP
205     HINSTANCE hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
206     if (!hd3d11_dll) {
207         msg_Warn(vd, "cannot load d3d11.dll, aborting");
208         return VLC_EGENERIC;
209     }
210
211     HINSTANCE hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
212     if (!hd3dcompiler_dll) {
213         msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
214         FreeLibrary(hd3d11_dll);
215         return VLC_EGENERIC;
216     }
217
218 # if USE_DXGI
219     HINSTANCE hdxgi_dll = LoadLibrary(TEXT("DXGI.DLL"));
220     if (!hdxgi_dll) {
221         msg_Warn(vd, "cannot load dxgi.dll, aborting");
222         return VLC_EGENERIC;
223     }
224 # endif
225
226 #else
227     IDXGISwapChain1* dxgiswapChain  = var_InheritInteger(vd, "winrt-dxgiswapchain");
228     if (!dxgiswapChain)
229         return VLC_EGENERIC;
230     ID3D11Device* d3ddevice         = var_InheritInteger(vd, "winrt-d3ddevice");
231     if (!d3ddevice)
232         return VLC_EGENERIC;
233     ID3D11DeviceContext* d3dcontext = var_InheritInteger(vd, "winrt-d3dcontext");
234     if (!d3dcontext)
235         return VLC_EGENERIC;
236 #endif
237
238     vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
239     if (!sys)
240         return VLC_ENOMEM;
241
242 #if !VLC_WINSTORE_APP
243     sys->hd3d11_dll       = hd3d11_dll;
244     sys->hd3dcompiler_dll = hd3dcompiler_dll;
245
246     sys->OurD3DCompile = (void *)GetProcAddress(sys->hd3dcompiler_dll, "D3DCompile");
247     if (!sys->OurD3DCompile) {
248         msg_Err(vd, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
249         Direct3D11Destroy(vd);
250         return VLC_EGENERIC;
251     }
252
253 # if USE_DXGI
254     sys->hdxgi_dll = hdxgi_dll;
255
256     /* TODO : enable all dxgi versions from 1.3 -> 1.1 */
257     PFN_CREATE_DXGI_FACTORY OurCreateDXGIFactory =
258         (void *)GetProcAddress(sys->hdxgi_dll, "CreateDXGIFactory");
259     if (!OurCreateDXGIFactory) {
260         msg_Err(vd, "Cannot locate reference to CreateDXGIFactory in dxgi DLL");
261         Direct3D11Destroy(vd);
262         return VLC_EGENERIC;
263     }
264
265     /* TODO : detect the directx version supported and use IID_IDXGIFactory3 or 2 */
266     HRESULT hr = OurCreateDXGIFactory(&IID_IDXGIFactory, (void **)&sys->dxgifactory);
267     if (FAILED(hr)) {
268         msg_Err(vd, "Could not create dxgi factory. (hr=0x%lX)", hr);
269         Direct3D11Destroy(vd);
270         return VLC_EGENERIC;
271     }
272
273     sys->OurD3D11CreateDeviceAndSwapChain =
274         (void *)GetProcAddress(sys->hd3d11_dll, "D3D11CreateDeviceAndSwapChain");
275     if (!sys->OurD3D11CreateDeviceAndSwapChain) {
276         msg_Err(vd, "Cannot locate reference to D3D11CreateDeviceAndSwapChain in d3d11 DLL");
277         Direct3D11Destroy(vd);
278         return VLC_EGENERIC;
279     }
280
281 # else
282     sys->OurD3D11CreateDevice =
283         (void *)GetProcAddress(sys->hd3d11_dll, "D3D11CreateDevice");
284     if (!sys->OurD3D11CreateDevice) {
285         msg_Err(vd, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
286         Direct3D11Destroy(vd);
287         return VLC_EGENERIC;
288     }
289 # endif
290
291 #else
292     sys->dxgiswapChain = dxgiswapChain;
293     sys->d3ddevice     = d3ddevice;
294     sys->d3dcontext    = d3dcontext;
295 #endif
296
297     if (CommonInit(vd))
298         goto error;
299
300     video_format_t fmt;
301     if (Direct3D11Open(vd, &fmt)) {
302         msg_Err(vd, "Direct3D11 could not be opened");
303         goto error;
304     }
305
306     vout_display_info_t info  = vd->info;
307     info.is_slow              = true;
308     info.has_double_click     = true;
309     info.has_hide_mouse       = false;
310     info.has_pictures_invalid = true;
311     info.has_event_thread     = true;
312
313     /* TODO : subtitle support */
314     info.subpicture_chromas   = NULL;
315
316     video_format_Clean(&vd->fmt);
317     video_format_Copy(&vd->fmt, &fmt);
318     vd->info = info;
319
320     vd->pool    = CommonPool;
321     vd->prepare = Prepare;
322     vd->display = Display;
323     vd->control = CommonControl;
324     vd->manage  = CommonManage;
325
326     msg_Dbg(vd, "Direct3D11 Open Succeeded");
327
328     return VLC_SUCCESS;
329 error:
330     Direct3D11Close(vd);
331     CommonClean(vd);
332     Direct3D11Destroy(vd);
333     free(vd->sys);
334     return VLC_EGENERIC;
335 }
336
337 static void Close(vlc_object_t *object)
338 {
339     vout_display_t * vd = (vout_display_t *)object;
340
341     Direct3D11Close(vd);
342     CommonClean(vd);
343     Direct3D11Destroy(vd);
344     free(vd->sys);
345 }
346
347 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
348 {
349     vout_display_sys_t *sys = vd->sys;
350     VLC_UNUSED(subpicture);
351     VLC_UNUSED(picture);
352
353     /* float ClearColor[4] = { 1.0f, 0.125f, 0.3f, 1.0f }; */
354     /* ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext,sys->d3drenderTargetView, ClearColor); */
355     ID3D11DeviceContext_ClearDepthStencilView(sys->d3dcontext,sys->d3ddepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
356
357     /* Render the quad */
358     ID3D11DeviceContext_VSSetShader(sys->d3dcontext, sys->d3dvertexShader, NULL, 0);
359     ID3D11DeviceContext_PSSetShader(sys->d3dcontext, sys->d3dpixelShader, NULL, 0);
360     ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 0, 1, &sys->d3dresViewY);
361
362     if( sys->d3dFormatUV )
363         ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 1, 1, &sys->d3dresViewUV);
364
365     ID3D11DeviceContext_PSSetSamplers(sys->d3dcontext, 0, 1, &sys->d3dsampState);
366     ID3D11DeviceContext_DrawIndexed(sys->d3dcontext, 6, 0, 0);
367 }
368
369 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
370 {
371     vout_display_sys_t *sys = vd->sys;
372
373     IDXGISwapChain_Present(sys->dxgiswapChain, 0, 0);
374
375     picture_Release(picture);
376     if (subpicture)
377         subpicture_Delete(subpicture);
378
379     CommonDisplay(vd);
380 }
381
382 static void Direct3D11Destroy(vout_display_t *vd)
383 {
384
385 #if !VLC_WINSTORE_APP
386
387     vout_display_sys_t *sys = vd->sys;
388
389 # if USE_DXGI
390     if (sys->hdxgi_dll)
391         FreeLibrary(sys->hdxgi_dll);
392 # endif
393
394     if (sys->hd3d11_dll)
395         FreeLibrary(sys->hd3d11_dll);
396     if (sys->hd3dcompiler_dll)
397         FreeLibrary(sys->hd3dcompiler_dll);
398
399     /* TODO : add release of d3d11 objects here */
400
401     sys->OurD3D11CreateDevice = NULL;
402     sys->OurD3D11CreateDeviceAndSwapChain = NULL;
403     sys->OurD3DCompile = NULL;
404     sys->hdxgi_dll = NULL;
405     sys->hd3d11_dll = NULL;
406     sys->hd3dcompiler_dll = NULL;
407 #else
408
409     VLC_UNUSED(vd);
410
411 #endif
412 }
413
414 #if !VLC_WINSTORE_APP
415 static HINSTANCE Direct3D11LoadShaderLibrary(void)
416 {
417     HINSTANCE instance = NULL;
418     /* d3dcompiler_47 is the latest on windows 8.1 */
419     for (int i = 47; i > 41; --i) {
420         TCHAR filename[19];
421         _sntprintf(filename, 19, TEXT("D3DCOMPILER_%d.dll"), i);
422         instance = LoadLibrary(filename);
423         if (instance) break;
424     }
425     return instance;
426 }
427 #endif
428
429
430 static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
431 {
432     vout_display_sys_t *sys = vd->sys;
433     *fmt = vd->source;
434
435 #if !VLC_WINSTORE_APP
436
437     UINT creationFlags = 0;
438     HRESULT hr = S_OK;
439
440     static const D3D_FEATURE_LEVEL featureLevels[] =
441     {
442         D3D_FEATURE_LEVEL_11_1,
443         D3D_FEATURE_LEVEL_11_0,
444         D3D_FEATURE_LEVEL_10_1,
445         D3D_FEATURE_LEVEL_10_0,
446         D3D_FEATURE_LEVEL_9_3,
447         D3D_FEATURE_LEVEL_9_2,
448         D3D_FEATURE_LEVEL_9_1
449     };
450
451 # if !defined(NDEBUG) && defined(_MSC_VER)
452     creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
453 # endif
454
455     DXGI_SWAP_CHAIN_DESC scd;
456     memset(&scd, 0, sizeof(scd));
457     scd.BufferCount = 1;
458     scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
459     scd.SampleDesc.Count = 1;
460     scd.SampleDesc.Quality = 0;
461     scd.BufferDesc.Width = fmt->i_visible_width;
462     scd.BufferDesc.Height = fmt->i_visible_height;
463     scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
464
465 # if VLC_WINSTORE_APP
466     /* TODO : check different values for performance */
467     scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
468     scd.BufferCount = 2;
469     scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
470     scd.Flags = DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER;
471     scd.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
472     scd.Scaling = DXGI_SCALING_NONE;
473 # else
474     scd.Windowed = TRUE;
475     scd.OutputWindow = sys->hvideownd;
476 # endif
477
478 # if USE_DXGI
479
480     /* TODO : list adapters for the user to choose from */
481     hr = IDXGIFactory_EnumAdapters(sys->dxgifactory, 0, &sys->dxgiadapter);
482     if (FAILED(hr)) {
483        msg_Err(vd, "Could not create find factory. (hr=0x%lX)", hr);
484        return VLC_EGENERIC;
485     }
486
487     IDXGIOutput* output;
488     hr = IDXGIAdapter_EnumOutputs(sys->dxgiadapter, 0, &output);
489     if (FAILED(hr)) {
490        msg_Err(vd, "Could not Enumerate DXGI Outputs. (hr=0x%lX)", hr);
491        return VLC_EGENERIC;
492     }
493
494     DXGI_MODE_DESC md;
495     memset(&md, 0, sizeof(md));
496     md.Width  = fmt->i_visible_width;
497     md.Height = fmt->i_visible_height;
498     md.Format = scd.BufferDesc.Format;
499     md.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
500
501     hr = IDXGIOutput_FindClosestMatchingMode(output, &md, &scd.BufferDesc, NULL);
502     if (FAILED(hr)) {
503        msg_Err(vd, "Failed to find a supported video mode. (hr=0x%lX)", hr);
504        return VLC_EGENERIC;
505     }
506
507     /* mode desc doesn't carry over the width and height*/
508     scd.BufferDesc.Width = fmt->i_visible_width;
509     scd.BufferDesc.Height = fmt->i_visible_height;
510
511     hr = D3D11CreateDeviceAndSwapChain(sys->dxgiadapter,
512                     D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags,
513                     featureLevels, ARRAYSIZE(featureLevels),
514                     D3D11_SDK_VERSION, &scd, &sys->dxgiswapChain,
515                     &sys->d3ddevice, &sys->d3dfeaturelevel, &sys->d3dcontext);
516     if (FAILED(hr)) {
517        msg_Err(vd, "Could not Create the D3D11 device and SwapChain. (hr=0x%lX)", hr);
518        return VLC_EGENERIC;
519     }
520
521 # else
522
523     static const D3D_DRIVER_TYPE driverAttempts[] = {
524         D3D_DRIVER_TYPE_HARDWARE,
525         D3D_DRIVER_TYPE_WARP,
526         D3D_DRIVER_TYPE_REFERENCE,
527     };
528
529     for (UINT driver = 0; driver < ARRAYSIZE(driverAttempts); driver++) {
530         hr = D3D11CreateDevice(NULL, driverAttempts[driver], NULL, creationFlags,
531                     featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION,
532                     &sys->d3ddevice, &sys->d3dfeaturelevel, &sys->d3dcontext);
533         if (SUCCEEDED(hr)) break;
534     }
535
536     if (FAILED(hr)) {
537        msg_Err(vd, "Could not Create the D3D11 device. (hr=0x%lX)", hr);
538        return VLC_EGENERIC;
539     }
540
541     IDXGIDevice *pDXGIDevice = NULL;
542     hr = ID3D11Device_QueryInterface(sys->d3ddevice, &IID_IDXGIDevice, (void **)&pDXGIDevice);
543     if (FAILED(hr)) {
544        msg_Err(vd, "Could not Query DXGI Interface. (hr=0x%lX)", hr);
545        return VLC_EGENERIC;
546     }
547
548     hr = IDXGIDevice_GetAdapter(pDXGIDevice, &sys->dxgiadapter);
549     if (FAILED(hr)) {
550        msg_Err(vd, "Could not get the DXGI Adapter. (hr=0x%lX)", hr);
551        return VLC_EGENERIC;
552     }
553
554     hr = IDXGIAdapter_GetParent(sys->dxgiadapter, &IID_IDXGIFactory, (void **)&sys->dxgifactory);
555     if (FAILED(hr)) {
556        msg_Err(vd, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
557        return VLC_EGENERIC;
558     }
559
560     hr = IDXGIFactory_CreateSwapChain(sys->dxgifactory, (IUnknown *)sys->d3ddevice, &scd, &sys->dxgiswapChain);
561
562     if (FAILED(hr)) {
563        msg_Err(vd, "Could not create the SwapChain. (hr=0x%lX)", hr);
564        return VLC_EGENERIC;
565     }
566
567 #  if VLC_WINSTORE_APP /* avoided until we can pass ISwapchainPanel without c++/cx mode */
568     /* TODO: figure out how to get "ISwapChainPanel ^panel" into brokenpanel in gcc */
569     ISwapChainPanel *brokenpanel;
570     ISwapChainPanelNative *panelNative;
571     hr = ISwapChainPanelNative_QueryInterface(brokenpanel, &IID_ISwapChainPanelNative, (void **)&pDXGIDevice);
572     if (FAILED(hr)) {
573        msg_Err(vd, "Could not get the Native Panel. (hr=0x%lX)", hr);
574        return VLC_EGENERIC;
575     }
576
577     hr = ISwapChainPanelNative_SetSwapChain(panelNative, sys->dxgiswapChain);
578     if (FAILED(hr)) {
579        msg_Err(vd, "Could not link the SwapChain with the Native Panel. (hr=0x%lX)", hr);
580        return VLC_EGENERIC;
581     }
582
583 #  endif
584 # endif
585 #endif
586
587     for (unsigned i = 0; d3d_formats[i].name != 0; i++)
588     {
589         UINT i_formatSupport;
590         if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
591                                                        d3d_formats[i].formatTexture,
592                                                        &i_formatSupport)) &&
593                 ( i_formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D ))
594         {
595             msg_Dbg(vd, "Using pixel format %s", d3d_formats[i].name );
596             sys->d3dFormatTex = d3d_formats[i].formatTexture;
597             sys->vlcFormat    = d3d_formats[i].fourcc;
598             sys->d3dFormatY   = d3d_formats[i].formatY;
599             sys->d3dFormatUV  = d3d_formats[i].formatUV;
600             break;
601         }
602     }
603     if ( !sys->vlcFormat ) {
604        msg_Err(vd, "Could not get a suitable texture pixel format");
605        return VLC_EGENERIC;
606     }
607
608     UpdateRects(vd, NULL, NULL, true);
609
610     if (Direct3D11CreateResources(vd, fmt)) {
611         msg_Err(vd, "Failed to allocate resources");
612         Direct3D11DestroyResources(vd);
613         return VLC_EGENERIC;
614     }
615
616     EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
617
618     msg_Dbg(vd, "Direct3D11 device adapter successfully initialized");
619     return VLC_SUCCESS;
620 }
621
622 static void Direct3D11Close(vout_display_t *vd)
623 {
624     vout_display_sys_t *sys = vd->sys;
625
626     Direct3D11DestroyResources(vd);
627     if ( sys->d3dcontext )
628         ID3D11DeviceContext_Release(sys->d3dcontext);
629     if ( sys->d3ddevice )
630         ID3D11Device_Release(sys->d3ddevice);
631     msg_Dbg(vd, "Direct3D11 device adapter closed");
632 }
633
634 /* TODO : handle errors better
635    TODO : seperate out into smaller functions like createshaders */
636 static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
637 {
638     vout_display_sys_t *sys = vd->sys;
639     ID3D11Texture2D* pBackBuffer = NULL;
640     ID3D11Texture2D* pDepthStencil= NULL;
641     HRESULT hr;
642
643     fmt->i_chroma = sys->vlcFormat;
644
645     hr = IDXGISwapChain_GetBuffer(sys->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *)&pBackBuffer);
646     if (FAILED(hr)) {
647        msg_Err(vd, "Could not get the backbuffer from the Swapchain. (hr=0x%lX)", hr);
648        return VLC_EGENERIC;
649     }
650
651     hr = ID3D11Device_CreateRenderTargetView(sys->d3ddevice, (ID3D11Resource *)pBackBuffer, NULL, &sys->d3drenderTargetView);
652
653     ID3D11Texture2D_Release(pBackBuffer);
654
655     if (FAILED(hr)) {
656        msg_Err(vd, "Could not create the render view target. (hr=0x%lX)", hr);
657        return VLC_EGENERIC;
658     }
659
660     D3D11_TEXTURE2D_DESC deptTexDesc;
661     memset(&deptTexDesc, 0,sizeof(deptTexDesc));
662     deptTexDesc.ArraySize = 1;
663     deptTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
664     deptTexDesc.CPUAccessFlags = 0;
665     deptTexDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
666     deptTexDesc.Width = fmt->i_visible_width;
667     deptTexDesc.Height = fmt->i_visible_height;
668     deptTexDesc.MipLevels = 1;
669     deptTexDesc.MiscFlags = 0;
670     deptTexDesc.SampleDesc.Count = 1;
671     deptTexDesc.SampleDesc.Quality = 0;
672     deptTexDesc.Usage = D3D11_USAGE_DEFAULT;
673
674     hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &deptTexDesc, NULL, &pDepthStencil);
675
676     if (FAILED(hr)) {
677        msg_Err(vd, "Could not create the depth stencil texture. (hr=0x%lX)", hr);
678        return VLC_EGENERIC;
679     }
680
681     D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc;
682     memset(&depthViewDesc, 0, sizeof(depthViewDesc));
683
684     depthViewDesc.Format = deptTexDesc.Format;
685     depthViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
686     depthViewDesc.Texture2D.MipSlice = 0;
687
688     hr = ID3D11Device_CreateDepthStencilView(sys->d3ddevice, (ID3D11Resource *)pDepthStencil, &depthViewDesc, &sys->d3ddepthStencilView);
689
690     ID3D11Texture2D_Release(pDepthStencil);
691
692     if (FAILED(hr)) {
693        msg_Err(vd, "Could not create the depth stencil view. (hr=0x%lX)", hr);
694        return VLC_EGENERIC;
695     }
696
697     ID3D11DeviceContext_OMSetRenderTargets(sys->d3dcontext, 1, &sys->d3drenderTargetView, sys->d3ddepthStencilView);
698
699     D3D11_VIEWPORT vp;
700     vp.Width = (FLOAT)fmt->i_visible_width;
701     vp.Height = (FLOAT)fmt->i_visible_height;
702     vp.MinDepth = 0.0f;
703     vp.MaxDepth = 1.0f;
704     vp.TopLeftX = 0;
705     vp.TopLeftY = 0;
706
707     ID3D11DeviceContext_RSSetViewports(sys->d3dcontext, 1, &vp);
708
709     ID3DBlob* pVSBlob = NULL;
710
711     /* TODO : Match the version to the D3D_FEATURE_LEVEL */
712     hr = D3DCompile(globVertexShaderDefault, strlen(globVertexShaderDefault),
713                     NULL, NULL, NULL, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob, NULL);
714
715     if( FAILED(hr)) {
716       msg_Err(vd, "The Vertex Shader is invalid.");
717       return VLC_EGENERIC;
718     }
719
720     hr = ID3D11Device_CreateVertexShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
721                                         ID3D10Blob_GetBufferSize(pVSBlob), NULL, &sys->d3dvertexShader);
722
723     if(FAILED(hr)) {
724       ID3D11Device_Release(pVSBlob);
725       msg_Err(vd, "Failed to create the vertex shader.");
726       return VLC_EGENERIC;
727     }
728
729     D3D11_INPUT_ELEMENT_DESC layout[] = {
730     { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0},
731     { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
732     };
733
734     ID3D11InputLayout* pVertexLayout = NULL;
735     hr = ID3D11Device_CreateInputLayout(sys->d3ddevice, layout, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
736                                         ID3D10Blob_GetBufferSize(pVSBlob), &pVertexLayout);
737
738     ID3D10Blob_Release(pVSBlob);
739
740     if(FAILED(hr)) {
741       msg_Err(vd, "Failed to create the vertex input layout");
742       return VLC_EGENERIC;
743     }
744
745     ID3D11DeviceContext_IASetInputLayout(sys->d3dcontext, pVertexLayout);
746
747     ID3DBlob* pPSBlob = NULL;
748
749     /* TODO : Match the version to the D3D_FEATURE_LEVEL */
750     if( sys->d3dFormatUV )
751         hr = D3DCompile(globPixelShaderBiplanarYUV2RGB, strlen(globPixelShaderBiplanarYUV2RGB),
752                         NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
753     else
754         hr = D3DCompile(globPixelShaderDefault, strlen(globPixelShaderDefault),
755                         NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
756
757
758     if( FAILED(hr)) {
759       msg_Err(vd, "The Pixel Shader is invalid.");
760       return VLC_EGENERIC;
761     }
762
763     hr = ID3D11Device_CreatePixelShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
764                                         ID3D10Blob_GetBufferSize(pPSBlob), NULL, &sys->d3dpixelShader);
765
766     ID3D10Blob_Release(pPSBlob);
767
768     if(FAILED(hr)) {
769       msg_Err(vd, "Failed to create the pixel shader.");
770       return VLC_EGENERIC;
771     }
772
773     float vertices[] = {
774     -1.0f, -1.0f, -1.0f, 0.0f, 1.0f,
775      1.0f, -1.0f, -1.0f, 1.0f, 1.0f,
776      1.0f,  1.0f, -1.0f, 1.0f, 0.0f,
777     -1.0f,  1.0f, -1.0f, 0.0f, 0.0f,
778     };
779
780     D3D11_BUFFER_DESC bd;
781     memset(&bd, 0, sizeof(bd));
782     bd.Usage = D3D11_USAGE_DEFAULT;
783     bd.ByteWidth = sizeof(float) * 5 * 4;
784     bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
785     bd.CPUAccessFlags = 0;
786
787     D3D11_SUBRESOURCE_DATA InitData;
788     memset(&InitData, 0, sizeof(InitData));
789     InitData.pSysMem = vertices;
790
791     ID3D11Buffer* pVertexBuffer = NULL;
792     hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &bd, &InitData, &pVertexBuffer);
793
794     if(FAILED(hr)) {
795       msg_Err(vd, "Failed to create vertex buffer.");
796       return VLC_EGENERIC;
797     }
798
799     UINT stride = sizeof(float) * 5;
800     UINT offset = 0;
801     ID3D11DeviceContext_IASetVertexBuffers(sys->d3dcontext, 0, 1, &pVertexBuffer, &stride, &offset);
802
803     ID3D11Buffer_Release(pVertexBuffer);
804
805     WORD indices[] = {
806       3, 1, 0,
807       2, 1, 3,
808     };
809
810     bd.Usage = D3D11_USAGE_DEFAULT;
811     bd.ByteWidth = sizeof(WORD)*6;
812     bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
813     bd.CPUAccessFlags = 0;
814     InitData.pSysMem = indices;
815
816     ID3D11Buffer* pIndexBuffer = NULL;
817     hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &bd, &InitData, &pIndexBuffer);
818     if(FAILED(hr)) {
819       msg_Err(vd, "Failed to create index buffer.");
820       return VLC_EGENERIC;
821     }
822
823     ID3D11DeviceContext_IASetIndexBuffer(sys->d3dcontext, pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
824
825     ID3D11Buffer_Release(pVertexBuffer);
826
827     ID3D11DeviceContext_IASetPrimitiveTopology(sys->d3dcontext, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
828
829     D3D11_TEXTURE2D_DESC texDesc;
830     memset(&texDesc, 0, sizeof(texDesc));
831     texDesc.Width = fmt->i_visible_width;
832     texDesc.Height = fmt->i_visible_height;
833     texDesc.MipLevels = texDesc.ArraySize = 1;
834     texDesc.Format = sys->d3dFormatTex;
835     texDesc.SampleDesc.Count = 1;
836     texDesc.Usage = D3D11_USAGE_DYNAMIC;
837     texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
838     texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
839     texDesc.MiscFlags = 0;
840
841     hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &texDesc, NULL, &sys->d3dtexture);
842     if (FAILED(hr)) {
843         msg_Err(vd, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr);
844         return VLC_EGENERIC;
845     }
846
847     D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc;
848     memset(&resviewDesc, 0, sizeof(resviewDesc));
849     resviewDesc.Format = sys->d3dFormatY;
850     resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
851     resviewDesc.Texture2D.MipLevels = texDesc.MipLevels;
852
853     hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)sys->d3dtexture, &resviewDesc, &sys->d3dresViewY);
854     if (FAILED(hr)) {
855         if(sys->d3dtexture) ID3D11Texture2D_Release(sys->d3dtexture);
856         msg_Err(vd, "Could not Create the Y D3d11 Texture ResourceView. (hr=0x%lX)", hr);
857         return VLC_EGENERIC;
858     }
859
860     if( sys->d3dFormatUV )
861     {
862         resviewDesc.Format = sys->d3dFormatUV;
863         hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)sys->d3dtexture, &resviewDesc, &sys->d3dresViewUV);
864         if (FAILED(hr)) {
865             if(sys->d3dtexture) ID3D11Texture2D_Release(sys->d3dtexture);
866             msg_Err(vd, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr);
867             return VLC_EGENERIC;
868         }
869     }
870
871     D3D11_SAMPLER_DESC sampDesc;
872     memset(&sampDesc, 0, sizeof(sampDesc));
873     sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
874     sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
875     sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
876     sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
877     sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
878     sampDesc.MinLOD = 0;
879     sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
880
881     hr = ID3D11Device_CreateSamplerState(sys->d3ddevice, &sampDesc, &sys->d3dsampState);
882
883     if (FAILED(hr)) {
884       if(sys->d3dtexture) ID3D11Texture2D_Release(sys->d3dtexture);
885       msg_Err(vd, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr);
886       return VLC_EGENERIC;
887     }
888
889     picture_sys_t *picsys = malloc(sizeof(*picsys));
890     if (unlikely(picsys == NULL)) {
891         if(sys->d3dtexture) ID3D11Texture2D_Release(sys->d3dtexture);
892         return VLC_ENOMEM;
893     }
894
895     picsys->texture  = sys->d3dtexture;
896     picsys->context  = sys->d3dcontext;
897     picsys->vd       = vd;
898
899     picture_resource_t resource = { .p_sys = picsys };
900     for (int i = 0; i < PICTURE_PLANE_MAX; i++)
901         resource.p[i].i_lines = fmt->i_visible_height / (i > 0 ? 2 : 1);
902
903     picture_t *picture = picture_NewFromResource(fmt, &resource);
904     if (!picture) {
905         if(sys->d3dtexture) ID3D11Texture2D_Release(sys->d3dtexture);
906         free(picsys);
907         return VLC_ENOMEM;
908     }
909     sys->picsys = picsys;
910
911     picture_pool_configuration_t pool_cfg;
912     memset(&pool_cfg, 0, sizeof(pool_cfg));
913     pool_cfg.picture_count = 1;
914     pool_cfg.picture       = &picture;
915     pool_cfg.lock          = Direct3D11MapTexture;
916
917     sys->pool = picture_pool_NewExtended(&pool_cfg);
918     if (!sys->pool) {
919         picture_Release(picture);
920         if(sys->d3dtexture) ID3D11Texture2D_Release(sys->d3dtexture);
921         return VLC_ENOMEM;
922     }
923
924     msg_Dbg(vd, "Direct3D11 resources created");
925     return VLC_SUCCESS;
926 }
927
928 static void Direct3D11DestroyResources(vout_display_t *vd)
929 {
930     vout_display_sys_t *sys = vd->sys;
931
932     /* TODO: Destroy Shaders? */
933     if (sys->pool) {
934         picture_sys_t *picsys = sys->picsys;
935         ID3D11Texture2D_Release(picsys->texture);
936         picture_pool_Release(sys->pool);
937     }
938     sys->pool = NULL;
939
940     msg_Dbg(vd, "Direct3D11 resources destroyed");
941 }
942
943 static int Direct3D11MapTexture(picture_t *picture)
944 {
945     D3D11_MAPPED_SUBRESOURCE mappedResource;
946     HRESULT hr;
947     int res;
948     hr = ID3D11DeviceContext_Map(picture->p_sys->context, (ID3D11Resource *)picture->p_sys->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
949     if( FAILED(hr) )
950     {
951         msg_Dbg( picture->p_sys->vd, "failed to map the texture (hr=0x%lX)", hr );
952         return VLC_EGENERIC;
953     }
954     res = CommonUpdatePicture(picture, NULL, mappedResource.pData, mappedResource.RowPitch);
955     ID3D11DeviceContext_Unmap(picture->p_sys->context,(ID3D11Resource *)picture->p_sys->texture, 0);
956     return res;
957 }