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