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