direct3d11: code cleaning
[vlc.git] / modules / video_output / msw / direct3d11.c
bloba995c67adb66acc1b65c532e70e301676844f95a
1 /*****************************************************************************
2 * direct3d11.c: Windows Direct3D11 video output module
3 *****************************************************************************
4 * Copyright (C) 2014-2015 VLC authors and VideoLAN
6 * Authors: Martell Malone <martellmalone@gmail.com>
7 * Steve Lhomme <robux4@gmail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30 #include <vlc_vout_display.h>
32 #define COBJMACROS
33 #define INITGUID
34 #include <d3d11.h>
36 /* avoided until we can pass ISwapchainPanel without c++/cx mode
37 # include <windows.ui.xaml.media.dxinterop.h> */
39 #include "common.h"
41 #if !VLC_WINSTORE_APP
42 # if USE_DXGI
43 # define D3D11CreateDeviceAndSwapChain(args...) sys->OurD3D11CreateDeviceAndSwapChain(args)
44 # else
45 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
46 # endif
47 # define D3DCompile(args...) sys->OurD3DCompile(args)
48 #endif
50 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
51 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
53 static int Open(vlc_object_t *);
54 static void Close(vlc_object_t *);
56 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
57 #define HW_BLENDING_TEXT N_("Use hardware blending support")
58 #define HW_BLENDING_LONGTEXT N_(\
59 "Try to use hardware acceleration for subtitle/OSD blending.")
61 vlc_module_begin ()
62 set_shortname("Direct3D11")
63 set_description(N_("Direct3D11 video output"))
64 set_help(D3D11_HELP)
65 set_category(CAT_VIDEO)
66 set_subcategory(SUBCAT_VIDEO_VOUT)
68 add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT, true)
70 #if VLC_WINSTORE_APP
71 add_integer("winrt-d3ddevice", 0x0, NULL, NULL, true); /* ID3D11Device* */
72 add_integer("winrt-d3dcontext", 0x0, NULL, NULL, true); /* ID3D11DeviceContext* */
73 add_integer("winrt-swapchain", 0x0, NULL, NULL, true); /* IDXGISwapChain1* */
74 #endif
76 set_capability("vout display", 240)
77 add_shortcut("direct3d11")
78 set_callbacks(Open, Close)
79 vlc_module_end ()
81 typedef struct
83 const char *name;
84 DXGI_FORMAT formatTexture;
85 vlc_fourcc_t fourcc;
86 DXGI_FORMAT formatY;
87 DXGI_FORMAT formatUV;
88 } d3d_format_t;
90 static const d3d_format_t d3d_formats[] = {
91 { "I420", DXGI_FORMAT_NV12, VLC_CODEC_I420, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM },
92 { "YV12", DXGI_FORMAT_NV12, VLC_CODEC_YV12, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM },
93 { "NV12", DXGI_FORMAT_NV12, VLC_CODEC_NV12, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM },
94 { "VA_NV12", DXGI_FORMAT_NV12, VLC_CODEC_D3D11_OPAQUE, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM },
95 #ifdef BROKEN_PIXEL
96 { "YUY2", DXGI_FORMAT_YUY2, VLC_CODEC_I422, DXGI_FORMAT_R8G8B8A8_UNORM, 0 },
97 { "AYUV", DXGI_FORMAT_AYUV, VLC_CODEC_YUVA, DXGI_FORMAT_R8G8B8A8_UNORM, 0 },
98 { "Y416", DXGI_FORMAT_Y416, VLC_CODEC_I444_16L, DXGI_FORMAT_R16G16B16A16_UINT, 0 },
99 #endif
100 #ifdef UNTESTED
101 { "P010", DXGI_FORMAT_P010, VLC_CODEC_I420_10L, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM },
102 { "Y210", DXGI_FORMAT_Y210, VLC_CODEC_I422_10L, DXGI_FORMAT_R16G16B16A16_UNORM, 0 },
103 { "Y410", DXGI_FORMAT_Y410, VLC_CODEC_I444_10L, DXGI_FORMAT_R10G10B10A2_UNORM, 0 },
104 { "NV11", DXGI_FORMAT_NV11, VLC_CODEC_I411, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM },
105 #endif
106 { "R8G8B8A8", DXGI_FORMAT_R8G8B8A8_UNORM, VLC_CODEC_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, 0 },
107 { "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM, 0 },
108 { "R8G8B8X8", DXGI_FORMAT_B8G8R8X8_UNORM, VLC_CODEC_RGB32, DXGI_FORMAT_B8G8R8X8_UNORM, 0 },
109 { "B5G6R5", DXGI_FORMAT_B5G6R5_UNORM, VLC_CODEC_RGB16, DXGI_FORMAT_B5G6R5_UNORM, 0 },
111 { NULL, 0, 0, 0, 0}
114 #ifdef HAVE_ID3D11VIDEODECODER
115 /* VLC_CODEC_D3D11_OPAQUE */
116 struct picture_sys_t
118 ID3D11VideoDecoderOutputView *decoder; /* may be NULL for pictures from the pool */
119 ID3D11Texture2D *texture;
120 ID3D11DeviceContext *context;
122 #endif
124 /* internal picture_t pool */
125 typedef struct
127 ID3D11Texture2D *texture;
128 vout_display_t *vd;
129 } picture_sys_pool_t;
131 /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
132 typedef struct d3d_vertex_t {
133 struct {
134 FLOAT x;
135 FLOAT y;
136 FLOAT z;
137 } position;
138 struct {
139 FLOAT x;
140 FLOAT y;
141 } texture;
142 FLOAT opacity;
143 } d3d_vertex_t;
145 #define RECTWidth(r) (int)(r.right - r.left)
146 #define RECTHeight(r) (int)(r.bottom - r.top)
148 static int Open(vlc_object_t *);
149 static void Close(vlc_object_t *object);
151 static picture_pool_t *Pool(vout_display_t *vd, unsigned count);
153 static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
154 static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
156 static HINSTANCE Direct3D11LoadShaderLibrary(void);
157 static void Direct3D11Destroy(vout_display_t *);
159 static int Direct3D11Open (vout_display_t *, video_format_t *);
160 static void Direct3D11Close(vout_display_t *);
162 static int Direct3D11CreateResources (vout_display_t *, video_format_t *);
163 static void Direct3D11DestroyResources(vout_display_t *);
165 static int Direct3D11CreatePool (vout_display_t *, video_format_t *);
166 static void Direct3D11DestroyPool(vout_display_t *);
168 static void DestroyDisplayPicture(picture_t *);
169 static void DestroyDisplayPoolPicture(picture_t *);
170 static int Direct3D11MapTexture(picture_t *);
171 static void Direct3D11DeleteRegions(int, picture_t **);
172 static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
174 static int AllocQuad(vout_display_t *, const video_format_t *, d3d_quad_t *,
175 d3d_quad_cfg_t *, ID3D11PixelShader *);
176 static void ReleaseQuad(d3d_quad_t *);
177 static void UpdatePicQuadPosition(vout_display_t *);
178 static void UpdateQuadPosition(vout_display_t *, const d3d_quad_t *, const RECT *, int w, int h, float o);
180 static void Manage(vout_display_t *vd);
182 /* All the #if USE_DXGI contain an alternative method to setup dx11
183 They both need to be benchmarked to see which performs better */
184 #if USE_DXGI
185 /* I have no idea why MS decided dxgi headers do not define this
186 As they do have prototypes for d3d11 functions */
187 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
188 #endif
190 /* TODO: Move to a direct3d11_shaders header */
191 static const char* globVertexShaderDefault = "\
192 struct VS_INPUT\
194 float4 Position : POSITION;\
195 float2 Texture : TEXCOORD0;\
196 float Opacity : OPACITY;\
199 struct VS_OUTPUT\
201 float4 Position : SV_POSITION;\
202 float2 Texture : TEXCOORD0;\
203 float Opacity : OPACITY;\
206 VS_OUTPUT VS( VS_INPUT In )\
208 VS_OUTPUT Output;\
209 Output.Position = float4(In.Position.xy, 0.0f, 1.0f);\
210 Output.Texture = In.Texture;\
211 Output.Opacity = In.Opacity;\
212 return Output;\
216 static const char* globPixelShaderDefault = "\
217 Texture2D shaderTexture;\
218 SamplerState SampleType;\
220 struct PS_INPUT\
222 float4 Position : SV_POSITION;\
223 float2 Texture : TEXCOORD0;\
224 float Opacity : OPACITY;\
227 float4 PS( PS_INPUT In ) : SV_TARGET\
229 float4 rgba; \
231 rgba = shaderTexture.Sample(SampleType, In.Texture);\
232 rgba.a = rgba.a * In.Opacity;\
233 return rgba; \
237 static const char *globPixelShaderBiplanarI420_BT601_2RGB = "\
238 Texture2D shaderTextureY;\
239 Texture2D shaderTextureUV;\
240 SamplerState SampleType;\
242 struct PS_INPUT\
244 float4 Position : SV_POSITION;\
245 float2 Texture : TEXCOORD0;\
246 float Opacity : OPACITY;\
249 float4 PS( PS_INPUT In ) : SV_TARGET\
251 float Y;\
252 float UCb;\
253 float VCr;\
254 float2 UCbPos;\
255 float2 VCrPos;\
256 float4 rgba;\
258 Y = shaderTextureY.Sample(SampleType, In.Texture).x;\
260 VCrPos = In.Texture / 2;\
261 VCr = shaderTextureUV.Sample(SampleType, VCrPos).x;\
263 UCbPos = In.Texture / 2;\
264 UCbPos.y = UCbPos.y + 0.5;\
265 UCb = shaderTextureUV.Sample(SampleType, UCbPos).x;\
267 Y = 1.164383561643836 * (Y - 0.0625);\
268 UCb = UCb - 0.5;\
269 VCr = VCr - 0.5;\
271 rgba.x = saturate(Y + 1.596026785714286 * VCr);\
272 rgba.y = saturate(Y - 0.812967647237771 * VCr - 0.391762290094914 * UCb);\
273 rgba.z = saturate(Y + 2.017232142857142 * UCb);\
274 rgba.a = In.Opacity;\
275 return rgba;\
279 static const char *globPixelShaderBiplanarI420_BT709_2RGB = "\
280 Texture2D shaderTextureY;\
281 Texture2D shaderTextureUV;\
282 SamplerState SampleType;\
284 struct PS_INPUT\
286 float4 Position : SV_POSITION;\
287 float2 Texture : TEXCOORD0;\
288 float Opacity : OPACITY;\
291 float4 PS( PS_INPUT In ) : SV_TARGET\
293 float Y;\
294 float UCb;\
295 float VCr;\
296 float2 UCbPos;\
297 float2 VCrPos;\
298 float4 rgba;\
300 Y = shaderTextureY.Sample(SampleType, In.Texture).x;\
302 VCrPos = In.Texture / 2;\
303 VCr = shaderTextureUV.Sample(SampleType, VCrPos).x;\
305 UCbPos = In.Texture / 2;\
306 UCbPos.y = UCbPos.y + 0.5;\
307 UCb = shaderTextureUV.Sample(SampleType, UCbPos).x;\
309 Y = 1.164383561643836 * (Y - 0.0625);\
310 UCb = UCb - 0.5;\
311 VCr = VCr - 0.5;\
313 rgba.x = saturate(Y + 1.792741071428571 * VCr);\
314 rgba.y = saturate(Y - 0.532909328559444 * VCr - 0.21324861427373 * UCb);\
315 rgba.z = saturate(Y + 2.112401785714286 * UCb);\
316 rgba.a = In.Opacity;\
317 return rgba;\
321 static const char *globPixelShaderBiplanarYUV_BT601_2RGB = "\
322 Texture2D shaderTextureY;\
323 Texture2D shaderTextureUV;\
324 SamplerState SampleType;\
326 struct PS_INPUT\
328 float4 Position : SV_POSITION;\
329 float2 Texture : TEXCOORD0;\
330 float Opacity : OPACITY;\
333 float4 PS( PS_INPUT In ) : SV_TARGET\
335 float3 yuv;\
336 float4 rgba;\
337 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
338 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
339 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
340 yuv.y = yuv.y - 0.5;\
341 yuv.z = yuv.z - 0.5;\
342 rgba.x = saturate(yuv.x + 1.596026785714286 * yuv.z);\
343 rgba.y = saturate(yuv.x - 0.812967647237771 * yuv.z - 0.391762290094914 * yuv.y);\
344 rgba.z = saturate(yuv.x + 2.017232142857142 * yuv.y);\
345 rgba.a = In.Opacity;\
346 return rgba;\
350 static const char *globPixelShaderBiplanarYUV_BT709_2RGB = "\
351 Texture2D shaderTextureY;\
352 Texture2D shaderTextureUV;\
353 SamplerState SampleType;\
355 struct PS_INPUT\
357 float4 Position : SV_POSITION;\
358 float2 Texture : TEXCOORD0;\
359 float Opacity : OPACITY;\
362 float4 PS( PS_INPUT In ) : SV_TARGET\
364 float3 yuv;\
365 float4 rgba;\
366 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
367 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
368 yuv.x = 1.164383561643836 * (yuv.x-0.0625);\
369 yuv.y = yuv.y - 0.5;\
370 yuv.z = yuv.z - 0.5;\
371 rgba.x = saturate(yuv.x + 1.792741071428571 * yuv.z);\
372 rgba.y = saturate(yuv.x - 0.532909328559444 * yuv.z - 0.21324861427373 * yuv.y);\
373 rgba.z = saturate(yuv.x + 2.112401785714286 * yuv.y);\
374 rgba.a = In.Opacity;\
375 return rgba;\
379 static int Open(vlc_object_t *object)
381 vout_display_t *vd = (vout_display_t *)object;
383 #if !VLC_WINSTORE_APP
384 HINSTANCE hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
385 if (!hd3d11_dll) {
386 msg_Warn(vd, "cannot load d3d11.dll, aborting");
387 return VLC_EGENERIC;
390 HINSTANCE hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
391 if (!hd3dcompiler_dll) {
392 msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
393 FreeLibrary(hd3d11_dll);
394 return VLC_EGENERIC;
397 # if USE_DXGI
398 HINSTANCE hdxgi_dll = LoadLibrary(TEXT("DXGI.DLL"));
399 if (!hdxgi_dll) {
400 msg_Warn(vd, "cannot load dxgi.dll, aborting");
401 return VLC_EGENERIC;
403 # endif
405 #else
406 IDXGISwapChain1* dxgiswapChain = var_InheritInteger(vd, "winrt-swapchain");
407 if (!dxgiswapChain)
408 return VLC_EGENERIC;
409 ID3D11Device* d3ddevice = var_InheritInteger(vd, "winrt-d3ddevice");
410 if (!d3ddevice)
411 return VLC_EGENERIC;
412 ID3D11DeviceContext* d3dcontext = var_InheritInteger(vd, "winrt-d3dcontext");
413 if (!d3dcontext)
414 return VLC_EGENERIC;
415 #endif
417 vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
418 if (!sys)
419 return VLC_ENOMEM;
421 #if !VLC_WINSTORE_APP
422 sys->hd3d11_dll = hd3d11_dll;
423 sys->hd3dcompiler_dll = hd3dcompiler_dll;
425 sys->OurD3DCompile = (void *)GetProcAddress(sys->hd3dcompiler_dll, "D3DCompile");
426 if (!sys->OurD3DCompile) {
427 msg_Err(vd, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
428 Direct3D11Destroy(vd);
429 return VLC_EGENERIC;
432 # if USE_DXGI
433 sys->hdxgi_dll = hdxgi_dll;
435 /* TODO : enable all dxgi versions from 1.3 -> 1.1 */
436 PFN_CREATE_DXGI_FACTORY OurCreateDXGIFactory =
437 (void *)GetProcAddress(sys->hdxgi_dll, "CreateDXGIFactory");
438 if (!OurCreateDXGIFactory) {
439 msg_Err(vd, "Cannot locate reference to CreateDXGIFactory in dxgi DLL");
440 Direct3D11Destroy(vd);
441 return VLC_EGENERIC;
444 /* TODO : detect the directx version supported and use IID_IDXGIFactory3 or 2 */
445 HRESULT hr = OurCreateDXGIFactory(&IID_IDXGIFactory, (void **)&sys->dxgifactory);
446 if (FAILED(hr)) {
447 msg_Err(vd, "Could not create dxgi factory. (hr=0x%lX)", hr);
448 Direct3D11Destroy(vd);
449 return VLC_EGENERIC;
452 sys->OurD3D11CreateDeviceAndSwapChain =
453 (void *)GetProcAddress(sys->hd3d11_dll, "D3D11CreateDeviceAndSwapChain");
454 if (!sys->OurD3D11CreateDeviceAndSwapChain) {
455 msg_Err(vd, "Cannot locate reference to D3D11CreateDeviceAndSwapChain in d3d11 DLL");
456 Direct3D11Destroy(vd);
457 return VLC_EGENERIC;
460 # else
461 sys->OurD3D11CreateDevice =
462 (void *)GetProcAddress(sys->hd3d11_dll, "D3D11CreateDevice");
463 if (!sys->OurD3D11CreateDevice) {
464 msg_Err(vd, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
465 Direct3D11Destroy(vd);
466 return VLC_EGENERIC;
468 # endif
470 #else
471 sys->dxgiswapChain = dxgiswapChain;
472 sys->d3ddevice = d3ddevice;
473 sys->d3dcontext = d3dcontext;
474 IDXGISwapChain_AddRef (sys->dxgiswapChain);
475 ID3D11Device_AddRef (sys->d3ddevice);
476 ID3D11DeviceContext_AddRef(sys->d3dcontext);
477 #endif
479 if (CommonInit(vd))
480 goto error;
482 video_format_t fmt;
483 if (Direct3D11Open(vd, &fmt)) {
484 msg_Err(vd, "Direct3D11 could not be opened");
485 goto error;
488 vout_display_info_t info = vd->info;
489 info.is_slow = fmt.i_chroma != VLC_CODEC_D3D11_OPAQUE;
490 info.has_double_click = true;
491 info.has_hide_mouse = false;
492 info.has_pictures_invalid = true;
493 info.has_event_thread = true;
494 info.has_pictures_invalid = fmt.i_chroma != VLC_CODEC_D3D11_OPAQUE;
496 if (var_InheritBool(vd, "direct3d11-hw-blending") &&
497 sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
498 info.subpicture_chromas = sys->pSubpictureChromas;
499 else
500 info.subpicture_chromas = NULL;
502 video_format_Clean(&vd->fmt);
503 video_format_Copy(&vd->fmt, &fmt);
504 vd->info = info;
506 vd->pool = Pool;
507 vd->prepare = Prepare;
508 vd->display = Display;
509 vd->control = CommonControl;
510 vd->manage = Manage;
512 msg_Dbg(vd, "Direct3D11 Open Succeeded");
514 return VLC_SUCCESS;
515 error:
516 Direct3D11Close(vd);
517 CommonClean(vd);
518 Direct3D11Destroy(vd);
519 free(vd->sys);
520 return VLC_EGENERIC;
523 static void Close(vlc_object_t *object)
525 vout_display_t * vd = (vout_display_t *)object;
527 Direct3D11Close(vd);
528 CommonClean(vd);
529 Direct3D11Destroy(vd);
530 free(vd->sys);
533 static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
535 if ( vd->sys->pool != NULL )
536 return vd->sys->pool;
538 #ifdef HAVE_ID3D11VIDEODECODER
539 picture_t** pictures = NULL;
540 unsigned picture_count = 0;
541 HRESULT hr;
543 ID3D10Multithread *pMultithread;
544 hr = ID3D11Device_QueryInterface( vd->sys->d3ddevice, &IID_ID3D10Multithread, (void **)&pMultithread);
545 if (SUCCEEDED(hr)) {
546 ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
547 ID3D10Multithread_Release(pMultithread);
550 pictures = calloc(pool_size, sizeof(*pictures));
551 if (!pictures)
552 goto error;
554 D3D11_TEXTURE2D_DESC texDesc;
555 ZeroMemory(&texDesc, sizeof(texDesc));
556 texDesc.Width = vd->fmt.i_width;
557 texDesc.Height = vd->fmt.i_height;
558 texDesc.MipLevels = 1;
559 texDesc.Format = vd->sys->picQuadConfig.textureFormat;
560 texDesc.SampleDesc.Count = 1;
561 texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
562 texDesc.ArraySize = 1;
563 texDesc.Usage = D3D11_USAGE_DYNAMIC;
564 texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
565 texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
567 unsigned surface_count;
568 for (surface_count = 0; surface_count < pool_size; surface_count++) {
569 picture_sys_t *picsys = calloc(1, sizeof(*picsys));
570 if (unlikely(picsys == NULL))
571 goto error;
573 hr = ID3D11Device_CreateTexture2D( vd->sys->d3ddevice, &texDesc, NULL, &picsys->texture );
574 if (FAILED(hr)) {
575 msg_Err(vd, "CreateTexture2D %d failed. (hr=0x%0lx)", pool_size, hr);
576 goto error;
579 picsys->context = vd->sys->d3dcontext;
581 picture_resource_t resource = {
582 .p_sys = picsys,
583 .pf_destroy = DestroyDisplayPoolPicture,
586 picture_t *picture = picture_NewFromResource(&vd->fmt, &resource);
587 if (unlikely(picture == NULL)) {
588 free(picsys);
589 goto error;
592 pictures[surface_count] = picture;
593 /* each picture_t holds a ref to the context and release it on Destroy */
594 ID3D11DeviceContext_AddRef(picsys->context);
596 msg_Dbg(vd, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d)",
597 pool_size, vd->fmt.i_width, vd->fmt.i_height);
599 picture_pool_configuration_t pool_cfg;
600 memset(&pool_cfg, 0, sizeof(pool_cfg));
601 pool_cfg.picture_count = pool_size;
602 pool_cfg.picture = pictures;
604 vd->sys->pool = picture_pool_NewExtended( &pool_cfg );
606 error:
607 if (vd->sys->pool ==NULL && pictures) {
608 for (unsigned i=0;i<picture_count; ++i)
609 DestroyDisplayPoolPicture(pictures[i]);
610 free(pictures);
612 #endif
613 return vd->sys->pool;
616 #ifdef HAVE_ID3D11VIDEODECODER
617 static void DestroyDisplayPoolPicture(picture_t *picture)
619 picture_sys_t *p_sys = (picture_sys_t*) picture->p_sys;
621 if (p_sys->texture)
622 ID3D11Texture2D_Release(p_sys->texture);
624 free(p_sys);
625 free(picture);
627 #endif
629 static void DestroyDisplayPicture(picture_t *picture)
631 picture_sys_pool_t *p_sys = (picture_sys_pool_t*) picture->p_sys;
633 if (p_sys->texture)
634 ID3D11Texture2D_Release(p_sys->texture);
636 free(p_sys);
637 free(picture);
640 static HRESULT UpdateBackBuffer(vout_display_t *vd)
642 vout_display_sys_t *sys = vd->sys;
643 HRESULT hr;
644 ID3D11Texture2D* pDepthStencil;
645 ID3D11Texture2D* pBackBuffer;
646 uint32_t i_width = RECTWidth(sys->rect_dest_clipped);
647 uint32_t i_height = RECTHeight(sys->rect_dest_clipped);
648 #if VLC_WINSTORE_APP
649 UINT dataSize = sizeof(i_width);
650 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, &i_width);
651 if (FAILED(hr)) {
652 msg_Err(vd, "Can't get swapchain width, size %d. (hr=0x%lX)", hr, dataSize);
653 return hr;
655 dataSize = sizeof(i_height);
656 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, &i_height);
657 if (FAILED(hr)) {
658 msg_Err(vd, "Can't get swapchain height, size %d. (hr=0x%lX)", hr, dataSize);
659 return hr;
661 #endif
663 if (sys->d3drenderTargetView) {
664 ID3D11RenderTargetView_Release(sys->d3drenderTargetView);
665 sys->d3drenderTargetView = NULL;
667 if (sys->d3ddepthStencilView) {
668 ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
669 sys->d3ddepthStencilView = NULL;
672 hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
673 DXGI_FORMAT_UNKNOWN, 0);
674 if (FAILED(hr)) {
675 msg_Err(vd, "Failed to resize the backbuffer. (hr=0x%lX)", hr);
676 return hr;
679 hr = IDXGISwapChain_GetBuffer(sys->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *)&pBackBuffer);
680 if (FAILED(hr)) {
681 msg_Err(vd, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr);
682 return hr;
685 hr = ID3D11Device_CreateRenderTargetView(sys->d3ddevice, (ID3D11Resource *)pBackBuffer, NULL, &sys->d3drenderTargetView);
686 ID3D11Texture2D_Release(pBackBuffer);
687 if (FAILED(hr)) {
688 msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
689 return hr;
692 D3D11_TEXTURE2D_DESC deptTexDesc;
693 memset(&deptTexDesc, 0,sizeof(deptTexDesc));
694 deptTexDesc.ArraySize = 1;
695 deptTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
696 deptTexDesc.CPUAccessFlags = 0;
697 deptTexDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
698 deptTexDesc.Width = i_width;
699 deptTexDesc.Height = i_height;
700 deptTexDesc.MipLevels = 1;
701 deptTexDesc.MiscFlags = 0;
702 deptTexDesc.SampleDesc.Count = 1;
703 deptTexDesc.SampleDesc.Quality = 0;
704 deptTexDesc.Usage = D3D11_USAGE_DEFAULT;
706 hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &deptTexDesc, NULL, &pDepthStencil);
707 if (FAILED(hr)) {
708 msg_Err(vd, "Could not create the depth stencil texture. (hr=0x%lX)", hr);
709 return hr;
712 D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc;
713 memset(&depthViewDesc, 0, sizeof(depthViewDesc));
715 depthViewDesc.Format = deptTexDesc.Format;
716 depthViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
717 depthViewDesc.Texture2D.MipSlice = 0;
719 hr = ID3D11Device_CreateDepthStencilView(sys->d3ddevice, (ID3D11Resource *)pDepthStencil, &depthViewDesc, &sys->d3ddepthStencilView);
720 ID3D11Texture2D_Release(pDepthStencil);
722 if (FAILED(hr)) {
723 msg_Err(vd, "Could not create the depth stencil view. (hr=0x%lX)", hr);
724 return hr;
727 D3D11_VIEWPORT vp;
728 vp.Width = (FLOAT)i_width;
729 vp.Height = (FLOAT)i_height;
730 vp.MinDepth = 0.0f;
731 vp.MaxDepth = 1.0f;
732 vp.TopLeftX = 0;
733 vp.TopLeftY = 0;
735 ID3D11DeviceContext_RSSetViewports(sys->d3dcontext, 1, &vp);
737 return S_OK;
740 static void Manage(vout_display_t *vd)
742 vout_display_sys_t *sys = vd->sys;
743 RECT size_before = sys->rect_dest_clipped;
745 CommonManage(vd);
747 if (RECTWidth(size_before) != RECTWidth(sys->rect_dest_clipped) ||
748 RECTHeight(size_before) != RECTHeight(sys->rect_dest_clipped))
750 msg_Dbg(vd, "Manage detected size change %dx%d", RECTWidth(sys->rect_dest_clipped),
751 RECTHeight(sys->rect_dest_clipped));
753 UpdateBackBuffer(vd);
755 UpdatePicQuadPosition(vd);
759 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
761 vout_display_sys_t *sys = vd->sys;
763 #ifdef HAVE_ID3D11VIDEODECODER
764 if (picture->format.i_chroma == VLC_CODEC_D3D11_OPAQUE) {
765 D3D11_BOX box;
766 box.left = 0;
767 box.right = picture->format.i_visible_width;
768 box.top = 0;
769 box.bottom = picture->format.i_visible_height;
770 box.back = 1;
771 box.front = 0;
773 picture_sys_t *p_sys = picture->p_sys;
774 ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
775 (ID3D11Resource*) sys->picQuad.pTexture,
776 0, 0, 0, 0,
777 (ID3D11Resource*) p_sys->texture,
778 0, &box);
780 #endif
782 if (subpicture) {
783 int subpicture_region_count = 0;
784 picture_t **subpicture_regions = NULL;
785 Direct3D11MapSubpicture(vd, &subpicture_region_count, &subpicture_regions, subpicture);
786 Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
787 sys->d3dregion_count = subpicture_region_count;
788 sys->d3dregions = subpicture_regions;
792 static void DisplayD3DPicture(vout_display_sys_t *sys, d3d_quad_t *quad)
794 UINT stride = sizeof(d3d_vertex_t);
795 UINT offset = 0;
797 /* Render the quad */
798 ID3D11DeviceContext_PSSetShader(sys->d3dcontext, quad->d3dpixelShader, NULL, 0);
799 ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 0, 1, &quad->d3dresViewY);
801 if( quad->d3dresViewUV )
802 ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 1, 1, &quad->d3dresViewUV);
804 ID3D11DeviceContext_IASetVertexBuffers(sys->d3dcontext, 0, 1, &quad->pVertexBuffer, &stride, &offset);
805 ID3D11DeviceContext_DrawIndexed(sys->d3dcontext, 6, 0, 0);
808 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
810 vout_display_sys_t *sys = vd->sys;
812 FLOAT blackRGBA[4] = {0.0f, 0.0f, 0.0f, 1.0f};
813 ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext, sys->d3drenderTargetView, blackRGBA);
815 /* no ID3D11Device operations should come here */
817 ID3D11DeviceContext_OMSetRenderTargets(sys->d3dcontext, 1, &sys->d3drenderTargetView, sys->d3ddepthStencilView);
819 ID3D11DeviceContext_ClearDepthStencilView(sys->d3dcontext, sys->d3ddepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
821 /* Render the quad */
822 DisplayD3DPicture(sys, &sys->picQuad);
824 if (subpicture) {
825 // draw the additional vertices
826 for (int i = 0; i < sys->d3dregion_count; ++i) {
827 DisplayD3DPicture(sys, (d3d_quad_t *) sys->d3dregions[i]->p_sys);
831 HRESULT hr = IDXGISwapChain_Present(sys->dxgiswapChain, 0, 0);
832 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
834 /* TODO device lost */
837 picture_Release(picture);
838 if (subpicture)
839 subpicture_Delete(subpicture);
841 CommonDisplay(vd);
844 static void Direct3D11Destroy(vout_display_t *vd)
846 #if !VLC_WINSTORE_APP
847 vout_display_sys_t *sys = vd->sys;
849 # if USE_DXGI
850 if (sys->hdxgi_dll)
851 FreeLibrary(sys->hdxgi_dll);
852 # endif
854 if (sys->hd3d11_dll)
855 FreeLibrary(sys->hd3d11_dll);
856 if (sys->hd3dcompiler_dll)
857 FreeLibrary(sys->hd3dcompiler_dll);
859 /* TODO : add release of d3d11 objects here */
861 sys->OurD3D11CreateDevice = NULL;
862 sys->OurD3D11CreateDeviceAndSwapChain = NULL;
863 sys->OurD3DCompile = NULL;
864 sys->hdxgi_dll = NULL;
865 sys->hd3d11_dll = NULL;
866 sys->hd3dcompiler_dll = NULL;
867 #else
868 VLC_UNUSED(vd);
869 #endif
872 #if !VLC_WINSTORE_APP
873 static HINSTANCE Direct3D11LoadShaderLibrary(void)
875 HINSTANCE instance = NULL;
876 /* d3dcompiler_47 is the latest on windows 8.1 */
877 for (int i = 47; i > 41; --i) {
878 TCHAR filename[19];
879 _sntprintf(filename, 19, TEXT("D3DCOMPILER_%d.dll"), i);
880 instance = LoadLibrary(filename);
881 if (instance) break;
883 return instance;
885 #endif
888 static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
890 vout_display_sys_t *sys = vd->sys;
891 *fmt = vd->source;
893 #if !VLC_WINSTORE_APP
895 UINT creationFlags = 0;
896 HRESULT hr = S_OK;
898 # if !defined(NDEBUG) && defined(_MSC_VER)
899 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
900 # endif
902 DXGI_SWAP_CHAIN_DESC scd;
903 memset(&scd, 0, sizeof(scd));
904 scd.BufferCount = 1;
905 scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
906 scd.SampleDesc.Count = 1;
907 scd.SampleDesc.Quality = 0;
908 scd.BufferDesc.Width = fmt->i_visible_width;
909 scd.BufferDesc.Height = fmt->i_visible_height;
910 scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
912 scd.Windowed = TRUE;
913 scd.OutputWindow = sys->hvideownd;
915 IDXGIAdapter *dxgiadapter;
916 # if USE_DXGI
917 static const D3D_FEATURE_LEVEL featureLevels[] =
919 D3D_FEATURE_LEVEL_11_1,
920 D3D_FEATURE_LEVEL_11_0,
921 D3D_FEATURE_LEVEL_10_1,
922 D3D_FEATURE_LEVEL_10_0,
923 D3D_FEATURE_LEVEL_9_3,
924 D3D_FEATURE_LEVEL_9_2,
925 D3D_FEATURE_LEVEL_9_1
928 /* TODO : list adapters for the user to choose from */
929 hr = IDXGIFactory_EnumAdapters(sys->dxgifactory, 0, &dxgiadapter);
930 if (FAILED(hr)) {
931 msg_Err(vd, "Could not create find factory. (hr=0x%lX)", hr);
932 return VLC_EGENERIC;
935 IDXGIOutput* output;
936 hr = IDXGIAdapter_EnumOutputs(dxgiadapter, 0, &output);
937 if (FAILED(hr)) {
938 msg_Err(vd, "Could not Enumerate DXGI Outputs. (hr=0x%lX)", hr);
939 IDXGIAdapter_Release(dxgiadapter);
940 return VLC_EGENERIC;
943 DXGI_MODE_DESC md;
944 memset(&md, 0, sizeof(md));
945 md.Width = fmt->i_visible_width;
946 md.Height = fmt->i_visible_height;
947 md.Format = scd.BufferDesc.Format;
948 md.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
950 hr = IDXGIOutput_FindClosestMatchingMode(output, &md, &scd.BufferDesc, NULL);
951 if (FAILED(hr)) {
952 msg_Err(vd, "Failed to find a supported video mode. (hr=0x%lX)", hr);
953 IDXGIAdapter_Release(dxgiadapter);
954 return VLC_EGENERIC;
957 /* mode desc doesn't carry over the width and height*/
958 scd.BufferDesc.Width = fmt->i_visible_width;
959 scd.BufferDesc.Height = fmt->i_visible_height;
961 hr = D3D11CreateDeviceAndSwapChain(dxgiadapter,
962 D3D_DRIVER_TYPE_UNKNOWN, NULL, creationFlags,
963 featureLevels, ARRAYSIZE(featureLevels),
964 D3D11_SDK_VERSION, &scd, &sys->dxgiswapChain,
965 &sys->d3ddevice, NULL, &sys->d3dcontext);
966 IDXGIAdapter_Release(dxgiadapter);
967 if (FAILED(hr)) {
968 msg_Err(vd, "Could not Create the D3D11 device and SwapChain. (hr=0x%lX)", hr);
969 return VLC_EGENERIC;
972 # else
974 static const D3D_DRIVER_TYPE driverAttempts[] = {
975 D3D_DRIVER_TYPE_HARDWARE,
976 D3D_DRIVER_TYPE_WARP,
977 D3D_DRIVER_TYPE_REFERENCE,
980 for (UINT driver = 0; driver < ARRAYSIZE(driverAttempts); driver++) {
981 hr = D3D11CreateDevice(NULL, driverAttempts[driver], NULL, creationFlags,
982 NULL, 0, D3D11_SDK_VERSION,
983 &sys->d3ddevice, NULL, &sys->d3dcontext);
984 if (SUCCEEDED(hr)) {
985 #ifndef NDEBUG
986 msg_Dbg(vd, "Created the D3D11 device 0x%p ctx 0x%p type %d.", sys->d3ddevice, sys->d3dcontext, driverAttempts[driver]);
987 #endif
988 break;
992 if (FAILED(hr)) {
993 msg_Err(vd, "Could not Create the D3D11 device. (hr=0x%lX)", hr);
994 return VLC_EGENERIC;
997 IDXGIDevice *pDXGIDevice = NULL;
998 hr = ID3D11Device_QueryInterface(sys->d3ddevice, &IID_IDXGIDevice, (void **)&pDXGIDevice);
999 if (FAILED(hr)) {
1000 msg_Err(vd, "Could not Query DXGI Interface. (hr=0x%lX)", hr);
1001 return VLC_EGENERIC;
1004 hr = IDXGIDevice_GetAdapter(pDXGIDevice, &dxgiadapter);
1005 IDXGIAdapter_Release(pDXGIDevice);
1006 if (FAILED(hr)) {
1007 msg_Err(vd, "Could not get the DXGI Adapter. (hr=0x%lX)", hr);
1008 return VLC_EGENERIC;
1011 hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory, (void **)&sys->dxgifactory);
1012 IDXGIAdapter_Release(dxgiadapter);
1013 if (FAILED(hr)) {
1014 msg_Err(vd, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
1015 return VLC_EGENERIC;
1018 hr = IDXGIFactory_CreateSwapChain(sys->dxgifactory, (IUnknown *)sys->d3ddevice, &scd, &sys->dxgiswapChain);
1019 IDXGIFactory_Release(sys->dxgifactory);
1020 if (FAILED(hr)) {
1021 msg_Err(vd, "Could not create the SwapChain. (hr=0x%lX)", hr);
1022 return VLC_EGENERIC;
1025 # endif
1026 #endif
1028 vlc_fourcc_t i_src_chroma = fmt->i_chroma;
1029 fmt->i_chroma = 0;
1031 // look for the request pixel format first
1032 UINT i_quadSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_LOAD;
1033 UINT i_formatSupport;
1034 for (unsigned i = 0; d3d_formats[i].name != 0; i++)
1036 if( i_src_chroma == d3d_formats[i].fourcc)
1038 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1039 d3d_formats[i].formatTexture,
1040 &i_formatSupport)) &&
1041 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
1043 msg_Dbg(vd, "Using pixel format %s", d3d_formats[i].name );
1044 fmt->i_chroma = d3d_formats[i].fourcc;
1045 sys->picQuadConfig.textureFormat = d3d_formats[i].formatTexture;
1046 sys->picQuadConfig.resourceFormatYRGB = d3d_formats[i].formatY;
1047 sys->picQuadConfig.resourceFormatUV = d3d_formats[i].formatUV;
1048 break;
1053 // look for any pixel format that we can handle
1054 if ( !fmt->i_chroma )
1056 for (unsigned i = 0; d3d_formats[i].name != 0; i++)
1058 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1059 d3d_formats[i].formatTexture,
1060 &i_formatSupport)) &&
1061 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
1063 msg_Dbg(vd, "Using pixel format %s", d3d_formats[i].name );
1064 fmt->i_chroma = d3d_formats[i].fourcc;
1065 sys->picQuadConfig.textureFormat = d3d_formats[i].formatTexture;
1066 sys->picQuadConfig.resourceFormatYRGB = d3d_formats[i].formatY;
1067 sys->picQuadConfig.resourceFormatUV = d3d_formats[i].formatUV;
1068 break;
1072 if ( !fmt->i_chroma )
1074 msg_Err(vd, "Could not get a suitable texture pixel format");
1075 return VLC_EGENERIC;
1078 /* check the region pixel format */
1079 i_quadSupportFlags |= D3D11_FORMAT_SUPPORT_BLENDABLE;
1080 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1081 DXGI_FORMAT_R8G8B8A8_UNORM,
1082 &i_formatSupport)) &&
1083 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags) {
1084 sys->d3dregion_format = DXGI_FORMAT_R8G8B8A8_UNORM;
1085 sys->pSubpictureChromas[0] = VLC_CODEC_RGBA;
1086 sys->pSubpictureChromas[1] = 0;
1087 } else if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1088 DXGI_FORMAT_B8G8R8A8_UNORM,
1089 &i_formatSupport)) &&
1090 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags) {
1091 sys->d3dregion_format = DXGI_FORMAT_B8G8R8A8_UNORM;
1092 sys->pSubpictureChromas[0] = VLC_CODEC_BGRA;
1093 sys->pSubpictureChromas[1] = 0;
1094 } else {
1095 sys->d3dregion_format = DXGI_FORMAT_UNKNOWN;
1098 switch (fmt->i_chroma)
1100 case VLC_CODEC_NV12:
1101 case VLC_CODEC_D3D11_OPAQUE:
1102 if( fmt->i_height > 576 )
1103 sys->d3dPxShader = globPixelShaderBiplanarYUV_BT709_2RGB;
1104 else
1105 sys->d3dPxShader = globPixelShaderBiplanarYUV_BT601_2RGB;
1106 break;
1107 case VLC_CODEC_YV12:
1108 case VLC_CODEC_I420:
1109 if( fmt->i_height > 576 )
1110 sys->d3dPxShader = globPixelShaderBiplanarI420_BT709_2RGB;
1111 else
1112 sys->d3dPxShader = globPixelShaderBiplanarI420_BT601_2RGB;
1113 break;
1114 case VLC_CODEC_RGB32:
1115 case VLC_CODEC_BGRA:
1116 case VLC_CODEC_RGB16:
1117 default:
1118 sys->d3dPxShader = globPixelShaderDefault;
1119 break;
1121 if (sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
1122 sys->psz_rgbaPxShader = globPixelShaderDefault;
1123 else
1124 sys->psz_rgbaPxShader = NULL;
1126 UpdateRects(vd, NULL, NULL, true);
1128 if (Direct3D11CreateResources(vd, fmt)) {
1129 msg_Err(vd, "Failed to allocate resources");
1130 Direct3D11DestroyResources(vd);
1131 return VLC_EGENERIC;
1134 #if !VLC_WINSTORE_APP
1135 EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
1136 #endif
1138 msg_Dbg(vd, "Direct3D11 device adapter successfully initialized");
1139 return VLC_SUCCESS;
1142 static void Direct3D11Close(vout_display_t *vd)
1144 vout_display_sys_t *sys = vd->sys;
1146 Direct3D11DestroyResources(vd);
1147 if (sys->d3dcontext)
1149 ID3D11DeviceContext_Flush(sys->d3dcontext);
1150 ID3D11DeviceContext_Release(sys->d3dcontext);
1151 sys->d3dcontext = NULL;
1153 if (sys->d3ddevice)
1155 ID3D11Device_Release(sys->d3ddevice);
1156 sys->d3ddevice = NULL;
1158 if (sys->dxgiswapChain)
1160 IDXGISwapChain_Release(sys->dxgiswapChain);
1161 sys->dxgiswapChain = NULL;
1164 msg_Dbg(vd, "Direct3D11 device adapter closed");
1167 static void UpdatePicQuadPosition(vout_display_t *vd)
1169 vout_display_sys_t *sys = vd->sys;
1170 int i_width = RECTWidth(sys->rect_dest_clipped);
1171 int i_height = RECTHeight(sys->rect_dest_clipped);
1172 #if VLC_WINSTORE_APP
1173 UINT dataSize = sizeof(i_width);
1174 HRESULT hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, &i_width);
1175 if (FAILED(hr)) {
1176 msg_Err(vd, "Can't get swapchain width, size %d. (hr=0x%lX)", hr, dataSize);
1177 return;
1179 dataSize = sizeof(i_height);
1180 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, &i_height);
1181 if (FAILED(hr)) {
1182 msg_Err(vd, "Can't get swapchain height, size %d. (hr=0x%lX)", hr, dataSize);
1183 return;
1185 #endif
1187 /* Map the subpicture to sys->rect_dest_clipped */
1188 UpdateQuadPosition(vd, &sys->picQuad, &sys->rect_dest_clipped, i_width, i_height, 1.0f);
1191 /* TODO : handle errors better
1192 TODO : seperate out into smaller functions like createshaders */
1193 static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
1195 vout_display_sys_t *sys = vd->sys;
1196 HRESULT hr;
1198 hr = UpdateBackBuffer(vd);
1199 if (FAILED(hr)) {
1200 msg_Err(vd, "Could not update the backbuffer. (hr=0x%lX)", hr);
1201 return VLC_EGENERIC;
1204 ID3D11BlendState *pSpuBlendState;
1205 D3D11_BLEND_DESC spuBlendDesc = { 0 };
1206 spuBlendDesc.RenderTarget[0].BlendEnable = TRUE;
1207 spuBlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
1208 spuBlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
1209 spuBlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
1211 spuBlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1212 spuBlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
1213 spuBlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1215 spuBlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1217 spuBlendDesc.RenderTarget[1].BlendEnable = TRUE;
1218 spuBlendDesc.RenderTarget[1].SrcBlend = D3D11_BLEND_ONE;
1219 spuBlendDesc.RenderTarget[1].DestBlend = D3D11_BLEND_ZERO;
1220 spuBlendDesc.RenderTarget[1].BlendOp = D3D11_BLEND_OP_ADD;
1222 spuBlendDesc.RenderTarget[1].SrcBlendAlpha = D3D11_BLEND_ONE;
1223 spuBlendDesc.RenderTarget[1].DestBlendAlpha = D3D11_BLEND_ZERO;
1224 spuBlendDesc.RenderTarget[1].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1226 spuBlendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1227 hr = ID3D11Device_CreateBlendState(sys->d3ddevice, &spuBlendDesc, &pSpuBlendState);
1228 if (FAILED(hr)) {
1229 msg_Err(vd, "Could not create SPU blend state. (hr=0x%lX)", hr);
1230 return VLC_EGENERIC;
1232 ID3D11DeviceContext_OMSetBlendState(sys->d3dcontext, pSpuBlendState, NULL, 0xFFFFFFFF);
1233 ID3D11BlendState_Release(pSpuBlendState);
1235 /* disable depth testing as we're only doing 2D
1236 * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
1237 * see http://rastertek.com/dx11tut11.html
1239 D3D11_DEPTH_STENCIL_DESC stencilDesc;
1240 ZeroMemory(&stencilDesc, sizeof(stencilDesc));
1241 stencilDesc.DepthEnable = FALSE;
1242 stencilDesc.StencilEnable = TRUE;
1243 stencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
1244 stencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
1245 stencilDesc.StencilReadMask = 0xFF;
1246 stencilDesc.StencilWriteMask = 0xFF;
1247 stencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
1248 stencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
1249 stencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
1250 stencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
1251 stencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
1252 stencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
1253 stencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
1254 stencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
1256 ID3D11DepthStencilState *pDepthStencilState;
1257 hr = ID3D11Device_CreateDepthStencilState(sys->d3ddevice, &stencilDesc, &pDepthStencilState );
1258 if (SUCCEEDED(hr)) {
1259 ID3D11DeviceContext_OMSetDepthStencilState(sys->d3dcontext, pDepthStencilState, 0);
1260 ID3D11DepthStencilState_Release(pDepthStencilState);
1263 ID3DBlob* pVSBlob = NULL;
1265 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1266 hr = D3DCompile(globVertexShaderDefault, strlen(globVertexShaderDefault),
1267 NULL, NULL, NULL, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob, NULL);
1269 if( FAILED(hr)) {
1270 msg_Err(vd, "The Vertex Shader is invalid.");
1271 return VLC_EGENERIC;
1274 ID3D11VertexShader *d3dvertexShader;
1275 hr = ID3D11Device_CreateVertexShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
1276 ID3D10Blob_GetBufferSize(pVSBlob), NULL, &d3dvertexShader);
1278 if(FAILED(hr)) {
1279 ID3D11Device_Release(pVSBlob);
1280 msg_Err(vd, "Failed to create the vertex shader.");
1281 return VLC_EGENERIC;
1283 ID3D11DeviceContext_VSSetShader(sys->d3dcontext, d3dvertexShader, NULL, 0);
1284 ID3D11VertexShader_Release(d3dvertexShader);
1286 D3D11_INPUT_ELEMENT_DESC layout[] = {
1287 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
1288 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
1289 { "OPACITY", 0, DXGI_FORMAT_R32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0},
1292 ID3D11InputLayout* pVertexLayout = NULL;
1293 hr = ID3D11Device_CreateInputLayout(sys->d3ddevice, layout, 3, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
1294 ID3D10Blob_GetBufferSize(pVSBlob), &pVertexLayout);
1296 ID3D10Blob_Release(pVSBlob);
1298 if(FAILED(hr)) {
1299 msg_Err(vd, "Failed to create the vertex input layout");
1300 return VLC_EGENERIC;
1303 ID3D11DeviceContext_IASetInputLayout(sys->d3dcontext, pVertexLayout);
1304 ID3D11SamplerState_Release(pVertexLayout);
1306 /* create the index of the vertices */
1307 WORD indices[] = {
1308 3, 1, 0,
1309 2, 1, 3,
1312 D3D11_BUFFER_DESC quadDesc = {
1313 .Usage = D3D11_USAGE_DEFAULT,
1314 .ByteWidth = sizeof(WORD) * 6,
1315 .BindFlags = D3D11_BIND_INDEX_BUFFER,
1316 .CPUAccessFlags = 0,
1319 D3D11_SUBRESOURCE_DATA quadIndicesInit = {
1320 .pSysMem = indices,
1323 ID3D11Buffer* pIndexBuffer = NULL;
1324 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &quadDesc, &quadIndicesInit, &pIndexBuffer);
1325 if(FAILED(hr)) {
1326 msg_Err(vd, "Could not Create the common quad indices. (hr=0x%lX)", hr);
1327 return VLC_EGENERIC;
1329 ID3D11DeviceContext_IASetIndexBuffer(sys->d3dcontext, pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
1330 ID3D11Buffer_Release(pIndexBuffer);
1332 ID3D11DeviceContext_IASetPrimitiveTopology(sys->d3dcontext, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1334 ID3DBlob* pPSBlob = NULL;
1336 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1337 hr = D3DCompile(sys->d3dPxShader, strlen(sys->d3dPxShader),
1338 NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
1341 if( FAILED(hr)) {
1342 msg_Err(vd, "The Pixel Shader is invalid. (hr=0x%lX)", hr );
1343 return VLC_EGENERIC;
1346 ID3D11PixelShader *pPicQuadShader;
1347 hr = ID3D11Device_CreatePixelShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
1348 ID3D10Blob_GetBufferSize(pPSBlob), NULL, &pPicQuadShader);
1350 ID3D10Blob_Release(pPSBlob);
1352 if(FAILED(hr)) {
1353 msg_Err(vd, "Failed to create the pixel shader.");
1354 return VLC_EGENERIC;
1357 if (sys->psz_rgbaPxShader != NULL)
1359 hr = D3DCompile(sys->psz_rgbaPxShader, strlen(sys->psz_rgbaPxShader),
1360 NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
1361 if( FAILED(hr)) {
1362 ID3D11PixelShader_Release(pPicQuadShader);
1363 msg_Err(vd, "The RGBA Pixel Shader is invalid. (hr=0x%lX)", hr );
1364 return VLC_EGENERIC;
1367 hr = ID3D11Device_CreatePixelShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
1368 ID3D10Blob_GetBufferSize(pPSBlob), NULL, &sys->pSPUPixelShader);
1370 ID3D10Blob_Release(pPSBlob);
1372 if(FAILED(hr)) {
1373 ID3D11PixelShader_Release(pPicQuadShader);
1374 msg_Err(vd, "Failed to create the SPU pixel shader.");
1375 return VLC_EGENERIC;
1379 if (AllocQuad( vd, fmt, &sys->picQuad, &sys->picQuadConfig, pPicQuadShader) != VLC_SUCCESS) {
1380 ID3D11PixelShader_Release(pPicQuadShader);
1381 msg_Err(vd, "Could not Create the main quad picture. (hr=0x%lX)", hr);
1382 return VLC_EGENERIC;
1384 ID3D11PixelShader_Release(pPicQuadShader);
1386 UpdatePicQuadPosition(vd);
1388 D3D11_SAMPLER_DESC sampDesc;
1389 memset(&sampDesc, 0, sizeof(sampDesc));
1390 sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
1391 sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
1392 sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
1393 sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
1394 sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
1395 sampDesc.MinLOD = 0;
1396 sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
1398 ID3D11SamplerState *d3dsampState;
1399 hr = ID3D11Device_CreateSamplerState(sys->d3ddevice, &sampDesc, &d3dsampState);
1401 if (FAILED(hr)) {
1402 msg_Err(vd, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr);
1403 return VLC_EGENERIC;
1405 ID3D11DeviceContext_PSSetSamplers(sys->d3dcontext, 0, 1, &d3dsampState);
1406 ID3D11SamplerState_Release(d3dsampState);
1408 if (Direct3D11CreatePool(vd, fmt))
1410 msg_Err(vd, "Direct3D picture pool initialization failed");
1411 return VLC_EGENERIC;
1414 msg_Dbg(vd, "Direct3D11 resources created");
1415 return VLC_SUCCESS;
1418 static int Direct3D11CreatePool(vout_display_t *vd, video_format_t *fmt)
1420 vout_display_sys_t *sys = vd->sys;
1422 if ( fmt->i_chroma == VLC_CODEC_D3D11_OPAQUE )
1423 /* a D3D11VA pool will be created when needed */
1424 return VLC_SUCCESS;
1426 picture_sys_pool_t *picsys = calloc(1, sizeof(*picsys));
1427 if (unlikely(picsys == NULL)) {
1428 return VLC_ENOMEM;
1431 picsys->texture = sys->picQuad.pTexture;
1432 picsys->vd = vd;
1434 picture_resource_t resource = {
1435 .p_sys = (picture_sys_t*) picsys,
1436 .pf_destroy = DestroyDisplayPicture,
1439 picture_t *picture = picture_NewFromResource(fmt, &resource);
1440 if (!picture) {
1441 free(picsys);
1442 return VLC_ENOMEM;
1444 ID3D11Texture2D_AddRef(picsys->texture);
1446 picture_pool_configuration_t pool_cfg;
1447 memset(&pool_cfg, 0, sizeof(pool_cfg));
1448 pool_cfg.picture_count = 1;
1449 pool_cfg.picture = &picture;
1450 pool_cfg.lock = Direct3D11MapTexture;
1452 sys->pool = picture_pool_NewExtended(&pool_cfg);
1453 if (!sys->pool) {
1454 picture_Release(picture);
1455 return VLC_ENOMEM;
1458 return VLC_SUCCESS;
1461 static void Direct3D11DestroyPool(vout_display_t *vd)
1463 vout_display_sys_t *sys = vd->sys;
1465 if (sys->pool)
1466 picture_pool_Release(sys->pool);
1467 sys->pool = NULL;
1470 static int AllocQuad(vout_display_t *vd, const video_format_t *fmt, d3d_quad_t *quad,
1471 d3d_quad_cfg_t *cfg, ID3D11PixelShader *d3dpixelShader)
1473 vout_display_sys_t *sys = vd->sys;
1474 HRESULT hr;
1476 D3D11_BUFFER_DESC bd;
1477 memset(&bd, 0, sizeof(bd));
1478 bd.Usage = D3D11_USAGE_DYNAMIC;
1479 bd.ByteWidth = sizeof(d3d_vertex_t) * 4;
1480 bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1481 bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1483 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &bd, NULL, &quad->pVertexBuffer);
1484 if(FAILED(hr)) {
1485 msg_Err(vd, "Failed to create vertex buffer.");
1486 goto error;
1489 D3D11_TEXTURE2D_DESC texDesc;
1490 memset(&texDesc, 0, sizeof(texDesc));
1491 texDesc.Width = fmt->i_visible_width;
1492 texDesc.Height = fmt->i_visible_height;
1493 texDesc.MipLevels = texDesc.ArraySize = 1;
1494 texDesc.Format = cfg->textureFormat;
1495 texDesc.SampleDesc.Count = 1;
1496 texDesc.Usage = D3D11_USAGE_DYNAMIC;
1497 texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
1498 texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1499 texDesc.MiscFlags = 0;
1501 hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &texDesc, NULL, &quad->pTexture);
1502 if (FAILED(hr)) {
1503 msg_Err(vd, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr);
1504 goto error;
1507 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc;
1508 memset(&resviewDesc, 0, sizeof(resviewDesc));
1509 resviewDesc.Format = cfg->resourceFormatYRGB;
1510 resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
1511 resviewDesc.Texture2D.MipLevels = texDesc.MipLevels;
1513 hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)quad->pTexture, &resviewDesc, &quad->d3dresViewY);
1514 if (FAILED(hr)) {
1515 msg_Err(vd, "Could not Create the Y/RGB D3d11 Texture ResourceView. (hr=0x%lX)", hr);
1516 goto error;
1519 if( cfg->resourceFormatUV )
1521 resviewDesc.Format = cfg->resourceFormatUV;
1522 hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)quad->pTexture, &resviewDesc, &quad->d3dresViewUV);
1523 if (FAILED(hr)) {
1524 msg_Err(vd, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr);
1525 goto error;
1529 quad->d3dpixelShader = d3dpixelShader;
1530 ID3D11PixelShader_AddRef(quad->d3dpixelShader);
1532 return VLC_SUCCESS;
1534 error:
1535 ReleaseQuad(quad);
1536 return VLC_EGENERIC;
1539 static void ReleaseQuad(d3d_quad_t *quad)
1541 if (quad->pVertexBuffer)
1542 ID3D11Buffer_Release(quad->pVertexBuffer);
1543 if (quad->pTexture)
1544 ID3D11Texture2D_Release(quad->pTexture);
1545 if (quad->d3dresViewY)
1546 ID3D11ShaderResourceView_Release(quad->d3dresViewY);
1547 if (quad->d3dresViewUV)
1548 ID3D11ShaderResourceView_Release(quad->d3dresViewUV);
1549 if (quad->d3dpixelShader)
1550 ID3D11VertexShader_Release(quad->d3dpixelShader);
1553 static void Direct3D11DestroyResources(vout_display_t *vd)
1555 vout_display_sys_t *sys = vd->sys;
1557 Direct3D11DestroyPool(vd);
1559 ReleaseQuad(&sys->picQuad);
1560 Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
1561 sys->d3dregion_count = 0;
1563 if (sys->d3drenderTargetView)
1564 ID3D11RenderTargetView_Release(sys->d3drenderTargetView);
1565 if (sys->d3ddepthStencilView)
1566 ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
1567 if (sys->pSPUPixelShader)
1568 ID3D11VertexShader_Release(sys->pSPUPixelShader);
1570 msg_Dbg(vd, "Direct3D11 resources destroyed");
1573 static int Direct3D11MapTexture(picture_t *picture)
1575 picture_sys_pool_t *p_sys = (picture_sys_pool_t*) picture->p_sys;
1576 vout_display_t *vd = p_sys->vd;
1577 D3D11_MAPPED_SUBRESOURCE mappedResource;
1578 HRESULT hr;
1579 int res;
1580 hr = ID3D11DeviceContext_Map(vd->sys->d3dcontext, (ID3D11Resource *)p_sys->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
1581 if( FAILED(hr) )
1583 msg_Dbg( vd, "failed to map the texture (hr=0x%lX)", hr );
1584 return VLC_EGENERIC;
1586 res = CommonUpdatePicture(picture, NULL, mappedResource.pData, mappedResource.RowPitch);
1587 ID3D11DeviceContext_Unmap(vd->sys->d3dcontext,(ID3D11Resource *)p_sys->texture, 0);
1588 return res;
1591 static void Direct3D11DeleteRegions(int count, picture_t **region)
1593 for (int i = 0; i < count; ++i) {
1594 if (region[i]) {
1595 picture_Release(region[i]);
1598 free(region);
1601 static void DestroyPictureQuad(picture_t *p_picture)
1603 ReleaseQuad( (d3d_quad_t *) p_picture->p_sys );
1604 free( p_picture );
1607 static void UpdateQuadPosition(vout_display_t *vd, const d3d_quad_t *quad, const RECT *dst, int i_width, int i_height, float opacity)
1609 vout_display_sys_t *sys = vd->sys;
1610 D3D11_MAPPED_SUBRESOURCE mappedResource;
1612 // adjust with the center at 0,0 and the edges at -1/1
1613 float left = -1.0f + 2.0f * ((float) dst->left / i_width );
1614 float right = -1.0f + 2.0f * ((float) dst->right / i_width );
1615 float top = 1.0f - 2.0f * ((float) dst->top / i_height );
1616 float bottom = 1.0f - 2.0f * ((float) dst->bottom / i_height );
1618 HRESULT hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
1619 if (SUCCEEDED(hr)) {
1620 d3d_vertex_t *dst_data = mappedResource.pData;
1622 // bottom left
1623 dst_data[0].position.x = left;
1624 dst_data[0].position.y = bottom;
1625 dst_data[0].position.z = 0.0f;
1626 dst_data[0].texture.x = 0.0f;
1627 dst_data[0].texture.y = 1.0f;
1628 dst_data[0].opacity = opacity;
1630 // bottom right
1631 dst_data[1].position.x = right;
1632 dst_data[1].position.y = bottom;
1633 dst_data[1].position.z = 0.0f;
1634 dst_data[1].texture.x = 1.0f;
1635 dst_data[1].texture.y = 1.0f;
1636 dst_data[1].opacity = opacity;
1638 // top right
1639 dst_data[2].position.x = right;
1640 dst_data[2].position.y = top;
1641 dst_data[2].position.z = 0.0f;
1642 dst_data[2].texture.x = 1.0f;
1643 dst_data[2].texture.y = 0.0f;
1644 dst_data[2].opacity = opacity;
1646 // top left
1647 dst_data[3].position.x = left;
1648 dst_data[3].position.y = top;
1649 dst_data[3].position.z = 0.0f;
1650 dst_data[3].texture.x = 0.0f;
1651 dst_data[3].texture.y = 0.0f;
1652 dst_data[3].opacity = opacity;
1654 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
1656 else {
1657 msg_Err(vd, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr);
1661 static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_count,
1662 picture_t ***region, subpicture_t *subpicture)
1664 vout_display_sys_t *sys = vd->sys;
1665 D3D11_MAPPED_SUBRESOURCE mappedResource;
1666 D3D11_TEXTURE2D_DESC texDesc;
1667 HRESULT hr;
1668 int err;
1670 int count = 0;
1671 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
1672 count++;
1674 *region = calloc(count, sizeof(picture_t *));
1675 if (unlikely(*region==NULL))
1676 return VLC_ENOMEM;
1677 *subpicture_region_count = count;
1679 int i = 0;
1680 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
1681 for (int j = 0; j < sys->d3dregion_count; j++) {
1682 picture_t *cache = sys->d3dregions[j];
1683 if (cache != NULL && ((d3d_quad_t *) cache->p_sys)->pTexture) {
1684 ID3D11Texture2D_GetDesc( ((d3d_quad_t *) cache->p_sys)->pTexture, &texDesc );
1685 if (texDesc.Format == sys->d3dregion_format &&
1686 texDesc.Width == r->fmt.i_visible_width &&
1687 texDesc.Height == r->fmt.i_visible_height) {
1688 (*region)[i] = cache;
1689 memset(&sys->d3dregions[j], 0, sizeof(cache)); // do not reuse this cached value
1690 break;
1695 picture_t *quad_picture = (*region)[i];
1696 if (quad_picture == NULL) {
1697 d3d_quad_t *d3dquad = calloc(1, sizeof(*d3dquad));
1698 if (unlikely(d3dquad==NULL)) {
1699 continue;
1701 d3d_quad_cfg_t rgbaCfg = {
1702 .textureFormat = sys->d3dregion_format,
1703 .resourceFormatYRGB = sys->d3dregion_format,
1705 err = AllocQuad(vd, &r->fmt, d3dquad, &rgbaCfg, sys->pSPUPixelShader);
1706 if (err != VLC_SUCCESS) {
1707 msg_Err(vd, "Failed to create %dx%d texture for OSD",
1708 r->fmt.i_visible_width, r->fmt.i_visible_height);
1709 free(d3dquad);
1710 continue;
1712 picture_resource_t picres = {
1713 .p_sys = (picture_sys_t *) d3dquad,
1714 .pf_destroy = DestroyPictureQuad,
1716 (*region)[i] = picture_NewFromResource(&r->fmt, &picres);
1717 if ((*region)[i] == NULL) {
1718 msg_Err(vd, "Failed to create %dx%d picture for OSD",
1719 r->fmt.i_visible_width, r->fmt.i_visible_height);
1720 ReleaseQuad(d3dquad);
1721 continue;
1723 quad_picture = (*region)[i];
1724 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
1725 if( SUCCEEDED(hr) ) {
1726 err = CommonUpdatePicture(quad_picture, NULL, mappedResource.pData, mappedResource.RowPitch);
1727 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0);
1728 if (err != VLC_SUCCESS) {
1729 msg_Err(vd, "Failed to set the buffer on the OSD picture" );
1730 picture_Release(quad_picture);
1731 continue;
1733 } else {
1734 msg_Err(vd, "Failed to map the OSD texture (hr=0x%lX)", hr );
1735 picture_Release(quad_picture);
1736 continue;
1738 #ifndef NDEBUG
1739 msg_Dbg(vd, "Created %dx%d texture for OSD",
1740 r->fmt.i_visible_width, r->fmt.i_visible_height);
1741 #endif
1744 picture_CopyPixels(quad_picture, r->p_picture);
1746 /* Map the subpicture to sys->rect_dest */
1747 const int i_original_width = subpicture->i_original_picture_width;
1748 const int i_original_height = subpicture->i_original_picture_height;
1750 const RECT video = sys->rect_dest;
1751 const float scale_w = (float)(video.right - video.left) / i_original_width;
1752 const float scale_h = (float)(video.bottom - video.top) / i_original_height;
1754 RECT dst;
1755 dst.left = video.left + scale_w * r->i_x,
1756 dst.right = dst.left + scale_w * r->fmt.i_visible_width,
1757 dst.top = video.top + scale_h * r->i_y,
1758 dst.bottom = dst.top + scale_h * r->fmt.i_visible_height;
1760 float opacity = (float)r->i_alpha / 255.0f;
1762 UpdateQuadPosition(vd, (d3d_quad_t *)quad_picture->p_sys, &dst,
1763 i_original_width, i_original_height, opacity);
1765 return VLC_SUCCESS;