direct3d11: remove the deprecated USE_DXGI code
[vlc.git] / modules / video_output / win32 / direct3d11.c
blob18348287d7dd40dcc586f8f0661a53f501f1420d
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 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_WIN7
25 # undef _WIN32_WINNT
26 # define _WIN32_WINNT _WIN32_WINNT_WIN7
27 #endif
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout_display.h>
37 #include <assert.h>
38 #include <math.h>
40 #define COBJMACROS
41 #define INITGUID
42 #include <d3d11.h>
44 /* avoided until we can pass ISwapchainPanel without c++/cx mode
45 # include <windows.ui.xaml.media.dxinterop.h> */
47 #include "common.h"
49 #include "../../video_chroma/dxgi_fmt.h"
51 #if !VLC_WINSTORE_APP
52 # define D3D11CreateDevice(args...) sys->OurD3D11CreateDevice(args)
53 # define D3DCompile(args...) sys->OurD3DCompile(args)
54 #endif
56 DEFINE_GUID(GUID_SWAPCHAIN_WIDTH, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
57 DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
58 DEFINE_GUID(GUID_CONTEXT_MUTEX, 0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
60 static int Open(vlc_object_t *);
61 static void Close(vlc_object_t *);
63 #define D3D11_HELP N_("Recommended video output for Windows 8 and later versions")
64 #define HW_BLENDING_TEXT N_("Use hardware blending support")
65 #define HW_BLENDING_LONGTEXT N_(\
66 "Try to use hardware acceleration for subtitle/OSD blending.")
68 vlc_module_begin ()
69 set_shortname("Direct3D11")
70 set_description(N_("Direct3D11 video output"))
71 set_help(D3D11_HELP)
72 set_category(CAT_VIDEO)
73 set_subcategory(SUBCAT_VIDEO_VOUT)
75 add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT, true)
77 #if VLC_WINSTORE_APP
78 add_integer("winrt-d3dcontext", 0x0, NULL, NULL, true); /* ID3D11DeviceContext* */
79 add_integer("winrt-swapchain", 0x0, NULL, NULL, true); /* IDXGISwapChain1* */
80 #endif
82 set_capability("vout display", 240)
83 add_shortcut("direct3d11")
84 set_callbacks(Open, Close)
85 vlc_module_end ()
87 #ifdef HAVE_ID3D11VIDEODECODER
88 /* VLC_CODEC_D3D11_OPAQUE */
89 struct picture_sys_t
91 ID3D11VideoDecoderOutputView *decoder; /* may be NULL for pictures from the pool */
92 ID3D11Texture2D *texture;
93 ID3D11DeviceContext *context;
94 unsigned slice_index;
96 #endif
98 /* internal picture_t pool */
99 typedef struct
101 ID3D11Texture2D *texture;
102 vout_display_t *vd;
103 } picture_sys_pool_t;
105 /* matches the D3D11_INPUT_ELEMENT_DESC we setup */
106 typedef struct d3d_vertex_t {
107 struct {
108 FLOAT x;
109 FLOAT y;
110 FLOAT z;
111 } position;
112 struct {
113 FLOAT x;
114 FLOAT y;
115 } texture;
116 } d3d_vertex_t;
118 typedef struct {
119 FLOAT Opacity;
120 FLOAT opacityPadding[3];
121 } PS_CONSTANT_BUFFER;
123 typedef struct {
124 FLOAT WhitePoint[3];
125 FLOAT whitePadding;
126 FLOAT Colorspace[4*4];
127 } PS_COLOR_TRANSFORM;
129 typedef struct {
130 FLOAT RotX[4*4];
131 FLOAT RotY[4*4];
132 FLOAT RotZ[4*4];
133 FLOAT View[4*4];
134 FLOAT Projection[4*4];
135 } VS_PROJECTION_CONST;
137 #define SPHERE_RADIUS 1.f
139 #define RECTWidth(r) (int)((r).right - (r).left)
140 #define RECTHeight(r) (int)((r).bottom - (r).top)
142 static picture_pool_t *Pool(vout_display_t *vd, unsigned count);
144 static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
145 static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
147 static HINSTANCE Direct3D11LoadShaderLibrary(void);
148 static void Direct3D11Destroy(vout_display_t *);
150 static int Direct3D11Open (vout_display_t *, video_format_t *);
151 static void Direct3D11Close(vout_display_t *);
153 static int Direct3D11CreateResources (vout_display_t *, video_format_t *);
154 static void Direct3D11DestroyResources(vout_display_t *);
156 static int Direct3D11CreatePool (vout_display_t *, video_format_t *);
157 static void Direct3D11DestroyPool(vout_display_t *);
159 static void DestroyDisplayPicture(picture_t *);
160 static void DestroyDisplayPoolPicture(picture_t *);
161 static int Direct3D11MapTexture(picture_t *);
162 static int Direct3D11UnmapTexture(picture_t *);
163 static void Direct3D11DeleteRegions(int, picture_t **);
164 static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
166 static int AllocQuad(vout_display_t *, const video_format_t *, d3d_quad_t *,
167 d3d_quad_cfg_t *, ID3D11PixelShader *, bool b_visible,
168 video_projection_mode_t);
169 static void ReleaseQuad(d3d_quad_t *);
170 static void UpdatePicQuadPosition(vout_display_t *);
171 static void UpdateQuadOpacity(vout_display_t *, const d3d_quad_t *, float);
173 static int Control(vout_display_t *vd, int query, va_list args);
174 static void Manage(vout_display_t *vd);
176 /* TODO: Move to a direct3d11_shaders header */
177 static const char* globVertexShaderFlat = "\
178 struct VS_INPUT\
180 float4 Position : POSITION;\
181 float2 Texture : TEXCOORD0;\
184 struct VS_OUTPUT\
186 float4 Position : SV_POSITION;\
187 float2 Texture : TEXCOORD0;\
190 VS_OUTPUT VS( VS_INPUT In )\
192 return In;\
196 static const char* globVertexShaderProjection = "\
197 cbuffer VS_PROJECTION_CONST : register(b0)\
199 float4x4 RotX;\
200 float4x4 RotY;\
201 float4x4 RotZ;\
202 float4x4 View;\
203 float4x4 Projection;\
205 struct VS_INPUT\
207 float4 Position : POSITION;\
208 float2 Texture : TEXCOORD0;\
211 struct VS_OUTPUT\
213 float4 Position : SV_POSITION;\
214 float2 Texture : TEXCOORD0;\
217 VS_OUTPUT VS( VS_INPUT In )\
219 VS_OUTPUT Output;\
220 float4 pos = In.Position;\
221 pos = mul(RotY, pos);\
222 pos = mul(RotX, pos);\
223 pos = mul(RotZ, pos);\
224 pos = mul(View, pos);\
225 pos = mul(Projection, pos);\
226 Output.Position = pos;\
227 Output.Texture = In.Texture;\
228 return Output;\
232 static const char* globPixelShaderDefault = "\
233 cbuffer PS_CONSTANT_BUFFER : register(b0)\
235 float Opacity;\
236 float opacityPadding[3];\
238 Texture2D shaderTexture;\
239 SamplerState SampleType;\
241 struct PS_INPUT\
243 float4 Position : SV_POSITION;\
244 float2 Texture : TEXCOORD0;\
247 float4 PS( PS_INPUT In ) : SV_TARGET\
249 float4 rgba; \
251 rgba = shaderTexture.Sample(SampleType, In.Texture);\
252 rgba.a = rgba.a * Opacity;\
253 return rgba; \
257 static const char *globPixelShaderBiplanarYUV_2RGB = "\
258 cbuffer PS_CONSTANT_BUFFER : register(b0)\
260 float Opacity;\
261 float opacityPadding[3];\
263 cbuffer PS_COLOR_TRANSFORM : register(b1)\
265 float WhitePointX;\
266 float WhitePointY;\
267 float WhitePointZ;\
268 float whitePadding;\
269 float4x4 Colorspace;\
271 Texture2D shaderTextureY;\
272 Texture2D shaderTextureUV;\
273 SamplerState SampleType;\
275 struct PS_INPUT\
277 float4 Position : SV_POSITION;\
278 float2 Texture : TEXCOORD0;\
281 float4 PS( PS_INPUT In ) : SV_TARGET\
283 float4 yuv;\
284 float4 rgba;\
285 yuv.x = shaderTextureY.Sample(SampleType, In.Texture).x;\
286 yuv.yz = shaderTextureUV.Sample(SampleType, In.Texture).xy;\
287 yuv.a = Opacity;\
288 yuv.x += WhitePointX;\
289 yuv.y += WhitePointY;\
290 yuv.z += WhitePointZ;\
291 rgba = saturate(mul(yuv, Colorspace));\
292 return rgba;\
296 static const char *globPixelShaderBiplanarYUYV_2RGB = "\
297 cbuffer PS_CONSTANT_BUFFER : register(b0)\
299 float Opacity;\
300 float opacityPadding[3];\
302 cbuffer PS_COLOR_TRANSFORM : register(b1)\
304 float WhitePointX;\
305 float WhitePointY;\
306 float WhitePointZ;\
307 float whitePadding;\
308 float4x4 Colorspace;\
310 Texture2D shaderTextureYUYV;\
311 SamplerState SampleType;\
313 struct PS_INPUT\
315 float4 Position : SV_POSITION;\
316 float2 Texture : TEXCOORD0;\
319 float4 PS( PS_INPUT In ) : SV_TARGET\
321 float4 yuv;\
322 float4 rgba;\
323 yuv.x = shaderTextureYUYV.Sample(SampleType, In.Texture).x;\
324 yuv.y = shaderTextureYUYV.Sample(SampleType, In.Texture).y;\
325 yuv.z = shaderTextureYUYV.Sample(SampleType, In.Texture).a;\
326 yuv.a = Opacity;\
327 yuv.x += WhitePointX;\
328 yuv.y += WhitePointY;\
329 yuv.z += WhitePointZ;\
330 rgba = saturate(mul(yuv, Colorspace));\
331 return rgba;\
335 #if !VLC_WINSTORE_APP
336 static int OpenHwnd(vout_display_t *vd)
338 HINSTANCE hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
339 if (!hd3d11_dll) {
340 msg_Warn(vd, "cannot load d3d11.dll, aborting");
341 return VLC_EGENERIC;
344 HINSTANCE hd3dcompiler_dll = Direct3D11LoadShaderLibrary();
345 if (!hd3dcompiler_dll) {
346 msg_Err(vd, "cannot load d3dcompiler.dll, aborting");
347 Direct3D11Destroy(vd);
348 return VLC_EGENERIC;
351 vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
352 if (!sys)
353 return VLC_ENOMEM;
355 sys->hd3d11_dll = hd3d11_dll;
356 sys->hd3dcompiler_dll = hd3dcompiler_dll;
358 sys->OurD3DCompile = (void *)GetProcAddress(sys->hd3dcompiler_dll, "D3DCompile");
359 if (!sys->OurD3DCompile) {
360 msg_Err(vd, "Cannot locate reference to D3DCompile in d3dcompiler DLL");
361 Direct3D11Destroy(vd);
362 return VLC_EGENERIC;
365 sys->OurD3D11CreateDevice =
366 (void *)GetProcAddress(hd3d11_dll, "D3D11CreateDevice");
367 if (!sys->OurD3D11CreateDevice) {
368 msg_Err(vd, "Cannot locate reference to D3D11CreateDevice in d3d11 DLL");
369 Direct3D11Destroy(vd);
370 return VLC_EGENERIC;
372 return VLC_SUCCESS;
374 #else
375 static int OpenCoreW(vout_display_t *vd)
377 IDXGISwapChain1* dxgiswapChain = var_InheritInteger(vd, "winrt-swapchain");
378 if (!dxgiswapChain)
379 return VLC_EGENERIC;
380 ID3D11DeviceContext* d3dcontext = var_InheritInteger(vd, "winrt-d3dcontext");
381 if (!d3dcontext)
382 return VLC_EGENERIC;
383 ID3D11Device* d3ddevice = NULL;
384 ID3D11DeviceContext_GetDevice(d3dcontext, &d3ddevice);
385 if (!d3ddevice)
386 return VLC_EGENERIC;
388 vout_display_sys_t *sys = vd->sys = calloc(1, sizeof(vout_display_sys_t));
389 if (!sys)
390 return VLC_ENOMEM;
392 sys->dxgiswapChain = dxgiswapChain;
393 sys->d3ddevice = d3ddevice;
394 sys->d3dcontext = d3dcontext;
395 IDXGISwapChain_AddRef (sys->dxgiswapChain);
396 ID3D11Device_AddRef (sys->d3ddevice);
397 ID3D11DeviceContext_AddRef(sys->d3dcontext);
399 return VLC_SUCCESS;
401 #endif
403 static bool is_d3d11_opaque(vlc_fourcc_t chroma)
405 switch (chroma)
407 case VLC_CODEC_D3D11_OPAQUE:
408 case VLC_CODEC_D3D11_OPAQUE_10B:
409 return true;
410 default:
411 return false;
415 static int Open(vlc_object_t *object)
417 vout_display_t *vd = (vout_display_t *)object;
419 #if !VLC_WINSTORE_APP
420 int ret = OpenHwnd(vd);
421 #else
422 int ret = OpenCoreW(vd);
423 #endif
425 if (ret != VLC_SUCCESS)
426 return ret;
428 if (CommonInit(vd))
429 goto error;
431 video_format_t fmt;
432 if (Direct3D11Open(vd, &fmt)) {
433 msg_Err(vd, "Direct3D11 could not be opened");
434 goto error;
437 vout_display_info_t info = vd->info;
438 info.is_slow = !is_d3d11_opaque(fmt.i_chroma);
439 info.has_double_click = true;
440 info.has_hide_mouse = false;
441 info.has_pictures_invalid = !is_d3d11_opaque(fmt.i_chroma);
443 if (var_InheritBool(vd, "direct3d11-hw-blending") &&
444 vd->sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
445 info.subpicture_chromas = vd->sys->pSubpictureChromas;
446 else
447 info.subpicture_chromas = NULL;
449 video_format_Clean(&vd->fmt);
450 video_format_Copy(&vd->fmt, &fmt);
451 vd->info = info;
453 vd->pool = Pool;
454 vd->prepare = Prepare;
455 vd->display = Display;
456 vd->control = Control;
457 vd->manage = Manage;
459 msg_Dbg(vd, "Direct3D11 Open Succeeded");
461 return VLC_SUCCESS;
463 error:
464 Close(object);
465 return VLC_EGENERIC;
468 static void Close(vlc_object_t *object)
470 vout_display_t * vd = (vout_display_t *)object;
472 Direct3D11Close(vd);
473 CommonClean(vd);
474 Direct3D11Destroy(vd);
475 free(vd->sys);
478 static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
480 if ( vd->sys->pool != NULL )
481 return vd->sys->pool;
483 if (pool_size > 30) {
484 msg_Err(vd, "Avoid crashing when using ID3D11VideoDecoderOutputView with too many slices (%d)", pool_size);
485 return NULL;
488 #ifdef HAVE_ID3D11VIDEODECODER
489 picture_t** pictures = NULL;
490 unsigned picture_count = 0;
491 HRESULT hr;
493 ID3D10Multithread *pMultithread;
494 hr = ID3D11Device_QueryInterface( vd->sys->d3ddevice, &IID_ID3D10Multithread, (void **)&pMultithread);
495 if (SUCCEEDED(hr)) {
496 ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
497 ID3D10Multithread_Release(pMultithread);
500 pictures = calloc(pool_size, sizeof(*pictures));
501 if (!pictures)
502 goto error;
504 D3D11_TEXTURE2D_DESC texDesc;
505 ZeroMemory(&texDesc, sizeof(texDesc));
506 texDesc.Width = vd->fmt.i_width;
507 texDesc.Height = vd->fmt.i_height;
508 texDesc.MipLevels = 1;
509 texDesc.Format = vd->sys->picQuadConfig.textureFormat;
510 texDesc.SampleDesc.Count = 1;
511 texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
512 texDesc.Usage = D3D11_USAGE_DEFAULT;
513 texDesc.BindFlags = D3D11_BIND_DECODER;
514 texDesc.CPUAccessFlags = 0;
516 texDesc.ArraySize = pool_size;
518 ID3D11Texture2D *texture;
519 hr = ID3D11Device_CreateTexture2D( vd->sys->d3ddevice, &texDesc, NULL, &texture );
520 if (FAILED(hr)) {
521 msg_Err(vd, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
522 goto error;
525 for (picture_count = 0; picture_count < pool_size; picture_count++) {
526 picture_sys_t *picsys = calloc(1, sizeof(*picsys));
527 if (unlikely(picsys == NULL))
528 goto error;
530 ID3D11Texture2D_AddRef(texture);
531 picsys->texture = texture;
532 picsys->slice_index = picture_count;
533 picsys->context = vd->sys->d3dcontext;
535 picture_resource_t resource = {
536 .p_sys = picsys,
537 .pf_destroy = DestroyDisplayPoolPicture,
540 picture_t *picture = picture_NewFromResource(&vd->fmt, &resource);
541 if (unlikely(picture == NULL)) {
542 free(picsys);
543 msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
544 goto error;
547 pictures[picture_count] = picture;
548 /* each picture_t holds a ref to the context and release it on Destroy */
549 ID3D11DeviceContext_AddRef(picsys->context);
551 ID3D11Texture2D_Release(texture);
553 msg_Dbg(vd, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d) texture 0x%p context 0x%p",
554 pool_size, vd->fmt.i_width, vd->fmt.i_height, texture, vd->sys->d3dcontext);
556 picture_pool_configuration_t pool_cfg;
557 memset(&pool_cfg, 0, sizeof(pool_cfg));
558 pool_cfg.picture_count = pool_size;
559 pool_cfg.picture = pictures;
561 vd->sys->pool = picture_pool_NewExtended( &pool_cfg );
563 error:
564 if (vd->sys->pool ==NULL && pictures) {
565 msg_Dbg(vd, "Failed to create the picture d3d11 pool");
566 for (unsigned i=0;i<picture_count; ++i)
567 DestroyDisplayPoolPicture(pictures[i]);
568 free(pictures);
570 /* create an empty pool to avoid crashing */
571 picture_pool_configuration_t pool_cfg;
572 memset( &pool_cfg, 0, sizeof( pool_cfg ) );
573 pool_cfg.picture_count = 0;
575 vd->sys->pool = picture_pool_NewExtended( &pool_cfg );
577 #endif
578 return vd->sys->pool;
581 #ifdef HAVE_ID3D11VIDEODECODER
582 static void DestroyDisplayPoolPicture(picture_t *picture)
584 picture_sys_t *p_sys = (picture_sys_t*) picture->p_sys;
586 if (p_sys->texture)
587 ID3D11Texture2D_Release(p_sys->texture);
588 if (p_sys->context)
589 ID3D11DeviceContext_Release(p_sys->context);
591 free(p_sys);
592 free(picture);
594 #endif
596 static void DestroyDisplayPicture(picture_t *picture)
598 picture_sys_pool_t *p_sys = (picture_sys_pool_t*) picture->p_sys;
600 if (p_sys->texture)
601 ID3D11Texture2D_Release(p_sys->texture);
603 free(p_sys);
604 free(picture);
607 static HRESULT UpdateBackBuffer(vout_display_t *vd)
609 vout_display_sys_t *sys = vd->sys;
610 HRESULT hr;
611 ID3D11Texture2D* pDepthStencil;
612 ID3D11Texture2D* pBackBuffer;
613 uint32_t i_width = RECTWidth(sys->rect_dest_clipped);
614 uint32_t i_height = RECTHeight(sys->rect_dest_clipped);
615 #if VLC_WINSTORE_APP
616 UINT dataSize = sizeof(i_width);
617 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, &i_width);
618 if (FAILED(hr)) {
619 msg_Err(vd, "Can't get swapchain width, size %d. (hr=0x%lX)", hr, dataSize);
620 return hr;
622 dataSize = sizeof(i_height);
623 hr = IDXGISwapChain_GetPrivateData(sys->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, &i_height);
624 if (FAILED(hr)) {
625 msg_Err(vd, "Can't get swapchain height, size %d. (hr=0x%lX)", hr, dataSize);
626 return hr;
628 #endif
630 if (sys->d3drenderTargetView) {
631 ID3D11RenderTargetView_Release(sys->d3drenderTargetView);
632 sys->d3drenderTargetView = NULL;
634 if (sys->d3ddepthStencilView) {
635 ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
636 sys->d3ddepthStencilView = NULL;
639 hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
640 DXGI_FORMAT_UNKNOWN, 0);
641 if (FAILED(hr)) {
642 msg_Err(vd, "Failed to resize the backbuffer. (hr=0x%lX)", hr);
643 return hr;
646 hr = IDXGISwapChain_GetBuffer(sys->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *)&pBackBuffer);
647 if (FAILED(hr)) {
648 msg_Err(vd, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr);
649 return hr;
652 hr = ID3D11Device_CreateRenderTargetView(sys->d3ddevice, (ID3D11Resource *)pBackBuffer, NULL, &sys->d3drenderTargetView);
653 ID3D11Texture2D_Release(pBackBuffer);
654 if (FAILED(hr)) {
655 msg_Err(vd, "Failed to create the target view. (hr=0x%lX)", hr);
656 return hr;
659 D3D11_TEXTURE2D_DESC deptTexDesc;
660 memset(&deptTexDesc, 0,sizeof(deptTexDesc));
661 deptTexDesc.ArraySize = 1;
662 deptTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
663 deptTexDesc.CPUAccessFlags = 0;
664 deptTexDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
665 deptTexDesc.Width = i_width;
666 deptTexDesc.Height = i_height;
667 deptTexDesc.MipLevels = 1;
668 deptTexDesc.MiscFlags = 0;
669 deptTexDesc.SampleDesc.Count = 1;
670 deptTexDesc.SampleDesc.Quality = 0;
671 deptTexDesc.Usage = D3D11_USAGE_DEFAULT;
673 hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &deptTexDesc, NULL, &pDepthStencil);
674 if (FAILED(hr)) {
675 msg_Err(vd, "Could not create the depth stencil texture. (hr=0x%lX)", hr);
676 return hr;
679 D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDesc;
680 memset(&depthViewDesc, 0, sizeof(depthViewDesc));
682 depthViewDesc.Format = deptTexDesc.Format;
683 depthViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
684 depthViewDesc.Texture2D.MipSlice = 0;
686 hr = ID3D11Device_CreateDepthStencilView(sys->d3ddevice, (ID3D11Resource *)pDepthStencil, &depthViewDesc, &sys->d3ddepthStencilView);
687 ID3D11Texture2D_Release(pDepthStencil);
689 if (FAILED(hr)) {
690 msg_Err(vd, "Could not create the depth stencil view. (hr=0x%lX)", hr);
691 return hr;
694 return S_OK;
697 /* rotation around the Z axis */
698 static void getZRotMatrix(float theta, FLOAT matrix[static 16])
700 float st, ct;
702 sincosf(theta, &st, &ct);
704 const FLOAT m[] = {
705 /* x y z w */
706 ct, -st, 0.f, 0.f,
707 st, ct, 0.f, 0.f,
708 0.f, 0.f, 1.f, 0.f,
709 0.f, 0.f, 0.f, 1.f
712 memcpy(matrix, m, sizeof(m));
715 /* rotation around the Y axis */
716 static void getYRotMatrix(float theta, FLOAT matrix[static 16])
718 float st, ct;
720 sincosf(theta, &st, &ct);
722 const FLOAT m[] = {
723 /* x y z w */
724 ct, 0.f, -st, 0.f,
725 0.f, 1.f, 0.f, 0.f,
726 st, 0.f, ct, 0.f,
727 0.f, 0.f, 0.f, 1.f
730 memcpy(matrix, m, sizeof(m));
733 /* rotation around the X axis */
734 static void getXRotMatrix(float phi, FLOAT matrix[static 16])
736 float sp, cp;
738 sincosf(phi, &sp, &cp);
740 const FLOAT m[] = {
741 /* x y z w */
742 1.f, 0.f, 0.f, 0.f,
743 0.f, cp, sp, 0.f,
744 0.f, -sp, cp, 0.f,
745 0.f, 0.f, 0.f, 1.f
748 memcpy(matrix, m, sizeof(m));
751 static void getZoomMatrix(float zoom, FLOAT matrix[static 16]) {
753 const FLOAT m[] = {
754 /* x y z w */
755 1.0f, 0.0f, 0.0f, 0.0f,
756 0.0f, 1.0f, 0.0f, 0.0f,
757 0.0f, 0.0f, 1.0f, 0.0f,
758 0.0f, 0.0f, zoom, 1.0f
761 memcpy(matrix, m, sizeof(m));
764 /* perspective matrix see https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml */
765 static void getProjectionMatrix(float sar, float fovy, FLOAT matrix[static 16]) {
767 float zFar = 1000;
768 float zNear = 0.01;
770 float f = 1.f / tanf(fovy / 2.f);
772 const FLOAT m[] = {
773 f / sar, 0.f, 0.f, 0.f,
774 0.f, f, 0.f, 0.f,
775 0.f, 0.f, (zNear + zFar) / (zNear - zFar), -1.f,
776 0.f, 0.f, (2 * zNear * zFar) / (zNear - zFar), 0.f};
778 memcpy(matrix, m, sizeof(m));
781 static float UpdateFOVy(float f_fovx, float f_sar)
783 return 2 * atanf(tanf(f_fovx / 2) / f_sar);
786 static float UpdateZ(float f_fovx, float f_fovy)
788 /* Do trigonometry to calculate the minimal z value
789 * that will allow us to zoom out without seeing the outside of the
790 * sphere (black borders). */
791 float tan_fovx_2 = tanf(f_fovx / 2);
792 float tan_fovy_2 = tanf(f_fovy / 2);
793 float z_min = - SPHERE_RADIUS / sinf(atanf(sqrtf(
794 tan_fovx_2 * tan_fovx_2 + tan_fovy_2 * tan_fovy_2)));
796 /* The FOV value above which z is dynamically calculated. */
797 const float z_thresh = 90.f;
799 float f_z;
800 if (f_fovx <= z_thresh * M_PI / 180)
801 f_z = 0;
802 else
804 float f = z_min / ((FIELD_OF_VIEW_DEGREES_MAX - z_thresh) * M_PI / 180);
805 f_z = f * f_fovx - f * z_thresh * M_PI / 180;
806 if (f_z < z_min)
807 f_z = z_min;
809 return f_z;
812 static void SetQuadVSProjection(vout_display_t *vd, d3d_quad_t *quad, const vlc_viewpoint_t *p_vp)
814 if (!quad->pVertexShaderConstants)
815 return;
817 #define RAD(d) ((float) ((d) * M_PI / 180.f))
818 float f_fovx = RAD(p_vp->fov);
819 if ( f_fovx > FIELD_OF_VIEW_DEGREES_MAX * M_PI / 180 + 0.001f ||
820 f_fovx < -0.001f )
821 return;
823 float f_sar = (float) vd->cfg->display.width / vd->cfg->display.height;
824 float f_teta = RAD(p_vp->yaw) - (float) M_PI_2;
825 float f_phi = RAD(p_vp->pitch);
826 float f_roll = RAD(p_vp->roll);
827 float f_fovy = UpdateFOVy(f_fovx, f_sar);
828 float f_z = UpdateZ(f_fovx, f_fovy);
830 vout_display_sys_t *sys = vd->sys;
831 HRESULT hr;
832 D3D11_MAPPED_SUBRESOURCE mapped;
833 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pVertexShaderConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
834 if (SUCCEEDED(hr)) {
835 VS_PROJECTION_CONST *dst_data = mapped.pData;
836 getXRotMatrix(f_phi, dst_data->RotX);
837 getYRotMatrix(f_teta, dst_data->RotY);
838 getZRotMatrix(f_roll, dst_data->RotZ);
839 getZoomMatrix(SPHERE_RADIUS * f_z, dst_data->View);
840 getProjectionMatrix(f_sar, f_fovy, dst_data->Projection);
842 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexShaderConstants, 0);
843 #undef RAD
846 static void CropStagingFormat(vout_display_t *vd, video_format_t *backup_fmt)
848 if ( vd->sys->stagingQuad.pTexture == NULL )
849 return;
851 video_format_Copy( backup_fmt, &vd->source );
852 /* the texture we display is a cropped version of the source */
853 vd->source.i_x_offset = 0;
854 vd->source.i_y_offset = 0;
855 vd->source.i_width = vd->source.i_visible_width;
856 vd->source.i_height = vd->source.i_visible_height;
859 static void UncropStagingFormat(vout_display_t *vd, video_format_t *backup_fmt)
861 if ( vd->sys->stagingQuad.pTexture == NULL )
862 return;
863 video_format_Copy( &vd->source, backup_fmt );
866 static int Control(vout_display_t *vd, int query, va_list args)
868 video_format_t core_source;
869 CropStagingFormat( vd, &core_source );
870 int res = CommonControl( vd, query, args );
872 if (query == VOUT_DISPLAY_CHANGE_VIEWPOINT)
874 const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t*);
875 if ( vd->sys->picQuad.pVertexShaderConstants )
877 SetQuadVSProjection( vd, &vd->sys->picQuad, &cfg->viewpoint );
878 res = VLC_SUCCESS;
882 UncropStagingFormat( vd, &core_source );
883 return res;
886 static void Manage(vout_display_t *vd)
888 vout_display_sys_t *sys = vd->sys;
889 RECT size_before = sys->rect_dest_clipped;
891 video_format_t core_source;
892 CropStagingFormat( vd, &core_source );
893 CommonManage(vd);
895 if (RECTWidth(size_before) != RECTWidth(sys->rect_dest_clipped) ||
896 RECTHeight(size_before) != RECTHeight(sys->rect_dest_clipped))
898 #if defined(HAVE_ID3D11VIDEODECODER)
899 if( sys->context_lock != INVALID_HANDLE_VALUE )
901 WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
903 #endif
904 msg_Dbg(vd, "Manage detected size change %dx%d", RECTWidth(sys->rect_dest_clipped),
905 RECTHeight(sys->rect_dest_clipped));
907 UpdateBackBuffer(vd);
909 UpdatePicQuadPosition(vd);
910 #if defined(HAVE_ID3D11VIDEODECODER)
911 if( sys->context_lock != INVALID_HANDLE_VALUE )
913 ReleaseMutex( sys->context_lock );
915 #endif
917 UncropStagingFormat( vd, &core_source );
920 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
922 vout_display_sys_t *sys = vd->sys;
924 if ( !is_d3d11_opaque(picture->format.i_chroma) &&
925 sys->stagingQuad.pTexture != NULL )
927 Direct3D11UnmapTexture(picture);
929 D3D11_BOX box;
930 box.left = picture->format.i_x_offset;
931 /* box.right = picture->format.i_x_offset + picture->format.i_visible_width; */
932 box.top = picture->format.i_y_offset;
933 /* box.bottom = picture->format.i_y_offset + picture->format.i_visible_height; */
934 box.back = 1;
935 box.front = 0;
937 D3D11_TEXTURE2D_DESC dstDesc;
938 ID3D11Texture2D_GetDesc(sys->picQuad.pTexture, &dstDesc);
939 box.bottom = box.top + dstDesc.Height;
940 box.right = box.left + dstDesc.Width;
942 ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
943 (ID3D11Resource*) sys->picQuad.pTexture,
944 0, 0, 0, 0,
945 (ID3D11Resource*) sys->stagingQuad.pTexture,
946 0, &box);
949 #ifdef HAVE_ID3D11VIDEODECODER
950 if (is_d3d11_opaque(picture->format.i_chroma)) {
951 if( sys->context_lock != INVALID_HANDLE_VALUE )
953 WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
955 D3D11_BOX box;
956 picture_sys_t *p_sys = picture->p_sys;
957 D3D11_TEXTURE2D_DESC texDesc;
958 ID3D11Texture2D_GetDesc( p_sys->texture, &texDesc );
959 if (texDesc.Format == DXGI_FORMAT_NV12 || texDesc.Format == DXGI_FORMAT_P010)
961 box.left = (picture->format.i_x_offset + 1) & ~1;
962 box.right = (picture->format.i_x_offset + picture->format.i_visible_width) & ~1;
963 box.top = (picture->format.i_y_offset + 1) & ~1;
964 box.bottom = (picture->format.i_y_offset + picture->format.i_visible_height) & ~1;
966 else
968 box.left = picture->format.i_x_offset;
969 box.right = picture->format.i_x_offset + picture->format.i_visible_width;
970 box.top = picture->format.i_y_offset;
971 box.bottom = picture->format.i_y_offset + picture->format.i_visible_height;
973 box.back = 1;
974 box.front = 0;
976 ID3D11DeviceContext_CopySubresourceRegion(sys->d3dcontext,
977 (ID3D11Resource*) sys->picQuad.pTexture,
978 0, 0, 0, 0,
979 (ID3D11Resource*) p_sys->texture,
980 p_sys->slice_index, &box);
982 #endif
984 if (subpicture) {
985 int subpicture_region_count = 0;
986 picture_t **subpicture_regions = NULL;
987 Direct3D11MapSubpicture(vd, &subpicture_region_count, &subpicture_regions, subpicture);
988 Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
989 sys->d3dregion_count = subpicture_region_count;
990 sys->d3dregions = subpicture_regions;
994 static void DisplayD3DPicture(vout_display_sys_t *sys, d3d_quad_t *quad)
996 UINT stride = sizeof(d3d_vertex_t);
997 UINT offset = 0;
999 /* Render the quad */
1000 /* vertex shader */
1001 ID3D11DeviceContext_IASetVertexBuffers(sys->d3dcontext, 0, 1, &quad->pVertexBuffer, &stride, &offset);
1002 ID3D11DeviceContext_IASetIndexBuffer(sys->d3dcontext, quad->pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
1003 if ( quad->pVertexShaderConstants )
1004 ID3D11DeviceContext_VSSetConstantBuffers(sys->d3dcontext, 0, 1, &quad->pVertexShaderConstants);
1006 ID3D11DeviceContext_VSSetShader(sys->d3dcontext, quad->d3dvertexShader, NULL, 0);
1008 /* pixel shader */
1009 ID3D11DeviceContext_PSSetShader(sys->d3dcontext, quad->d3dpixelShader, NULL, 0);
1011 ID3D11DeviceContext_PSSetConstantBuffers(sys->d3dcontext, 0, quad->PSConstantsCount, quad->pPixelShaderConstants);
1012 ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 0, 1, &quad->d3dresViewY);
1013 if( quad->d3dresViewUV )
1014 ID3D11DeviceContext_PSSetShaderResources(sys->d3dcontext, 1, 1, &quad->d3dresViewUV);
1016 ID3D11DeviceContext_RSSetViewports(sys->d3dcontext, 1, &quad->cropViewport);
1018 ID3D11DeviceContext_DrawIndexed(sys->d3dcontext, quad->indexCount, 0, 0);
1021 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
1023 vout_display_sys_t *sys = vd->sys;
1025 FLOAT blackRGBA[4] = {0.0f, 0.0f, 0.0f, 1.0f};
1026 ID3D11DeviceContext_ClearRenderTargetView(sys->d3dcontext, sys->d3drenderTargetView, blackRGBA);
1028 /* no ID3D11Device operations should come here */
1030 ID3D11DeviceContext_OMSetRenderTargets(sys->d3dcontext, 1, &sys->d3drenderTargetView, sys->d3ddepthStencilView);
1032 ID3D11DeviceContext_ClearDepthStencilView(sys->d3dcontext, sys->d3ddepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
1034 if ( !is_d3d11_opaque(picture->format.i_chroma) &&
1035 sys->stagingQuad.pTexture == NULL )
1036 Direct3D11UnmapTexture(picture);
1038 /* Render the quad */
1039 DisplayD3DPicture(sys, &sys->picQuad);
1041 if (subpicture) {
1042 // draw the additional vertices
1043 for (int i = 0; i < sys->d3dregion_count; ++i) {
1044 if (sys->d3dregions[i])
1045 DisplayD3DPicture(sys, (d3d_quad_t *) sys->d3dregions[i]->p_sys);
1049 DXGI_PRESENT_PARAMETERS presentParams;
1050 memset(&presentParams, 0, sizeof(presentParams));
1051 HRESULT hr = IDXGISwapChain1_Present1(sys->dxgiswapChain, 0, 0, &presentParams);
1052 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
1054 /* TODO device lost */
1055 msg_Dbg(vd, "SwapChain Present failed. (hr=0x%lX)", hr);
1057 #if defined(HAVE_ID3D11VIDEODECODER)
1058 if( is_d3d11_opaque(picture->format.i_chroma) && sys->context_lock != INVALID_HANDLE_VALUE) {
1059 ReleaseMutex( sys->context_lock );
1061 #endif
1063 picture_Release(picture);
1064 if (subpicture)
1065 subpicture_Delete(subpicture);
1067 CommonDisplay(vd);
1070 static void Direct3D11Destroy(vout_display_t *vd)
1072 #if !VLC_WINSTORE_APP
1073 vout_display_sys_t *sys = vd->sys;
1075 if (sys->hd3d11_dll)
1076 FreeLibrary(sys->hd3d11_dll);
1077 if (sys->hd3dcompiler_dll)
1078 FreeLibrary(sys->hd3dcompiler_dll);
1080 sys->OurD3D11CreateDevice = NULL;
1081 sys->OurD3D11CreateDeviceAndSwapChain = NULL;
1082 sys->OurD3DCompile = NULL;
1083 sys->hdxgi_dll = NULL;
1084 sys->hd3d11_dll = NULL;
1085 sys->hd3dcompiler_dll = NULL;
1086 #else
1087 VLC_UNUSED(vd);
1088 #endif
1091 #if !VLC_WINSTORE_APP
1092 static HINSTANCE Direct3D11LoadShaderLibrary(void)
1094 HINSTANCE instance = NULL;
1095 /* d3dcompiler_47 is the latest on windows 8.1 */
1096 for (int i = 47; i > 41; --i) {
1097 TCHAR filename[19];
1098 _sntprintf(filename, 19, TEXT("D3DCOMPILER_%d.dll"), i);
1099 instance = LoadLibrary(filename);
1100 if (instance) break;
1102 return instance;
1104 #endif
1107 static int Direct3D11Open(vout_display_t *vd, video_format_t *fmt)
1109 vout_display_sys_t *sys = vd->sys;
1110 *fmt = vd->source;
1112 #if !VLC_WINSTORE_APP
1114 UINT creationFlags = 0;
1115 HRESULT hr = S_OK;
1117 # if !defined(NDEBUG) && defined(_MSC_VER)
1118 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
1119 # endif
1121 DXGI_SWAP_CHAIN_DESC1 scd;
1122 memset(&scd, 0, sizeof(scd));
1123 scd.BufferCount = 2;
1124 scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1125 scd.SampleDesc.Count = 1;
1126 scd.SampleDesc.Quality = 0;
1127 scd.Width = fmt->i_visible_width;
1128 scd.Height = fmt->i_visible_height;
1129 switch(fmt->i_chroma)
1131 case VLC_CODEC_D3D11_OPAQUE_10B:
1132 scd.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
1133 break;
1134 default:
1135 scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; /* TODO: use DXGI_FORMAT_NV12 */
1136 break;
1138 //scd.Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
1139 scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
1141 IDXGIAdapter *dxgiadapter;
1142 static const D3D_FEATURE_LEVEL featureLevels[] =
1144 0xc000 /* D3D_FEATURE_LEVEL_12_1 */,
1145 0xc100 /* D3D_FEATURE_LEVEL_12_0 */,
1146 D3D_FEATURE_LEVEL_11_1,
1147 D3D_FEATURE_LEVEL_11_0,
1148 D3D_FEATURE_LEVEL_10_1,
1149 D3D_FEATURE_LEVEL_10_0,
1150 D3D_FEATURE_LEVEL_9_3,
1151 D3D_FEATURE_LEVEL_9_2,
1152 D3D_FEATURE_LEVEL_9_1,
1155 static const D3D_DRIVER_TYPE driverAttempts[] = {
1156 D3D_DRIVER_TYPE_HARDWARE,
1157 D3D_DRIVER_TYPE_WARP,
1158 #ifndef NDEBUG
1159 D3D_DRIVER_TYPE_REFERENCE,
1160 #endif
1163 for (UINT driver = 0; driver < ARRAYSIZE(driverAttempts); driver++) {
1164 D3D_FEATURE_LEVEL i_feature_level;
1165 hr = D3D11CreateDevice(NULL, driverAttempts[driver], NULL, creationFlags,
1166 featureLevels, 9, D3D11_SDK_VERSION,
1167 &sys->d3ddevice, &i_feature_level, &sys->d3dcontext);
1168 if (SUCCEEDED(hr)) {
1169 #ifndef NDEBUG
1170 msg_Dbg(vd, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
1171 (void *)sys->d3ddevice, (void *)sys->d3dcontext,
1172 driverAttempts[driver], i_feature_level);
1173 #endif
1174 break;
1178 if (FAILED(hr)) {
1179 msg_Err(vd, "Could not Create the D3D11 device. (hr=0x%lX)", hr);
1180 return VLC_EGENERIC;
1183 IDXGIDevice *pDXGIDevice = NULL;
1184 hr = ID3D11Device_QueryInterface(sys->d3ddevice, &IID_IDXGIDevice, (void **)&pDXGIDevice);
1185 if (FAILED(hr)) {
1186 msg_Err(vd, "Could not Query DXGI Interface. (hr=0x%lX)", hr);
1187 return VLC_EGENERIC;
1190 hr = IDXGIDevice_GetAdapter(pDXGIDevice, &dxgiadapter);
1191 IDXGIAdapter_Release(pDXGIDevice);
1192 if (FAILED(hr)) {
1193 msg_Err(vd, "Could not get the DXGI Adapter. (hr=0x%lX)", hr);
1194 return VLC_EGENERIC;
1197 hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&sys->dxgifactory);
1198 IDXGIAdapter_Release(dxgiadapter);
1199 if (FAILED(hr)) {
1200 msg_Err(vd, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
1201 return VLC_EGENERIC;
1204 hr = IDXGIFactory2_CreateSwapChainForHwnd(sys->dxgifactory, (IUnknown *)sys->d3ddevice,
1205 sys->hvideownd, &scd, NULL, NULL, &sys->dxgiswapChain);
1206 IDXGIFactory2_Release(sys->dxgifactory);
1207 if (FAILED(hr)) {
1208 msg_Err(vd, "Could not create the SwapChain. (hr=0x%lX)", hr);
1209 return VLC_EGENERIC;
1211 #endif
1213 vlc_fourcc_t i_src_chroma = fmt->i_chroma;
1214 fmt->i_chroma = 0;
1216 // look for the requested pixel format first
1217 UINT i_quadSupportFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_LOAD;
1218 UINT i_formatSupport;
1219 for (const d3d_format_t *output_format = GetRenderFormatList();
1220 output_format->name != NULL; ++output_format)
1222 if( i_src_chroma == output_format->fourcc )
1224 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1225 output_format->formatTexture,
1226 &i_formatSupport)) &&
1227 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
1229 msg_Dbg( vd, "Using pixel format %s from chroma %4.4s", output_format->name,
1230 (char *)&i_src_chroma );
1231 fmt->i_chroma = output_format->fourcc;
1232 DxgiFormatMask( output_format->formatTexture, fmt );
1233 sys->picQuadConfig.textureFormat = output_format->formatTexture;
1234 sys->picQuadConfig.resourceFormatYRGB = output_format->formatY;
1235 sys->picQuadConfig.resourceFormatUV = output_format->formatUV;
1236 break;
1241 // look for any pixel format that we can handle with enough pixels per channel
1242 if ( !fmt->i_chroma )
1244 uint8_t bits_per_channel;
1245 switch (i_src_chroma)
1247 case VLC_CODEC_D3D11_OPAQUE:
1248 bits_per_channel = 8;
1249 break;
1250 case VLC_CODEC_D3D11_OPAQUE_10B:
1251 bits_per_channel = 10;
1252 break;
1253 default:
1255 const vlc_chroma_description_t *p_format = vlc_fourcc_GetChromaDescription(i_src_chroma);
1256 bits_per_channel = p_format == NULL || p_format->pixel_bits == 0 ? 8 : p_format->pixel_bits;
1258 break;
1261 for (const d3d_format_t *output_format = GetRenderFormatList();
1262 output_format->name != NULL; ++output_format)
1264 if( bits_per_channel <= output_format->bitsPerChannel &&
1265 !is_d3d11_opaque(output_format->fourcc) )
1267 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1268 output_format->formatTexture,
1269 &i_formatSupport)) &&
1270 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags )
1272 msg_Dbg( vd, "Using pixel format %s for chroma %4.4s", output_format->name,
1273 (char *)&i_src_chroma );
1274 fmt->i_chroma = output_format->fourcc;
1275 DxgiFormatMask( output_format->formatTexture, fmt );
1276 sys->picQuadConfig.textureFormat = output_format->formatTexture;
1277 sys->picQuadConfig.resourceFormatYRGB = output_format->formatY;
1278 sys->picQuadConfig.resourceFormatUV = output_format->formatUV;
1279 break;
1284 // look for any pixel format that we can handle
1285 if ( !fmt->i_chroma )
1287 for (const d3d_format_t *output_format = GetRenderFormatList();
1288 output_format->name != NULL; ++output_format)
1290 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1291 output_format->formatTexture,
1292 &i_formatSupport)) &&
1293 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags &&
1294 !is_d3d11_opaque(output_format->fourcc) )
1296 msg_Dbg( vd, "Using pixel format %s for chroma %4.4s", output_format->name,
1297 (char *)&i_src_chroma );
1298 fmt->i_chroma = output_format->fourcc;
1299 DxgiFormatMask( output_format->formatTexture, fmt );
1300 sys->picQuadConfig.textureFormat = output_format->formatTexture;
1301 sys->picQuadConfig.resourceFormatYRGB = output_format->formatY;
1302 sys->picQuadConfig.resourceFormatUV = output_format->formatUV;
1303 break;
1307 if ( !fmt->i_chroma )
1309 msg_Err(vd, "Could not get a suitable texture pixel format");
1310 return VLC_EGENERIC;
1313 /* check the region pixel format */
1314 i_quadSupportFlags |= D3D11_FORMAT_SUPPORT_BLENDABLE;
1315 if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1316 DXGI_FORMAT_R8G8B8A8_UNORM,
1317 &i_formatSupport)) &&
1318 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags) {
1319 sys->d3dregion_format = DXGI_FORMAT_R8G8B8A8_UNORM;
1320 sys->pSubpictureChromas[0] = VLC_CODEC_RGBA;
1321 sys->pSubpictureChromas[1] = 0;
1322 } else if( SUCCEEDED( ID3D11Device_CheckFormatSupport(sys->d3ddevice,
1323 DXGI_FORMAT_B8G8R8A8_UNORM,
1324 &i_formatSupport)) &&
1325 ( i_formatSupport & i_quadSupportFlags ) == i_quadSupportFlags) {
1326 sys->d3dregion_format = DXGI_FORMAT_B8G8R8A8_UNORM;
1327 sys->pSubpictureChromas[0] = VLC_CODEC_BGRA;
1328 sys->pSubpictureChromas[1] = 0;
1329 } else {
1330 sys->d3dregion_format = DXGI_FORMAT_UNKNOWN;
1333 if (sys->picQuadConfig.resourceFormatYRGB == DXGI_FORMAT_R8_UNORM ||
1334 sys->picQuadConfig.resourceFormatYRGB == DXGI_FORMAT_R16_UNORM)
1335 sys->d3dPxShader = globPixelShaderBiplanarYUV_2RGB;
1336 else
1337 if (fmt->i_chroma == VLC_CODEC_YUYV)
1338 sys->d3dPxShader = globPixelShaderBiplanarYUYV_2RGB;
1339 else
1340 sys->d3dPxShader = globPixelShaderDefault;
1342 if (sys->d3dregion_format != DXGI_FORMAT_UNKNOWN)
1343 sys->psz_rgbaPxShader = globPixelShaderDefault;
1344 else
1345 sys->psz_rgbaPxShader = NULL;
1347 if ( fmt->i_height != fmt->i_visible_height || fmt->i_width != fmt->i_visible_width )
1349 msg_Dbg( vd, "use a staging texture to crop to visible size" );
1350 AllocQuad( vd, fmt, &sys->stagingQuad, &sys->picQuadConfig, NULL, false,
1351 PROJECTION_MODE_RECTANGULAR );
1354 video_format_t core_source;
1355 CropStagingFormat( vd, &core_source );
1356 UpdateRects(vd, NULL, NULL, true);
1357 UncropStagingFormat( vd, &core_source );
1359 #if defined(HAVE_ID3D11VIDEODECODER)
1360 if( sys->context_lock != INVALID_HANDLE_VALUE )
1362 WaitForSingleObjectEx( sys->context_lock, INFINITE, FALSE );
1364 #endif
1365 if (Direct3D11CreateResources(vd, fmt)) {
1366 #if defined(HAVE_ID3D11VIDEODECODER)
1367 if( sys->context_lock != INVALID_HANDLE_VALUE )
1369 ReleaseMutex( sys->context_lock );
1371 #endif
1372 msg_Err(vd, "Failed to allocate resources");
1373 Direct3D11DestroyResources(vd);
1374 return VLC_EGENERIC;
1376 #if defined(HAVE_ID3D11VIDEODECODER)
1377 if( sys->context_lock != INVALID_HANDLE_VALUE )
1379 ReleaseMutex( sys->context_lock );
1381 #endif
1383 #if !VLC_WINSTORE_APP
1384 EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D11 output)");
1385 #endif
1387 msg_Dbg(vd, "Direct3D11 device adapter successfully initialized");
1388 return VLC_SUCCESS;
1391 static void Direct3D11Close(vout_display_t *vd)
1393 vout_display_sys_t *sys = vd->sys;
1395 Direct3D11DestroyResources(vd);
1396 if (sys->d3dcontext)
1398 ID3D11DeviceContext_Flush(sys->d3dcontext);
1399 ID3D11DeviceContext_Release(sys->d3dcontext);
1400 sys->d3dcontext = NULL;
1402 if (sys->d3ddevice)
1404 ID3D11Device_Release(sys->d3ddevice);
1405 sys->d3ddevice = NULL;
1407 if (sys->dxgiswapChain)
1409 IDXGISwapChain_Release(sys->dxgiswapChain);
1410 sys->dxgiswapChain = NULL;
1413 msg_Dbg(vd, "Direct3D11 device adapter closed");
1416 static void UpdatePicQuadPosition(vout_display_t *vd)
1418 vout_display_sys_t *sys = vd->sys;
1419 int i_width = RECTWidth(sys->rect_dest_clipped);
1420 int i_height = RECTHeight(sys->rect_dest_clipped);
1422 int i_top = sys->rect_src_clipped.top * i_height;
1423 i_top /= vd->source.i_visible_height;
1424 i_top -= sys->rect_dest_clipped.top;
1425 int i_left = sys->rect_src_clipped.left * i_width;
1426 i_left /= vd->source.i_visible_width;
1427 i_left -= sys->rect_dest_clipped.left;
1429 sys->picQuad.cropViewport.Width = (FLOAT) vd->source.i_width * i_width / vd->source.i_visible_width;
1430 sys->picQuad.cropViewport.Height = (FLOAT) vd->source.i_height * i_height / vd->source.i_visible_height;
1431 sys->picQuad.cropViewport.TopLeftX = -i_left;
1432 sys->picQuad.cropViewport.TopLeftY = -i_top;
1434 sys->picQuad.cropViewport.MinDepth = 0.0f;
1435 sys->picQuad.cropViewport.MaxDepth = 1.0f;
1437 SetQuadVSProjection(vd, &sys->picQuad, &vd->cfg->viewpoint);
1439 #ifndef NDEBUG
1440 msg_Dbg(vd, "picQuad position (%.02f,%.02f) %.02fx%.02f", sys->picQuad.cropViewport.TopLeftX, sys->picQuad.cropViewport.TopLeftY, sys->picQuad.cropViewport.Width, sys->picQuad.cropViewport.Height );
1441 #endif
1444 /* TODO : handle errors better
1445 TODO : seperate out into smaller functions like createshaders */
1446 static int Direct3D11CreateResources(vout_display_t *vd, video_format_t *fmt)
1448 vout_display_sys_t *sys = vd->sys;
1449 HRESULT hr;
1451 #if defined(HAVE_ID3D11VIDEODECODER)
1452 sys->context_lock = CreateMutexEx( NULL, NULL, 0, SYNCHRONIZE );
1453 ID3D11Device_SetPrivateData( sys->d3ddevice, &GUID_CONTEXT_MUTEX, sizeof( sys->context_lock ), &sys->context_lock );
1454 #endif
1456 hr = UpdateBackBuffer(vd);
1457 if (FAILED(hr)) {
1458 msg_Err(vd, "Could not update the backbuffer. (hr=0x%lX)", hr);
1459 return VLC_EGENERIC;
1462 ID3D11BlendState *pSpuBlendState;
1463 D3D11_BLEND_DESC spuBlendDesc = { 0 };
1464 spuBlendDesc.RenderTarget[0].BlendEnable = TRUE;
1465 spuBlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
1466 spuBlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
1467 spuBlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
1469 spuBlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1470 spuBlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
1471 spuBlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1473 spuBlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1475 spuBlendDesc.RenderTarget[1].BlendEnable = TRUE;
1476 spuBlendDesc.RenderTarget[1].SrcBlend = D3D11_BLEND_ONE;
1477 spuBlendDesc.RenderTarget[1].DestBlend = D3D11_BLEND_ZERO;
1478 spuBlendDesc.RenderTarget[1].BlendOp = D3D11_BLEND_OP_ADD;
1480 spuBlendDesc.RenderTarget[1].SrcBlendAlpha = D3D11_BLEND_ONE;
1481 spuBlendDesc.RenderTarget[1].DestBlendAlpha = D3D11_BLEND_ZERO;
1482 spuBlendDesc.RenderTarget[1].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1484 spuBlendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1485 hr = ID3D11Device_CreateBlendState(sys->d3ddevice, &spuBlendDesc, &pSpuBlendState);
1486 if (FAILED(hr)) {
1487 msg_Err(vd, "Could not create SPU blend state. (hr=0x%lX)", hr);
1488 return VLC_EGENERIC;
1490 ID3D11DeviceContext_OMSetBlendState(sys->d3dcontext, pSpuBlendState, NULL, 0xFFFFFFFF);
1491 ID3D11BlendState_Release(pSpuBlendState);
1493 /* disable depth testing as we're only doing 2D
1494 * see https://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx
1495 * see http://rastertek.com/dx11tut11.html
1497 D3D11_DEPTH_STENCIL_DESC stencilDesc;
1498 ZeroMemory(&stencilDesc, sizeof(stencilDesc));
1500 ID3D11DepthStencilState *pDepthStencilState;
1501 hr = ID3D11Device_CreateDepthStencilState(sys->d3ddevice, &stencilDesc, &pDepthStencilState );
1502 if (SUCCEEDED(hr)) {
1503 ID3D11DeviceContext_OMSetDepthStencilState(sys->d3dcontext, pDepthStencilState, 0);
1504 ID3D11DepthStencilState_Release(pDepthStencilState);
1507 ID3DBlob* pVSBlob = NULL;
1508 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1509 hr = D3DCompile(globVertexShaderFlat, strlen(globVertexShaderFlat),
1510 NULL, NULL, NULL, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob, NULL);
1512 if( FAILED(hr)) {
1513 msg_Err(vd, "The flat Vertex Shader is invalid. (hr=0x%lX)", hr);
1514 return VLC_EGENERIC;
1517 hr = ID3D11Device_CreateVertexShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
1518 ID3D10Blob_GetBufferSize(pVSBlob), NULL, &sys->flatVSShader);
1520 if(FAILED(hr)) {
1521 ID3D11Device_Release(pVSBlob);
1522 msg_Err(vd, "Failed to create the flat vertex shader. (hr=0x%lX)", hr);
1523 return VLC_EGENERIC;
1526 D3D11_INPUT_ELEMENT_DESC layout[] = {
1527 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
1528 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
1531 ID3D11InputLayout* pVertexLayout = NULL;
1532 hr = ID3D11Device_CreateInputLayout(sys->d3ddevice, layout, 2, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
1533 ID3D10Blob_GetBufferSize(pVSBlob), &pVertexLayout);
1535 ID3D10Blob_Release(pVSBlob);
1537 if(FAILED(hr)) {
1538 msg_Err(vd, "Failed to create the vertex input layout. (hr=0x%lX)", hr);
1539 return VLC_EGENERIC;
1541 ID3D11DeviceContext_IASetInputLayout(sys->d3dcontext, pVertexLayout);
1542 ID3D11InputLayout_Release(pVertexLayout);
1544 hr = D3DCompile(globVertexShaderProjection, strlen(globVertexShaderProjection),
1545 NULL, NULL, NULL, "VS", "vs_4_0_level_9_1", 0, 0, &pVSBlob, NULL);
1547 if( FAILED(hr)) {
1548 msg_Err(vd, "The projection Vertex Shader is invalid. (hr=0x%lX)", hr);
1549 return VLC_EGENERIC;
1552 hr = ID3D11Device_CreateVertexShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pVSBlob),
1553 ID3D10Blob_GetBufferSize(pVSBlob), NULL, &sys->projectionVSShader);
1555 if(FAILED(hr)) {
1556 ID3D11Device_Release(pVSBlob);
1557 msg_Err(vd, "Failed to create the projection vertex shader. (hr=0x%lX)", hr);
1558 return VLC_EGENERIC;
1560 ID3D10Blob_Release(pVSBlob);
1562 ID3D11DeviceContext_IASetPrimitiveTopology(sys->d3dcontext, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1564 ID3DBlob* pPSBlob = NULL;
1566 /* TODO : Match the version to the D3D_FEATURE_LEVEL */
1567 hr = D3DCompile(sys->d3dPxShader, strlen(sys->d3dPxShader),
1568 NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
1571 if( FAILED(hr)) {
1572 msg_Err(vd, "The Pixel Shader is invalid. (hr=0x%lX)", hr );
1573 return VLC_EGENERIC;
1576 ID3D11PixelShader *pPicQuadShader;
1577 hr = ID3D11Device_CreatePixelShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
1578 ID3D10Blob_GetBufferSize(pPSBlob), NULL, &pPicQuadShader);
1580 ID3D10Blob_Release(pPSBlob);
1582 if(FAILED(hr)) {
1583 msg_Err(vd, "Failed to create the pixel shader. (hr=0x%lX)", hr);
1584 return VLC_EGENERIC;
1587 if (sys->psz_rgbaPxShader != NULL)
1589 hr = D3DCompile(sys->psz_rgbaPxShader, strlen(sys->psz_rgbaPxShader),
1590 NULL, NULL, NULL, "PS", "ps_4_0_level_9_1", 0, 0, &pPSBlob, NULL);
1591 if( FAILED(hr)) {
1592 ID3D11PixelShader_Release(pPicQuadShader);
1593 msg_Err(vd, "The RGBA Pixel Shader is invalid. (hr=0x%lX)", hr );
1594 return VLC_EGENERIC;
1597 hr = ID3D11Device_CreatePixelShader(sys->d3ddevice, (void *)ID3D10Blob_GetBufferPointer(pPSBlob),
1598 ID3D10Blob_GetBufferSize(pPSBlob), NULL, &sys->pSPUPixelShader);
1600 ID3D10Blob_Release(pPSBlob);
1602 if(FAILED(hr)) {
1603 ID3D11PixelShader_Release(pPicQuadShader);
1604 msg_Err(vd, "Failed to create the SPU pixel shader. (hr=0x%lX)", hr);
1605 return VLC_EGENERIC;
1609 if (AllocQuad( vd, fmt, &sys->picQuad, &sys->picQuadConfig, pPicQuadShader,
1610 true, vd->fmt.projection_mode) != VLC_SUCCESS) {
1611 ID3D11PixelShader_Release(pPicQuadShader);
1612 msg_Err(vd, "Could not Create the main quad picture. (hr=0x%lX)", hr);
1613 return VLC_EGENERIC;
1615 ID3D11PixelShader_Release(pPicQuadShader);
1617 video_format_t core_source;
1618 CropStagingFormat( vd, &core_source );
1619 UpdatePicQuadPosition(vd);
1620 UncropStagingFormat( vd, &core_source );
1622 D3D11_SAMPLER_DESC sampDesc;
1623 memset(&sampDesc, 0, sizeof(sampDesc));
1624 sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
1625 sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
1626 sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
1627 sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
1628 sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
1629 sampDesc.MinLOD = 0;
1630 sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
1632 ID3D11SamplerState *d3dsampState;
1633 hr = ID3D11Device_CreateSamplerState(sys->d3ddevice, &sampDesc, &d3dsampState);
1635 if (FAILED(hr)) {
1636 msg_Err(vd, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr);
1637 return VLC_EGENERIC;
1639 ID3D11DeviceContext_PSSetSamplers(sys->d3dcontext, 0, 1, &d3dsampState);
1640 ID3D11SamplerState_Release(d3dsampState);
1642 if (Direct3D11CreatePool(vd, fmt))
1644 msg_Err(vd, "Direct3D picture pool initialization failed");
1645 return VLC_EGENERIC;
1648 msg_Dbg(vd, "Direct3D11 resources created");
1649 return VLC_SUCCESS;
1652 static int Direct3D11CreatePool(vout_display_t *vd, video_format_t *fmt)
1654 vout_display_sys_t *sys = vd->sys;
1656 if ( is_d3d11_opaque(fmt->i_chroma) )
1657 /* a D3D11VA pool will be created when needed */
1658 return VLC_SUCCESS;
1660 picture_sys_pool_t *picsys = calloc(1, sizeof(*picsys));
1661 if (unlikely(picsys == NULL)) {
1662 return VLC_ENOMEM;
1665 if ( sys->stagingQuad.pTexture != NULL )
1666 picsys->texture = sys->stagingQuad.pTexture;
1667 else
1668 picsys->texture = sys->picQuad.pTexture;
1669 picsys->vd = vd;
1671 picture_resource_t resource = {
1672 .p_sys = (picture_sys_t*) picsys,
1673 .pf_destroy = DestroyDisplayPicture,
1676 picture_t *picture = picture_NewFromResource(fmt, &resource);
1677 if (!picture) {
1678 free(picsys);
1679 return VLC_ENOMEM;
1681 ID3D11Texture2D_AddRef(picsys->texture);
1683 picture_pool_configuration_t pool_cfg;
1684 memset(&pool_cfg, 0, sizeof(pool_cfg));
1685 pool_cfg.picture_count = 1;
1686 pool_cfg.picture = &picture;
1687 pool_cfg.lock = Direct3D11MapTexture;
1688 //pool_cfg.unlock = Direct3D11UnmapTexture;
1690 sys->pool = picture_pool_NewExtended(&pool_cfg);
1691 if (!sys->pool) {
1692 picture_Release(picture);
1693 return VLC_ENOMEM;
1696 return VLC_SUCCESS;
1699 static void Direct3D11DestroyPool(vout_display_t *vd)
1701 vout_display_sys_t *sys = vd->sys;
1703 if (sys->pool)
1704 picture_pool_Release(sys->pool);
1705 sys->pool = NULL;
1708 static void SetupQuadFlat(d3d_vertex_t *dst_data, WORD *triangle_pos)
1710 float right = 1.0f;
1711 float left = -1.0f;
1712 float top = 1.0f;
1713 float bottom = -1.0f;
1715 // bottom left
1716 dst_data[0].position.x = left;
1717 dst_data[0].position.y = bottom;
1718 dst_data[0].position.z = 0.0f;
1719 dst_data[0].texture.x = 0.0f;
1720 dst_data[0].texture.y = 1.0f;
1722 // bottom right
1723 dst_data[1].position.x = right;
1724 dst_data[1].position.y = bottom;
1725 dst_data[1].position.z = 0.0f;
1726 dst_data[1].texture.x = 1.0f;
1727 dst_data[1].texture.y = 1.0f;
1729 // top right
1730 dst_data[2].position.x = right;
1731 dst_data[2].position.y = top;
1732 dst_data[2].position.z = 0.0f;
1733 dst_data[2].texture.x = 1.0f;
1734 dst_data[2].texture.y = 0.0f;
1736 // top left
1737 dst_data[3].position.x = left;
1738 dst_data[3].position.y = top;
1739 dst_data[3].position.z = 0.0f;
1740 dst_data[3].texture.x = 0.0f;
1741 dst_data[3].texture.y = 0.0f;
1743 triangle_pos[0] = 3;
1744 triangle_pos[1] = 1;
1745 triangle_pos[2] = 0;
1747 triangle_pos[3] = 2;
1748 triangle_pos[4] = 1;
1749 triangle_pos[5] = 3;
1752 #define SPHERE_SLICES 128
1753 #define nbLatBands SPHERE_SLICES
1754 #define nbLonBands SPHERE_SLICES
1756 static void SetupQuadSphere(d3d_vertex_t *dst_data, WORD *triangle_pos)
1758 for (unsigned lat = 0; lat <= nbLatBands; lat++) {
1759 float theta = lat * (float) M_PI / nbLatBands;
1760 float sinTheta, cosTheta;
1762 sincosf(theta, &sinTheta, &cosTheta);
1764 for (unsigned lon = 0; lon <= nbLonBands; lon++) {
1765 float phi = lon * 2 * (float) M_PI / nbLonBands;
1766 float sinPhi, cosPhi;
1768 sincosf(phi, &sinPhi, &cosPhi);
1770 float x = cosPhi * sinTheta;
1771 float y = cosTheta;
1772 float z = sinPhi * sinTheta;
1774 unsigned off1 = lat * (nbLonBands + 1) + lon;
1775 dst_data[off1].position.x = SPHERE_RADIUS * x;
1776 dst_data[off1].position.y = SPHERE_RADIUS * y;
1777 dst_data[off1].position.z = SPHERE_RADIUS * z;
1779 dst_data[off1].texture.x = lon / (float) nbLonBands; // 0(left) to 1(right)
1780 dst_data[off1].texture.y = lat / (float) nbLatBands; // 0(top) to 1 (bottom)
1784 for (unsigned lat = 0; lat < nbLatBands; lat++) {
1785 for (unsigned lon = 0; lon < nbLonBands; lon++) {
1786 unsigned first = (lat * (nbLonBands + 1)) + lon;
1787 unsigned second = first + nbLonBands + 1;
1789 unsigned off = (lat * nbLatBands + lon) * 3 * 2;
1791 triangle_pos[off] = first;
1792 triangle_pos[off + 1] = first + 1;
1793 triangle_pos[off + 2] = second;
1795 triangle_pos[off + 3] = second;
1796 triangle_pos[off + 4] = first + 1;
1797 triangle_pos[off + 5] = second + 1;
1802 static bool AllocQuadVertices(vout_display_t *vd, d3d_quad_t *quad, video_projection_mode_t projection)
1804 HRESULT hr;
1805 D3D11_MAPPED_SUBRESOURCE mappedResource;
1806 vout_display_sys_t *sys = vd->sys;
1808 if (projection == PROJECTION_MODE_RECTANGULAR)
1810 quad->vertexCount = 4;
1811 quad->indexCount = 2 * 3;
1813 else if (projection == PROJECTION_MODE_EQUIRECTANGULAR)
1815 quad->vertexCount = (SPHERE_SLICES+1) * (SPHERE_SLICES+1);
1816 quad->indexCount = nbLatBands * nbLonBands * 2 * 3;
1818 else
1819 return false;
1821 D3D11_BUFFER_DESC bd;
1822 memset(&bd, 0, sizeof(bd));
1823 bd.Usage = D3D11_USAGE_DYNAMIC;
1824 bd.ByteWidth = sizeof(d3d_vertex_t) * quad->vertexCount;
1825 bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1826 bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1828 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &bd, NULL, &quad->pVertexBuffer);
1829 if(FAILED(hr)) {
1830 msg_Err(vd, "Failed to create vertex buffer. (hr=%lX)", hr);
1831 return false;
1834 /* create the index of the vertices */
1835 D3D11_BUFFER_DESC quadDesc = {
1836 .Usage = D3D11_USAGE_DYNAMIC,
1837 .ByteWidth = sizeof(WORD) * quad->indexCount,
1838 .BindFlags = D3D11_BIND_INDEX_BUFFER,
1839 .CPUAccessFlags = D3D11_CPU_ACCESS_WRITE,
1842 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &quadDesc, NULL, &quad->pIndexBuffer);
1843 if(FAILED(hr)) {
1844 msg_Err(vd, "Could not create the quad indices. (hr=0x%lX)", hr);
1845 return false;
1848 /* create the vertices */
1849 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
1850 if (FAILED(hr)) {
1851 msg_Err(vd, "Failed to lock the vertex buffer (hr=0x%lX)", hr);
1852 return false;
1854 d3d_vertex_t *dst_data = mappedResource.pData;
1856 /* create the vertex indices */
1857 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
1858 if (FAILED(hr)) {
1859 msg_Err(vd, "Failed to lock the index buffer (hr=0x%lX)", hr);
1860 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
1861 return false;
1863 WORD *triangle_pos = mappedResource.pData;
1865 if ( projection == PROJECTION_MODE_RECTANGULAR )
1866 SetupQuadFlat(dst_data, triangle_pos);
1867 else
1868 SetupQuadSphere(dst_data, triangle_pos);
1870 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pIndexBuffer, 0);
1871 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pVertexBuffer, 0);
1873 return true;
1876 static int AllocQuad(vout_display_t *vd, const video_format_t *fmt, d3d_quad_t *quad,
1877 d3d_quad_cfg_t *cfg, ID3D11PixelShader *d3dpixelShader, bool b_visible,
1878 video_projection_mode_t projection)
1880 vout_display_sys_t *sys = vd->sys;
1881 D3D11_MAPPED_SUBRESOURCE mappedResource;
1882 HRESULT hr;
1884 /* pixel shader constant buffer */
1885 PS_CONSTANT_BUFFER defaultConstants = {
1886 .Opacity = 1,
1888 static_assert((sizeof(PS_CONSTANT_BUFFER)%16)==0,"Constant buffers require 16-byte alignment");
1889 D3D11_BUFFER_DESC constantDesc = {
1890 .Usage = D3D11_USAGE_DYNAMIC,
1891 .ByteWidth = sizeof(PS_CONSTANT_BUFFER),
1892 .BindFlags = D3D11_BIND_CONSTANT_BUFFER,
1893 .CPUAccessFlags = D3D11_CPU_ACCESS_WRITE,
1895 D3D11_SUBRESOURCE_DATA constantInit = { .pSysMem = &defaultConstants };
1896 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &constantDesc, &constantInit, &quad->pPixelShaderConstants[0]);
1897 if(FAILED(hr)) {
1898 msg_Err(vd, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr);
1899 goto error;
1902 static const FLOAT WHITE_POINT_D65[4] = { -0.0625f, -0.5f, -0.5f, 1.f };
1904 static const FLOAT COLORSPACE_BT601_TO_FULL[4*4] = {
1905 1.164383561643836f, 0.f, 1.596026785714286f, 0.f,
1906 1.164383561643836f, -0.391762290094914f, -0.812967647237771f, 0.f,
1907 1.164383561643836f, 2.017232142857142f, 0.f, 0.f,
1908 0.f, 0.f, 0.f, 1.f,
1910 static const FLOAT COLORSPACE_BT709_TO_FULL[4*4] = {
1911 1.164383561643836f, 0.f, 1.792741071428571f, 0.f,
1912 1.164383561643836f, -0.213248614273730f, -0.532909328559444f, 0.f,
1913 1.164383561643836f, 2.112401785714286f, 0.f, 0.f,
1914 0.f, 0.f, 0.f, 1.f,
1916 /* RGB-709 to RGB-2020 based on https://www.researchgate.net/publication/258434326_Beyond_BT709 */
1917 static const FLOAT COLORSPACE_BT2020_TO_FULL[4*4] = {
1918 1.163746465f, -0.028815145f, 2.823537589f, 0.f,
1919 1.164383561f, -0.258509894f, 0.379693635f, 0.f,
1920 1.164383561f, 2.385315708f, 0.021554502f, 0.f,
1921 0.f, 0.f, 0.f, 1.f,
1924 PS_COLOR_TRANSFORM colorspace;
1925 const FLOAT *ppColorspace;
1926 switch (fmt->space){
1927 case COLOR_SPACE_BT709:
1928 ppColorspace = COLORSPACE_BT709_TO_FULL;
1929 break;
1930 case COLOR_SPACE_BT2020:
1931 ppColorspace = COLORSPACE_BT2020_TO_FULL;
1932 break;
1933 case COLOR_SPACE_BT601:
1934 ppColorspace = COLORSPACE_BT601_TO_FULL;
1935 break;
1936 case COLOR_SPACE_UNDEF:
1937 if( fmt->i_height > 576 )
1938 ppColorspace = COLORSPACE_BT709_TO_FULL;
1939 else
1940 ppColorspace = COLORSPACE_BT601_TO_FULL;
1941 break;
1943 memcpy(colorspace.Colorspace, ppColorspace, sizeof(colorspace.Colorspace));
1944 memcpy(colorspace.WhitePoint, WHITE_POINT_D65, sizeof(colorspace.WhitePoint));
1945 constantInit.pSysMem = &colorspace;
1947 static_assert((sizeof(PS_COLOR_TRANSFORM)%16)==0,"Constant buffers require 16-byte alignment");
1948 constantDesc.ByteWidth = sizeof(PS_COLOR_TRANSFORM);
1949 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &constantDesc, &constantInit, &quad->pPixelShaderConstants[1]);
1950 if(FAILED(hr)) {
1951 msg_Err(vd, "Could not create the pixel shader constant buffer. (hr=0x%lX)", hr);
1952 goto error;
1954 quad->PSConstantsCount = 2;
1956 /* vertex shader constant buffer */
1957 if ( projection == PROJECTION_MODE_EQUIRECTANGULAR )
1959 constantDesc.ByteWidth = sizeof(VS_PROJECTION_CONST);
1960 static_assert((sizeof(VS_PROJECTION_CONST)%16)==0,"Constant buffers require 16-byte alignment");
1961 hr = ID3D11Device_CreateBuffer(sys->d3ddevice, &constantDesc, NULL, &quad->pVertexShaderConstants);
1962 if(FAILED(hr)) {
1963 msg_Err(vd, "Could not create the vertex shader constant buffer. (hr=0x%lX)", hr);
1964 goto error;
1967 SetQuadVSProjection( vd, quad, &vd->cfg->viewpoint );
1970 D3D11_TEXTURE2D_DESC texDesc;
1971 memset(&texDesc, 0, sizeof(texDesc));
1972 texDesc.Width = b_visible ? fmt->i_visible_width : fmt->i_width;
1973 texDesc.Height = b_visible ? fmt->i_visible_height : fmt->i_height;
1974 texDesc.MipLevels = texDesc.ArraySize = 1;
1975 texDesc.Format = cfg->textureFormat;
1976 texDesc.SampleDesc.Count = 1;
1977 texDesc.Usage = D3D11_USAGE_DYNAMIC;
1978 texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
1979 texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1980 texDesc.MiscFlags = 0;
1982 /* remove half pixels, we don't want green lines */
1983 const vlc_chroma_description_t *p_chroma_desc = vlc_fourcc_GetChromaDescription( fmt->i_chroma );
1984 for (unsigned plane = 0; plane < p_chroma_desc->plane_count; ++plane)
1986 unsigned i_extra;
1987 i_extra = (texDesc.Width * p_chroma_desc->p[plane].w.num) % p_chroma_desc->p[plane].w.den;
1988 if ( i_extra )
1989 texDesc.Width -= p_chroma_desc->p[plane].w.den / p_chroma_desc->p[plane].w.num - i_extra;
1990 i_extra = (texDesc.Height * p_chroma_desc->p[plane].h.num) % p_chroma_desc->p[plane].h.den;
1991 if ( i_extra )
1992 texDesc.Height -= p_chroma_desc->p[plane].h.den / p_chroma_desc->p[plane].h.num - i_extra;
1994 if (texDesc.Format == DXGI_FORMAT_NV12 || texDesc.Format == DXGI_FORMAT_P010)
1996 texDesc.Width &= ~1;
1997 texDesc.Height &= ~1;
2000 hr = ID3D11Device_CreateTexture2D(sys->d3ddevice, &texDesc, NULL, &quad->pTexture);
2001 if (FAILED(hr)) {
2002 msg_Err(vd, "Could not Create the D3d11 Texture. (hr=0x%lX)", hr);
2003 goto error;
2006 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
2007 if( FAILED(hr) ) {
2008 msg_Err(vd, "The texture cannot be mapped. (hr=0x%lX)", hr);
2009 goto error;
2011 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pTexture, 0);
2012 if (mappedResource.RowPitch < p_chroma_desc->pixel_size * texDesc.Width) {
2013 msg_Err( vd, "The texture row pitch is too small (%d instead of %d)", mappedResource.RowPitch,
2014 p_chroma_desc->pixel_size * texDesc.Width );
2015 goto error;
2018 /* map texture planes to resource views */
2019 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc;
2020 memset(&resviewDesc, 0, sizeof(resviewDesc));
2021 resviewDesc.Format = cfg->resourceFormatYRGB;
2022 resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
2023 resviewDesc.Texture2D.MipLevels = texDesc.MipLevels;
2025 hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)quad->pTexture, &resviewDesc, &quad->d3dresViewY);
2026 if (FAILED(hr)) {
2027 msg_Err(vd, "Could not Create the Y/RGB D3d11 Texture ResourceView. (hr=0x%lX)", hr);
2028 goto error;
2031 if( cfg->resourceFormatUV )
2033 resviewDesc.Format = cfg->resourceFormatUV;
2034 hr = ID3D11Device_CreateShaderResourceView(sys->d3ddevice, (ID3D11Resource *)quad->pTexture, &resviewDesc, &quad->d3dresViewUV);
2035 if (FAILED(hr)) {
2036 msg_Err(vd, "Could not Create the UV D3d11 Texture ResourceView. (hr=0x%lX)", hr);
2037 goto error;
2041 if ( d3dpixelShader != NULL )
2043 if (!AllocQuadVertices(vd, quad, projection))
2044 goto error;
2046 if (projection == PROJECTION_MODE_RECTANGULAR)
2047 quad->d3dvertexShader = sys->flatVSShader;
2048 else
2049 quad->d3dvertexShader = sys->projectionVSShader;
2051 quad->d3dpixelShader = d3dpixelShader;
2052 ID3D11PixelShader_AddRef(quad->d3dpixelShader);
2055 return VLC_SUCCESS;
2057 error:
2058 ReleaseQuad(quad);
2059 return VLC_EGENERIC;
2062 static void ReleaseQuad(d3d_quad_t *quad)
2064 if (quad->pPixelShaderConstants[0])
2066 ID3D11Buffer_Release(quad->pPixelShaderConstants[0]);
2067 quad->pPixelShaderConstants[0] = NULL;
2069 if (quad->pPixelShaderConstants[1])
2071 ID3D11Buffer_Release(quad->pPixelShaderConstants[1]);
2072 quad->pPixelShaderConstants[1] = NULL;
2074 if (quad->pVertexBuffer)
2076 ID3D11Buffer_Release(quad->pVertexBuffer);
2077 quad->pVertexBuffer = NULL;
2079 quad->d3dvertexShader = NULL;
2080 if (quad->pIndexBuffer)
2082 ID3D11Buffer_Release(quad->pIndexBuffer);
2083 quad->pIndexBuffer = NULL;
2085 if (quad->pVertexShaderConstants)
2087 ID3D11Buffer_Release(quad->pVertexShaderConstants);
2088 quad->pVertexShaderConstants = NULL;
2090 if (quad->pTexture)
2092 ID3D11Texture2D_Release(quad->pTexture);
2093 quad->pTexture = NULL;
2095 if (quad->d3dresViewY)
2097 ID3D11ShaderResourceView_Release(quad->d3dresViewY);
2098 quad->d3dresViewY = NULL;
2100 if (quad->d3dresViewUV)
2102 ID3D11ShaderResourceView_Release(quad->d3dresViewUV);
2103 quad->d3dresViewUV = NULL;
2105 if (quad->d3dpixelShader)
2107 ID3D11VertexShader_Release(quad->d3dpixelShader);
2108 quad->d3dpixelShader = NULL;
2112 static void Direct3D11DestroyResources(vout_display_t *vd)
2114 vout_display_sys_t *sys = vd->sys;
2116 Direct3D11DestroyPool(vd);
2118 if ( sys->stagingQuad.pTexture )
2119 ReleaseQuad(&sys->stagingQuad);
2120 ReleaseQuad(&sys->picQuad);
2121 Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
2122 sys->d3dregion_count = 0;
2124 if (sys->flatVSShader)
2126 ID3D11VertexShader_Release(sys->flatVSShader);
2127 sys->flatVSShader = NULL;
2129 if (sys->projectionVSShader)
2131 ID3D11VertexShader_Release(sys->projectionVSShader);
2132 sys->projectionVSShader = NULL;
2134 if (sys->d3drenderTargetView)
2136 ID3D11RenderTargetView_Release(sys->d3drenderTargetView);
2137 sys->d3drenderTargetView = NULL;
2139 if (sys->d3ddepthStencilView)
2141 ID3D11DepthStencilView_Release(sys->d3ddepthStencilView);
2142 sys->d3ddepthStencilView = NULL;
2144 if (sys->pSPUPixelShader)
2146 ID3D11VertexShader_Release(sys->pSPUPixelShader);
2147 sys->pSPUPixelShader = NULL;
2149 #if defined(HAVE_ID3D11VIDEODECODER)
2150 if( sys->context_lock != INVALID_HANDLE_VALUE )
2152 CloseHandle( sys->context_lock );
2153 sys->context_lock = INVALID_HANDLE_VALUE;
2155 #endif
2157 msg_Dbg(vd, "Direct3D11 resources destroyed");
2160 static int Direct3D11MapTexture(picture_t *picture)
2162 picture_sys_pool_t *p_sys = (picture_sys_pool_t*) picture->p_sys;
2163 vout_display_t *vd = p_sys->vd;
2164 D3D11_MAPPED_SUBRESOURCE mappedResource;
2165 HRESULT hr;
2166 hr = ID3D11DeviceContext_Map(vd->sys->d3dcontext, (ID3D11Resource *)p_sys->texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
2167 if( FAILED(hr) )
2169 msg_Dbg( vd, "failed to map the texture (hr=0x%lX)", hr );
2170 return VLC_EGENERIC;
2172 return CommonUpdatePicture(picture, NULL, mappedResource.pData, mappedResource.RowPitch);
2175 static int Direct3D11UnmapTexture(picture_t *picture)
2177 picture_sys_pool_t *p_sys = (picture_sys_pool_t*)picture->p_sys;
2178 vout_display_t *vd = p_sys->vd;
2179 ID3D11DeviceContext_Unmap(vd->sys->d3dcontext, (ID3D11Resource *)p_sys->texture, 0);
2180 return VLC_SUCCESS;
2183 static void Direct3D11DeleteRegions(int count, picture_t **region)
2185 for (int i = 0; i < count; ++i) {
2186 if (region[i]) {
2187 picture_Release(region[i]);
2190 free(region);
2193 static void DestroyPictureQuad(picture_t *p_picture)
2195 ReleaseQuad( (d3d_quad_t *) p_picture->p_sys );
2196 free( p_picture );
2199 static void UpdateQuadOpacity(vout_display_t *vd, const d3d_quad_t *quad, float opacity)
2201 vout_display_sys_t *sys = vd->sys;
2202 D3D11_MAPPED_SUBRESOURCE mappedResource;
2204 HRESULT hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)quad->pPixelShaderConstants[0], 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
2205 if (SUCCEEDED(hr)) {
2206 FLOAT *dst_data = mappedResource.pData;
2207 *dst_data = opacity;
2208 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)quad->pPixelShaderConstants[0], 0);
2210 else {
2211 msg_Err(vd, "Failed to lock the subpicture vertex buffer (hr=0x%lX)", hr);
2215 static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_count,
2216 picture_t ***region, subpicture_t *subpicture)
2218 vout_display_sys_t *sys = vd->sys;
2219 D3D11_MAPPED_SUBRESOURCE mappedResource;
2220 D3D11_TEXTURE2D_DESC texDesc;
2221 HRESULT hr;
2222 int err;
2224 int count = 0;
2225 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
2226 count++;
2228 *region = calloc(count, sizeof(picture_t *));
2229 if (unlikely(*region==NULL))
2230 return VLC_ENOMEM;
2231 *subpicture_region_count = count;
2233 int i = 0;
2234 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
2235 if (!r->fmt.i_width || !r->fmt.i_height)
2236 continue; // won't render anything, keep the cache for later
2238 for (int j = 0; j < sys->d3dregion_count; j++) {
2239 picture_t *cache = sys->d3dregions[j];
2240 if (cache != NULL && ((d3d_quad_t *) cache->p_sys)->pTexture) {
2241 ID3D11Texture2D_GetDesc( ((d3d_quad_t *) cache->p_sys)->pTexture, &texDesc );
2242 if (texDesc.Format == sys->d3dregion_format &&
2243 texDesc.Width == r->fmt.i_visible_width &&
2244 texDesc.Height == r->fmt.i_visible_height) {
2245 (*region)[i] = cache;
2246 memset(&sys->d3dregions[j], 0, sizeof(cache)); // do not reuse this cached value
2247 break;
2252 picture_t *quad_picture = (*region)[i];
2253 if (quad_picture == NULL) {
2254 d3d_quad_t *d3dquad = calloc(1, sizeof(*d3dquad));
2255 if (unlikely(d3dquad==NULL)) {
2256 continue;
2258 d3d_quad_cfg_t rgbaCfg = {
2259 .textureFormat = sys->d3dregion_format,
2260 .resourceFormatYRGB = sys->d3dregion_format,
2262 err = AllocQuad( vd, &r->fmt, d3dquad, &rgbaCfg, sys->pSPUPixelShader,
2263 false, PROJECTION_MODE_RECTANGULAR );
2264 if (err != VLC_SUCCESS) {
2265 msg_Err(vd, "Failed to create %dx%d texture for OSD",
2266 r->fmt.i_visible_width, r->fmt.i_visible_height);
2267 free(d3dquad);
2268 continue;
2270 picture_resource_t picres = {
2271 .p_sys = (picture_sys_t *) d3dquad,
2272 .pf_destroy = DestroyPictureQuad,
2274 (*region)[i] = picture_NewFromResource(&r->fmt, &picres);
2275 if ((*region)[i] == NULL) {
2276 msg_Err(vd, "Failed to create %dx%d picture for OSD",
2277 r->fmt.i_width, r->fmt.i_height);
2278 ReleaseQuad(d3dquad);
2279 continue;
2281 quad_picture = (*region)[i];
2284 hr = ID3D11DeviceContext_Map(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
2285 if( SUCCEEDED(hr) ) {
2286 err = CommonUpdatePicture(quad_picture, NULL, mappedResource.pData, mappedResource.RowPitch);
2287 if (err != VLC_SUCCESS) {
2288 msg_Err(vd, "Failed to set the buffer on the SPU picture" );
2289 picture_Release(quad_picture);
2290 continue;
2293 picture_CopyPixels(quad_picture, r->p_picture);
2295 ID3D11DeviceContext_Unmap(sys->d3dcontext, (ID3D11Resource *)((d3d_quad_t *) quad_picture->p_sys)->pTexture, 0);
2296 } else {
2297 msg_Err(vd, "Failed to map the SPU texture (hr=0x%lX)", hr );
2298 picture_Release(quad_picture);
2299 continue;
2302 d3d_quad_t *quad = (d3d_quad_t *) quad_picture->p_sys;
2304 quad->cropViewport.Width = (FLOAT) r->fmt.i_visible_width * RECTWidth(sys->rect_dest) / subpicture->i_original_picture_width;
2305 quad->cropViewport.Height = (FLOAT) r->fmt.i_visible_height * RECTHeight(sys->rect_dest) / subpicture->i_original_picture_height;
2306 quad->cropViewport.MinDepth = 0.0f;
2307 quad->cropViewport.MaxDepth = 1.0f;
2308 quad->cropViewport.TopLeftX = sys->rect_dest.left + (FLOAT) r->i_x * RECTWidth(sys->rect_dest) / subpicture->i_original_picture_width;
2309 quad->cropViewport.TopLeftY = sys->rect_dest.top + (FLOAT) r->i_y * RECTHeight(sys->rect_dest) / subpicture->i_original_picture_height;
2311 UpdateQuadOpacity(vd, quad, r->i_alpha / 255.0f );
2313 return VLC_SUCCESS;