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