1 /*****************************************************************************
2 * direct3d9.c: Windows Direct3D9 video output module
3 *****************************************************************************
4 * Copyright (C) 2006-2014 VLC authors and VideoLAN
5 *$Id: 669af0f27d06b2ac0714e2b2673eddf5a89ddd61 $
6 *
7 * Authors: Martell Malone <martellmalone@gmail.com>,
8 * Damien Fouilleul <damienf@videolan.org>,
9 * Sasha Koruga <skoruga@gmail.com>,
10 * Felix Abecassis <felix.abecassis@gmail.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
26
27 /*****************************************************************************
28 * Preamble:
29 *
30 * This plugin will use YUV surface if supported, using YUV will result in
31 * the best video quality (hardware filtering when rescaling the picture)
32 * and the fastest display as it requires less processing.
33 *
34 * If YUV overlay is not supported this plugin will use RGB offscreen video
35 * surfaces that will be blitted onto the primary surface (display) to
36 * effectively display the pictures.
37 *
38 *****************************************************************************/
39 #ifdef HAVE_CONFIG_H
40 # include "config.h"
41 #endif
42
43 // For dynamic use of DXVA-HD
44 #if _WIN32_WINNT < 0x0601 // _WIN32_WINNT_WIN7
45 # undef _WIN32_WINNT
46 # define _WIN32_WINNT _WIN32_WINNT_WIN7
47 #endif
48
49 #include <vlc_common.h>
50 #include <vlc_plugin.h>
51 #include <vlc_vout_display.h>
52 #include <vlc_charset.h> /* ToT function */
53
54 #include <windows.h>
55 #include <d3d9.h>
56 #ifdef HAVE_D3DX9EFFECT_H
57 #include <d3dx9effect.h>
58 #endif
59 #include "../../video_chroma/d3d9_fmt.h"
60 #include <dxvahd.h>
61
62 #include "common.h"
63 #include "builtin_shaders.h"
64
65 #include <assert.h>
66
67 /*****************************************************************************
68 * Module descriptor
69 *****************************************************************************/
70 static int Open(vlc_object_t *);
71 static void Close(vlc_object_t *);
72
73 static int GLConvOpen(vlc_object_t *);
74 static void GLConvClose(vlc_object_t *);
75
76 #define DESKTOP_LONGTEXT N_(\
77 "The desktop mode allows you to display the video on the desktop.")
78
79 #define HW_BLENDING_TEXT N_("Use hardware blending support")
80 #define HW_BLENDING_LONGTEXT N_(\
81 "Try to use hardware acceleration for subtitle/OSD blending.")
82
83 #define PIXEL_SHADER_TEXT N_("Pixel Shader")
84 #define PIXEL_SHADER_LONGTEXT N_(\
85 "Choose a pixel shader to apply.")
86 #define PIXEL_SHADER_FILE_TEXT N_("Path to HLSL file")
87 #define PIXEL_SHADER_FILE_LONGTEXT N_("Path to an HLSL file containing a single pixel shader.")
88 /* The latest option in the selection list: used for loading a shader file. */
89 #define SELECTED_SHADER_FILE N_("HLSL File")
90
91 #define D3D9_HELP N_("Recommended video output for Windows Vista and later versions")
92
93 static int FindShadersCallback(vlc_object_t *, const char *,
94 char ***, char ***);
95
96 vlc_module_begin ()
97 set_shortname("Direct3D9")
98 set_description(N_("Direct3D9 video output"))
99 set_help(D3D9_HELP)
100 set_category(CAT_VIDEO)
101 set_subcategory(SUBCAT_VIDEO_VOUT)
102
103 add_bool("direct3d9-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT, true)
104
105 add_string("direct3d9-shader", "", PIXEL_SHADER_TEXT, PIXEL_SHADER_LONGTEXT, true)
106 change_string_cb(FindShadersCallback)
107 add_loadfile("direct3d9-shader-file", NULL, PIXEL_SHADER_FILE_TEXT, PIXEL_SHADER_FILE_LONGTEXT, false)
108
109 set_capability("vout display", 280)
110 add_shortcut("direct3d9", "direct3d")
111 set_callbacks(Open, Close)
112
113 #ifdef HAVE_GL
114 add_submodule()
115 set_description("DX OpenGL surface converter for D3D9")
116 set_capability("glconv", 1)
117 set_callbacks(GLConvOpen, GLConvClose)
118 #endif
119 vlc_module_end ()
120
121 /*****************************************************************************
122 * Local prototypes.
123 *****************************************************************************/
124 static const vlc_fourcc_t d3d_subpicture_chromas[] = {
125 VLC_CODEC_RGBA,
126 0
127 };
128
129 typedef struct
130 {
131 const char *name;
132 D3DFORMAT format; /* D3D format */
133 vlc_fourcc_t fourcc; /* VLC fourcc */
134 uint32_t rmask;
135 uint32_t gmask;
136 uint32_t bmask;
137 } d3d9_format_t;
138
139 struct vout_display_sys_t
140 {
141 vout_display_sys_win32_t sys;
142
143 bool allow_hw_yuv; /* Should we use hardware YUV->RGB conversions */
144 struct {
145 bool is_fullscreen;
146 bool is_on_top;
147 RECT win;
148 } desktop_save;
149 vout_display_cfg_t cfg_saved; /* configuration used before going into desktop mode */
150
151 // core objects
152 d3d9_handle_t hd3d;
153 HINSTANCE hxdll; /* handle of the opened d3d9x dll */
154 IDirect3DPixelShader9* d3dx_shader;
155 d3d9_device_t d3d_dev;
156
157 // scene objects
158 LPDIRECT3DTEXTURE9 d3dtex;
159 LPDIRECT3DVERTEXBUFFER9 d3dvtc;
160 D3DFORMAT d3dregion_format; /* Backbuffer output format */
161 int d3dregion_count;
162 struct d3d_region_t *d3dregion;
163 const d3d9_format_t *d3dtexture_format; /* Rendering texture(s) format */
164
165 /* */
166 bool reset_device;
167 bool reopen_device;
168 bool lost_not_ready;
169 bool clear_scene;
170
171 /* It protects the following variables */
172 vlc_mutex_t lock;
173 bool ch_desktop;
174 bool desktop_requested;
175
176 /* range converter */
177 struct {
178 HMODULE dll;
179 IDXVAHD_VideoProcessor *proc;
180 } processor;
181 };
182
183 static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target);
184 static const d3d9_format_t *FindBufferFormat(vout_display_t *, D3DFORMAT);
185
186 static int Open(vlc_object_t *);
187
188 static picture_pool_t *Direct3D9CreatePicturePool (vlc_object_t *, d3d9_device_t *,
189 const d3d9_format_t *, const video_format_t *, unsigned);
190
191 static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture);
192 static void Display(vout_display_t *, picture_t *, subpicture_t *subpicture);
193 static picture_pool_t*DisplayPool(vout_display_t *, unsigned);
194 static int Control(vout_display_t *, int, va_list);
195 static void Manage (vout_display_t *);
196
197 static int Direct3D9Reset (vout_display_t *);
198 static void Direct3D9Destroy(vout_display_sys_t *);
199
200 static int Direct3D9Open (vout_display_t *, video_format_t *);
201 static void Direct3D9Close(vout_display_t *);
202
203 /* */
204 typedef struct
205 {
206 FLOAT x,y,z; // vertex untransformed position
207 FLOAT rhw; // eye distance
208 D3DCOLOR diffuse; // diffuse color
209 FLOAT tu, tv; // texture relative coordinates
210 } CUSTOMVERTEX;
211 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
212
213 typedef struct d3d_region_t {
214 D3DFORMAT format;
215 unsigned width;
216 unsigned height;
217 CUSTOMVERTEX vertex[4];
218 LPDIRECT3DTEXTURE9 texture;
219 } d3d_region_t;
220
221 static void Direct3D9DeleteRegions(int, d3d_region_t *);
222
223 static int Direct3D9ImportPicture(vout_display_t *vd, d3d_region_t *, LPDIRECT3DSURFACE9 surface);
224 static void Direct3D9ImportSubpicture(vout_display_t *vd, int *, d3d_region_t **, subpicture_t *);
225
226 static void Direct3D9RenderScene(vout_display_t *vd, d3d_region_t *, int, d3d_region_t *);
227
228 /* */
229 static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
230
is_d3d9_opaque(vlc_fourcc_t chroma)231 static bool is_d3d9_opaque(vlc_fourcc_t chroma)
232 {
233 switch (chroma)
234 {
235 case VLC_CODEC_D3D9_OPAQUE:
236 case VLC_CODEC_D3D9_OPAQUE_10B:
237 return true;
238 default:
239 return false;
240 }
241 }
242
Direct3D9LoadShaderLibrary(void)243 static HINSTANCE Direct3D9LoadShaderLibrary(void)
244 {
245 HINSTANCE instance = NULL;
246 for (int i = 43; i > 23; --i) {
247 TCHAR filename[16];
248 _sntprintf(filename, 16, TEXT("D3dx9_%d.dll"), i);
249 instance = LoadLibrary(filename);
250 if (instance)
251 break;
252 }
253 return instance;
254 }
255
256 /**
257 * It creates a Direct3D vout display.
258 */
Open(vlc_object_t * object)259 static int Open(vlc_object_t *object)
260 {
261 vout_display_t *vd = (vout_display_t *)object;
262 vout_display_sys_t *sys;
263
264 if ( !vd->obj.force && vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR)
265 return VLC_EGENERIC; /* let a module who can handle it do it */
266
267 if ( !vd->obj.force && vd->source.mastering.max_luminance != 0)
268 return VLC_EGENERIC; /* let a module who can handle it do it */
269
270 #if !VLC_WINSTORE_APP
271 /* do not use D3D9 on XP unless forced */
272 if (!vd->obj.force)
273 {
274 bool isVistaOrGreater = false;
275 HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
276 if (likely(hKernel32 != NULL))
277 isVistaOrGreater = GetProcAddress(hKernel32, "EnumResourceLanguagesExW") != NULL;
278 if (!isVistaOrGreater)
279 return VLC_EGENERIC;
280 }
281 #endif
282
283 /* Allocate structure */
284 vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
285 if (!sys)
286 return VLC_ENOMEM;
287
288 if (D3D9_Create(vd, &sys->hd3d)) {
289 msg_Err(vd, "Direct3D9 could not be initialized");
290 free(sys);
291 return VLC_EGENERIC;
292 }
293
294 sys->hxdll = Direct3D9LoadShaderLibrary();
295 if (!sys->hxdll)
296 msg_Warn(object, "cannot load Direct3D9 Shader Library; HLSL pixel shading will be disabled.");
297
298 sys->sys.use_desktop = var_CreateGetBool(vd, "video-wallpaper");
299 sys->reset_device = false;
300 sys->reopen_device = false;
301 sys->lost_not_ready = false;
302 sys->allow_hw_yuv = var_CreateGetBool(vd, "directx-hw-yuv");
303 sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
304 sys->desktop_save.is_on_top = false;
305 sys->desktop_save.win.left = var_InheritInteger(vd, "video-x");
306 sys->desktop_save.win.right = vd->cfg->display.width;
307 sys->desktop_save.win.top = var_InheritInteger(vd, "video-y");
308 sys->desktop_save.win.bottom = vd->cfg->display.height;
309
310 if (CommonInit(vd))
311 goto error;
312
313 /* */
314 video_format_t fmt;
315 if (Direct3D9Open(vd, &fmt)) {
316 msg_Err(vd, "Direct3D9 could not be opened");
317 goto error;
318 }
319
320 /* */
321 vout_display_info_t info = vd->info;
322 info.is_slow = !is_d3d9_opaque(fmt.i_chroma);
323 info.has_double_click = true;
324 info.has_pictures_invalid = !is_d3d9_opaque(fmt.i_chroma);
325 if (var_InheritBool(vd, "direct3d9-hw-blending") &&
326 sys->d3dregion_format != D3DFMT_UNKNOWN &&
327 (sys->d3d_dev.caps.SrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) &&
328 (sys->d3d_dev.caps.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) &&
329 (sys->d3d_dev.caps.TextureCaps & D3DPTEXTURECAPS_ALPHA) &&
330 (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1) &&
331 (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE))
332 info.subpicture_chromas = d3d_subpicture_chromas;
333 else
334 info.subpicture_chromas = NULL;
335
336 /* Interaction */
337 vlc_mutex_init(&sys->lock);
338 sys->ch_desktop = false;
339 sys->desktop_requested = sys->sys.use_desktop;
340
341 vlc_value_t val;
342 val.psz_string = _("Desktop");
343 var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, &val, NULL);
344 var_AddCallback(vd, "video-wallpaper", DesktopCallback, NULL);
345
346 /* Setup vout_display now that everything is fine */
347 video_format_Clean(&vd->fmt);
348 video_format_Copy(&vd->fmt, &fmt);
349 vd->info = info;
350
351 vd->pool = DisplayPool;
352 vd->prepare = Prepare;
353 vd->display = Display;
354 vd->control = Control;
355 vd->manage = Manage;
356
357 /* Fix state in case of desktop mode */
358 if (sys->sys.use_desktop && vd->cfg->is_fullscreen)
359 vout_display_SendEventFullscreen(vd, false, false);
360
361 return VLC_SUCCESS;
362 error:
363 Direct3D9Close(vd);
364 CommonClean(vd);
365 Direct3D9Destroy(sys);
366 free(vd->sys);
367 return VLC_EGENERIC;
368 }
369
370 /**
371 * It destroyes a Direct3D vout display.
372 */
Close(vlc_object_t * object)373 static void Close(vlc_object_t *object)
374 {
375 vout_display_t * vd = (vout_display_t *)object;
376
377 var_DelCallback(vd, "video-wallpaper", DesktopCallback, NULL);
378 vlc_mutex_destroy(&vd->sys->lock);
379
380 Direct3D9Close(vd);
381
382 CommonClean(vd);
383
384 Direct3D9Destroy(vd->sys);
385
386 free(vd->sys);
387 }
388
DestroyPicture(picture_t * picture)389 static void DestroyPicture(picture_t *picture)
390 {
391 ReleasePictureSys(picture->p_sys);
392
393 free(picture->p_sys);
394 free(picture);
395 }
396
397 /**
398 * It locks the surface associated to the picture and get the surface
399 * descriptor which amongst other things has the pointer to the picture
400 * data and its pitch.
401 */
Direct3D9LockSurface(picture_t * picture)402 static int Direct3D9LockSurface(picture_t *picture)
403 {
404 /* Lock the surface to get a valid pointer to the picture buffer */
405 D3DLOCKED_RECT d3drect;
406 HRESULT hr = IDirect3DSurface9_LockRect(picture->p_sys->surface, &d3drect, NULL, 0);
407 if (FAILED(hr)) {
408 return VLC_EGENERIC;
409 }
410
411 CommonUpdatePicture(picture, NULL, d3drect.pBits, d3drect.Pitch);
412 return VLC_SUCCESS;
413 }
414 /**
415 * It unlocks the surface associated to the picture.
416 */
Direct3D9UnlockSurface(picture_t * picture)417 static void Direct3D9UnlockSurface(picture_t *picture)
418 {
419 /* Unlock the Surface */
420 HRESULT hr = IDirect3DSurface9_UnlockRect(picture->p_sys->surface);
421 if (FAILED(hr)) {
422 //msg_Dbg(vd, "Failed IDirect3DSurface9_UnlockRect: 0x%0lx", hr);
423 }
424 }
425
426 /* */
Direct3D9CreatePicturePool(vlc_object_t * o,d3d9_device_t * p_d3d9_dev,const d3d9_format_t * default_d3dfmt,const video_format_t * fmt,unsigned count)427 static picture_pool_t *Direct3D9CreatePicturePool(vlc_object_t *o,
428 d3d9_device_t *p_d3d9_dev, const d3d9_format_t *default_d3dfmt, const video_format_t *fmt, unsigned count)
429 {
430 picture_pool_t* pool = NULL;
431 picture_t** pictures = NULL;
432 unsigned picture_count = 0;
433
434 pictures = calloc(count, sizeof(*pictures));
435 if (!pictures)
436 goto error;
437
438 D3DFORMAT format;
439 switch (fmt->i_chroma)
440 {
441 case VLC_CODEC_D3D9_OPAQUE_10B:
442 format = MAKEFOURCC('P','0','1','0');
443 break;
444 case VLC_CODEC_D3D9_OPAQUE:
445 format = MAKEFOURCC('N','V','1','2');
446 break;
447 default:
448 if (!default_d3dfmt)
449 goto error;
450 format = default_d3dfmt->format;
451 break;
452 }
453
454 for (picture_count = 0; picture_count < count; ++picture_count)
455 {
456 picture_sys_t *picsys = malloc(sizeof(*picsys));
457 if (unlikely(picsys == NULL))
458 goto error;
459 memset(picsys, 0, sizeof(*picsys));
460
461 HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3d9_dev->dev,
462 fmt->i_width,
463 fmt->i_height,
464 format,
465 D3DPOOL_DEFAULT,
466 &picsys->surface,
467 NULL);
468 if (FAILED(hr)) {
469 msg_Err(o, "Failed to allocate surface %d (hr=0x%0lx)", picture_count, hr);
470 free(picsys);
471 goto error;
472 }
473
474 picture_resource_t resource = {
475 .p_sys = picsys,
476 .pf_destroy = DestroyPicture,
477 };
478
479 picture_t *picture = picture_NewFromResource(fmt, &resource);
480 if (unlikely(picture == NULL)) {
481 free(picsys);
482 goto error;
483 }
484
485 pictures[picture_count] = picture;
486 }
487
488 picture_pool_configuration_t pool_cfg;
489 memset(&pool_cfg, 0, sizeof(pool_cfg));
490 pool_cfg.picture_count = count;
491 pool_cfg.picture = pictures;
492 if( !is_d3d9_opaque( fmt->i_chroma ) )
493 {
494 pool_cfg.lock = Direct3D9LockSurface;
495 pool_cfg.unlock = Direct3D9UnlockSurface;
496 }
497
498 pool = picture_pool_NewExtended( &pool_cfg );
499
500 error:
501 if (pool == NULL && pictures) {
502 for (unsigned i=0;i<picture_count; ++i)
503 DestroyPicture(pictures[i]);
504 }
505 free(pictures);
506 return pool;
507 }
508
DisplayPool(vout_display_t * vd,unsigned count)509 static picture_pool_t *DisplayPool(vout_display_t *vd, unsigned count)
510 {
511 if ( vd->sys->sys.pool != NULL )
512 return vd->sys->sys.pool;
513 vd->sys->sys.pool = Direct3D9CreatePicturePool(VLC_OBJECT(vd), &vd->sys->d3d_dev,
514 vd->sys->d3dtexture_format, &vd->fmt, count);
515 return vd->sys->sys.pool;
516 }
517
Prepare(vout_display_t * vd,picture_t * picture,subpicture_t * subpicture)518 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
519 {
520 vout_display_sys_t *sys = vd->sys;
521 LPDIRECT3DSURFACE9 surface = picture->p_sys->surface;
522 d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
523
524 /* FIXME it is a bit ugly, we need the surface to be unlocked for
525 * rendering.
526 * The clean way would be to release the picture (and ensure that
527 * the vout doesn't keep a reference). But because of the vout
528 * wrapper, we can't */
529 if ( !is_d3d9_opaque(picture->format.i_chroma) )
530 Direct3D9UnlockSurface(picture);
531 else if (picture->context)
532 {
533 const struct va_pic_context *pic_ctx = (struct va_pic_context*)picture->context;
534 if (pic_ctx->picsys.surface != surface)
535 {
536 D3DSURFACE_DESC srcDesc, dstDesc;
537 IDirect3DSurface9_GetDesc(pic_ctx->picsys.surface, &srcDesc);
538 IDirect3DSurface9_GetDesc(surface, &dstDesc);
539 if ( srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height )
540 surface = pic_ctx->picsys.surface;
541 else
542 {
543 HRESULT hr;
544 RECT visibleSource;
545 visibleSource.left = 0;
546 visibleSource.top = 0;
547 visibleSource.right = picture->format.i_visible_width;
548 visibleSource.bottom = picture->format.i_visible_height;
549
550 hr = IDirect3DDevice9_StretchRect( p_d3d9_dev->dev, pic_ctx->picsys.surface, &visibleSource, surface, &visibleSource, D3DTEXF_NONE);
551 if (FAILED(hr)) {
552 msg_Err(vd, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
553 }
554 }
555 }
556 }
557
558 /* check if device is still available */
559 HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(p_d3d9_dev->dev);
560 if (FAILED(hr)) {
561 if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) {
562 vout_display_SendEventPicturesInvalid(vd);
563 sys->reset_device = true;
564 sys->lost_not_ready = false;
565 }
566 if (hr == D3DERR_DEVICELOST && !sys->lost_not_ready) {
567 /* Device is lost but not yet ready for reset. */
568 sys->lost_not_ready = true;
569 }
570 return;
571 }
572
573 d3d_region_t picture_region;
574 if (!Direct3D9ImportPicture(vd, &picture_region, surface)) {
575 picture_region.width = picture->format.i_visible_width;
576 picture_region.height = picture->format.i_visible_height;
577 int subpicture_region_count = 0;
578 d3d_region_t *subpicture_region = NULL;
579 if (subpicture)
580 Direct3D9ImportSubpicture(vd, &subpicture_region_count, &subpicture_region,
581 subpicture);
582
583 Direct3D9RenderScene(vd, &picture_region,
584 subpicture_region_count, subpicture_region);
585
586 Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
587 sys->d3dregion_count = subpicture_region_count;
588 sys->d3dregion = subpicture_region;
589 }
590 }
591
Display(vout_display_t * vd,picture_t * picture,subpicture_t * subpicture)592 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
593 {
594 vout_display_sys_t *sys = vd->sys;
595 const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
596
597 if (sys->lost_not_ready) {
598 picture_Release(picture);
599 if (subpicture)
600 subpicture_Delete(subpicture);
601 return;
602 }
603
604 // Present the back buffer contents to the display
605 // No stretching should happen here !
606 const RECT src = sys->sys.rect_dest_clipped;
607 const RECT dst = sys->sys.rect_dest_clipped;
608
609 HRESULT hr;
610 if (sys->hd3d.use_ex) {
611 hr = IDirect3DDevice9Ex_PresentEx(p_d3d9_dev->devex, &src, &dst, NULL, NULL, 0);
612 } else {
613 hr = IDirect3DDevice9_Present(p_d3d9_dev->dev, &src, &dst, NULL, NULL);
614 }
615 if (FAILED(hr)) {
616 msg_Dbg(vd, "Failed IDirect3DDevice9_Present: 0x%0lx", hr);
617 }
618
619 /* XXX See Prepare() */
620 if ( !is_d3d9_opaque(picture->format.i_chroma) )
621 Direct3D9LockSurface(picture);
622 picture_Release(picture);
623 if (subpicture)
624 subpicture_Delete(subpicture);
625
626 CommonDisplay(vd);
627 }
628
ControlReopenDevice(vout_display_t * vd)629 static int ControlReopenDevice(vout_display_t *vd)
630 {
631 vout_display_sys_t *sys = vd->sys;
632
633 if (!sys->sys.use_desktop) {
634 /* Save non-desktop state */
635 sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
636 sys->desktop_save.is_on_top = sys->sys.is_on_top;
637
638 WINDOWPLACEMENT wp = { .length = sizeof(wp), };
639 GetWindowPlacement(sys->sys.hparent ? sys->sys.hparent : sys->sys.hwnd, &wp);
640 sys->desktop_save.win = wp.rcNormalPosition;
641 }
642
643 /* */
644 Direct3D9Close(vd);
645 EventThreadStop(sys->sys.event);
646
647 /* */
648 vlc_mutex_lock(&sys->lock);
649 sys->sys.use_desktop = sys->desktop_requested;
650 sys->ch_desktop = false;
651 vlc_mutex_unlock(&sys->lock);
652
653 /* */
654 event_cfg_t cfg;
655 memset(&cfg, 0, sizeof(cfg));
656 cfg.use_desktop = sys->sys.use_desktop;
657 if (!sys->sys.use_desktop) {
658 cfg.x = sys->desktop_save.win.left;
659 cfg.y = sys->desktop_save.win.top;
660 cfg.width = sys->desktop_save.win.right - sys->desktop_save.win.left;
661 cfg.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top;
662 }
663
664 event_hwnd_t hwnd;
665 if (EventThreadStart(sys->sys.event, &hwnd, &cfg)) {
666 msg_Err(vd, "Failed to restart event thread");
667 return VLC_EGENERIC;
668 }
669 sys->sys.parent_window = hwnd.parent_window;
670 sys->sys.hparent = hwnd.hparent;
671 sys->sys.hwnd = hwnd.hwnd;
672 sys->sys.hvideownd = hwnd.hvideownd;
673 sys->sys.hfswnd = hwnd.hfswnd;
674 SetRectEmpty(&sys->sys.rect_parent);
675
676 /* */
677 video_format_t fmt;
678 if (Direct3D9Open(vd, &fmt)) {
679 CommonClean(vd);
680 msg_Err(vd, "Failed to reopen device");
681 return VLC_EGENERIC;
682 }
683 vd->fmt = fmt;
684 sys->sys.is_first_display = true;
685
686 if (sys->sys.use_desktop) {
687 /* Disable fullscreen/on_top while using desktop */
688 if (sys->desktop_save.is_fullscreen)
689 vout_display_SendEventFullscreen(vd, false, false);
690 if (sys->desktop_save.is_on_top)
691 vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_NORMAL);
692 } else {
693 /* Restore fullscreen/on_top */
694 if (sys->desktop_save.is_fullscreen)
695 vout_display_SendEventFullscreen(vd, true, false);
696 if (sys->desktop_save.is_on_top)
697 vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_ABOVE);
698 }
699 return VLC_SUCCESS;
700 }
Control(vout_display_t * vd,int query,va_list args)701 static int Control(vout_display_t *vd, int query, va_list args)
702 {
703 vout_display_sys_t *sys = vd->sys;
704
705 switch (query) {
706 case VOUT_DISPLAY_RESET_PICTURES:
707 /* FIXME what to do here in case of failure */
708 if (sys->reset_device) {
709 if (Direct3D9Reset(vd)) {
710 msg_Err(vd, "Failed to reset device");
711 return VLC_EGENERIC;
712 }
713 sys->reset_device = false;
714 } else if(sys->reopen_device) {
715 if (ControlReopenDevice(vd)) {
716 msg_Err(vd, "Failed to reopen device");
717 return VLC_EGENERIC;
718 }
719 sys->reopen_device = false;
720 }
721 return VLC_SUCCESS;
722 default:
723 return CommonControl(vd, query, args);
724 }
725 }
Manage(vout_display_t * vd)726 static void Manage (vout_display_t *vd)
727 {
728 vout_display_sys_t *sys = vd->sys;
729
730 CommonManage(vd);
731
732 /* Desktop mode change */
733 vlc_mutex_lock(&sys->lock);
734 const bool ch_desktop = sys->ch_desktop;
735 sys->ch_desktop = false;
736 vlc_mutex_unlock(&sys->lock);
737
738 if (ch_desktop) {
739 sys->reopen_device = true;
740 if (vd->info.has_pictures_invalid)
741 vout_display_SendEventPicturesInvalid(vd);
742 }
743
744 /* Position Change */
745 if (sys->sys.changes & DX_POSITION_CHANGE) {
746 #if 0 /* need that when bicubic filter is available */
747 RECT rect;
748 UINT width, height;
749
750 GetClientRect(p_sys->sys.hvideownd, &rect);
751 width = rect.right-rect.left;
752 height = rect.bottom-rect.top;
753
754 if (width != p_sys->pp.BackBufferWidth || height != p_sys->pp.BackBufferHeight)
755 {
756 msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height);
757 // need to reset D3D device to resize back buffer
758 if (VLC_SUCCESS != Direct3D9ResetDevice(vd, width, height))
759 return VLC_EGENERIC;
760 }
761 #endif
762 sys->clear_scene = true;
763 sys->sys.changes &= ~DX_POSITION_CHANGE;
764 }
765 }
766
767 /**
768 * It releases an instance of Direct3D9
769 */
Direct3D9Destroy(vout_display_sys_t * sys)770 static void Direct3D9Destroy(vout_display_sys_t *sys)
771 {
772 if (sys->processor.proc)
773 {
774 IDXVAHD_VideoProcessor_Release(sys->processor.proc);
775 FreeLibrary(sys->processor.dll);
776 }
777 D3D9_Destroy( &sys->hd3d );
778
779 if (sys->hxdll)
780 {
781 FreeLibrary(sys->hxdll);
782 sys->hxdll = NULL;
783 }
784 }
785
786 /* */
787 static int Direct3D9CreateResources (vout_display_t *, video_format_t *);
788 static void Direct3D9DestroyResources(vout_display_t *);
789
SetupProcessorInput(vout_display_t * vd,const video_format_t * fmt,const d3d9_format_t * d3dfmt)790 static void SetupProcessorInput(vout_display_t *vd, const video_format_t *fmt, const d3d9_format_t *d3dfmt)
791 {
792 vout_display_sys_t *sys = vd->sys;
793 HRESULT hr;
794 DXVAHD_STREAM_STATE_D3DFORMAT_DATA d3dformat = { d3dfmt->format };
795 hr = IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_D3DFORMAT, sizeof(d3dformat), &d3dformat );
796
797 DXVAHD_STREAM_STATE_FRAME_FORMAT_DATA frame_format = { DXVAHD_FRAME_FORMAT_PROGRESSIVE };
798 hr = IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_FRAME_FORMAT, sizeof(frame_format), &frame_format );
799
800 DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE_DATA colorspace = { 0 };
801 colorspace.RGB_Range = fmt->b_color_range_full ? 0 : 1;
802 colorspace.YCbCr_xvYCC = fmt->b_color_range_full ? 1 : 0;
803 colorspace.YCbCr_Matrix = fmt->space == COLOR_SPACE_BT601 ? 0 : 1;
804 hr = IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE, sizeof(colorspace), &colorspace );
805
806 DXVAHD_STREAM_STATE_SOURCE_RECT_DATA srcRect;
807 srcRect.Enable = TRUE;
808 srcRect.SourceRect = (RECT) {
809 .left = vd->source.i_x_offset,
810 .right = vd->source.i_x_offset + vd->source.i_visible_width,
811 .top = vd->source.i_y_offset,
812 .bottom = vd->source.i_y_offset + vd->source.i_visible_height,
813 };;
814 hr = IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_SOURCE_RECT, sizeof(srcRect), &srcRect );
815
816 DXVAHD_BLT_STATE_TARGET_RECT_DATA dstRect;
817 dstRect.Enable = TRUE;
818 dstRect.TargetRect = (RECT) {
819 .left = 0,
820 .right = vd->source.i_visible_width,
821 .top = 0,
822 .bottom = vd->source.i_visible_height,
823 };
824 hr = IDXVAHD_VideoProcessor_SetVideoProcessBltState( sys->processor.proc, DXVAHD_BLT_STATE_TARGET_RECT, sizeof(dstRect), &dstRect);
825 }
826
GetFrameRate(DXVAHD_RATIONAL * r,const video_format_t * fmt)827 static void GetFrameRate(DXVAHD_RATIONAL *r, const video_format_t *fmt)
828 {
829 if (fmt->i_frame_rate && fmt->i_frame_rate_base)
830 {
831 r->Numerator = fmt->i_frame_rate;
832 r->Denominator = fmt->i_frame_rate_base;
833 }
834 else
835 {
836 r->Numerator = 0;
837 r->Denominator = 0;
838 }
839 }
840
InitRangeProcessor(vout_display_t * vd,const d3d9_format_t * d3dfmt)841 static int InitRangeProcessor(vout_display_t *vd, const d3d9_format_t *d3dfmt)
842 {
843 vout_display_sys_t *sys = vd->sys;
844
845 HRESULT hr;
846
847 sys->processor.dll = LoadLibrary(TEXT("DXVA2.DLL"));
848 if (!sys->processor.dll)
849 return VLC_EGENERIC;
850
851 D3DFORMAT *formatsList = NULL;
852 DXVAHD_VPCAPS *capsList = NULL;
853 IDXVAHD_Device *hd_device = NULL;
854
855 HRESULT (WINAPI *CreateDevice)(IDirect3DDevice9Ex *,const DXVAHD_CONTENT_DESC *,DXVAHD_DEVICE_USAGE,PDXVAHDSW_Plugin,IDXVAHD_Device **);
856 CreateDevice = (void *)GetProcAddress(sys->processor.dll, "DXVAHD_CreateDevice");
857 if (CreateDevice == NULL)
858 {
859 msg_Err(vd, "Can't create HD device (not Windows 7+)");
860 goto error;
861 }
862
863 DXVAHD_CONTENT_DESC desc;
864 desc.InputFrameFormat = DXVAHD_FRAME_FORMAT_PROGRESSIVE;
865 GetFrameRate( &desc.InputFrameRate, &vd->source );
866 desc.InputWidth = vd->source.i_visible_width;
867 desc.InputHeight = vd->source.i_visible_height;
868 desc.OutputFrameRate = desc.InputFrameRate;
869 desc.OutputWidth = vd->source.i_visible_width;
870 desc.OutputHeight = vd->source.i_visible_height;
871
872 hr = CreateDevice(sys->d3d_dev.devex, &desc, DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL, NULL, &hd_device);
873 if (FAILED(hr))
874 {
875 msg_Dbg(vd, "Failed to create the device (error 0x%lX)", hr);
876 goto error;
877 }
878
879 DXVAHD_VPDEVCAPS devcaps = { 0 };
880 hr = IDXVAHD_Device_GetVideoProcessorDeviceCaps( hd_device, &devcaps );
881 if (unlikely(FAILED(hr)))
882 {
883 msg_Err(vd, "Failed to get the device capabilities (error 0x%lX)", hr);
884 goto error;
885 }
886 if (devcaps.VideoProcessorCount == 0)
887 {
888 msg_Warn(vd, "No good video processor found for range conversion");
889 goto error;
890 }
891
892 formatsList = malloc(devcaps.InputFormatCount * sizeof(*formatsList));
893 if (unlikely(formatsList == NULL))
894 goto error;
895
896 hr = IDXVAHD_Device_GetVideoProcessorInputFormats( hd_device, devcaps.InputFormatCount, formatsList);
897 UINT i;
898 for (i=0; i<devcaps.InputFormatCount; i++)
899 {
900 if (formatsList[i] == d3dfmt->format)
901 break;
902 }
903 if (i == devcaps.InputFormatCount)
904 {
905 msg_Warn(vd, "Input format %s not supported for range conversion", d3dfmt->name);
906 goto error;
907 }
908
909 free(formatsList);
910 formatsList = malloc(devcaps.OutputFormatCount * sizeof(*formatsList));
911 if (unlikely(formatsList == NULL))
912 goto error;
913
914 hr = IDXVAHD_Device_GetVideoProcessorOutputFormats( hd_device, devcaps.OutputFormatCount, formatsList);
915 for (i=0; i<devcaps.OutputFormatCount; i++)
916 {
917 if (formatsList[i] == sys->d3d_dev.pp.BackBufferFormat)
918 break;
919 }
920 if (i == devcaps.OutputFormatCount)
921 {
922 msg_Warn(vd, "Output format %s not supported for range conversion", d3dfmt->name);
923 goto error;
924 }
925
926 capsList = malloc(devcaps.VideoProcessorCount * sizeof(*capsList));
927 if (unlikely(capsList == NULL))
928 goto error;
929 hr = IDXVAHD_Device_GetVideoProcessorCaps( hd_device, devcaps.VideoProcessorCount, capsList);
930 if (FAILED(hr))
931 {
932 msg_Dbg(vd, "Failed to get the processor caps (error 0x%lX)", hr);
933 goto error;
934 }
935
936 hr = IDXVAHD_Device_CreateVideoProcessor( hd_device, &capsList->VPGuid, &sys->processor.proc );
937 if (FAILED(hr))
938 {
939 msg_Dbg(vd, "Failed to create the processor (error 0x%lX)", hr);
940 goto error;
941 }
942 IDXVAHD_Device_Release( hd_device );
943
944 SetupProcessorInput(vd, &vd->source, d3dfmt);
945
946 DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE_DATA colorspace;
947 colorspace.Usage = 0; // playback
948 colorspace.RGB_Range = 0; // full range display
949 colorspace.YCbCr_xvYCC = 1;
950 colorspace.YCbCr_Matrix = 1; // BT.709
951 hr = IDXVAHD_VideoProcessor_SetVideoProcessBltState( sys->processor.proc, DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE, sizeof(colorspace), &colorspace);
952
953 return VLC_SUCCESS;
954
955 error:
956 free(capsList);
957 free(formatsList);
958 if (hd_device)
959 IDXVAHD_Device_Release(hd_device);
960 FreeLibrary(sys->processor.dll);
961 return VLC_EGENERIC;
962 }
963
964 /**
965 * It creates a Direct3D9 device and the associated resources.
966 */
Direct3D9Open(vout_display_t * vd,video_format_t * fmt)967 static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
968 {
969 vout_display_sys_t *sys = vd->sys;
970
971 if (FAILED(D3D9_CreateDevice(vd, &sys->hd3d, sys->sys.hvideownd,
972 &vd->source, &sys->d3d_dev)))
973 return VLC_EGENERIC;
974
975 const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
976 /* */
977 RECT *display = &vd->sys->sys.rect_display;
978 display->left = 0;
979 display->top = 0;
980 display->right = p_d3d9_dev->pp.BackBufferWidth;
981 display->bottom = p_d3d9_dev->pp.BackBufferHeight;
982
983 *fmt = vd->source;
984
985 /* Find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
986 * the requested chroma which is usable by the hardware in an offscreen surface, as they
987 * typically support more formats than textures */
988 const d3d9_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, p_d3d9_dev->pp.BackBufferFormat);
989 if (!d3dfmt) {
990 msg_Err(vd, "surface pixel format is not supported.");
991 goto error;
992 }
993 const d3d9_format_t *d3dbuffer = FindBufferFormat(vd, p_d3d9_dev->pp.BackBufferFormat);
994 if (!d3dbuffer)
995 msg_Warn(vd, "Unknown back buffer format 0x%X", p_d3d9_dev->pp.BackBufferFormat);
996 else if (!vd->source.b_color_range_full && d3dbuffer->rmask && !d3dfmt->rmask)
997 {
998 D3DADAPTER_IDENTIFIER9 d3dai;
999 if (sys->hd3d.use_ex && SUCCEEDED(IDirect3D9Ex_GetAdapterIdentifier(sys->hd3d.objex, sys->d3d_dev.adapterId, 0, &d3dai)) &&
1000 d3dai.VendorId == GPU_MANUFACTURER_NVIDIA) {
1001
1002 // NVIDIA bug, YUV to RGB internal conversion in StretchRect always converts from limited to limited range
1003 InitRangeProcessor( vd, d3dfmt );
1004 }
1005 }
1006
1007 fmt->i_chroma = d3dfmt->fourcc;
1008 fmt->i_rmask = d3dfmt->rmask;
1009 fmt->i_gmask = d3dfmt->gmask;
1010 fmt->i_bmask = d3dfmt->bmask;
1011 sys->d3dtexture_format = d3dfmt;
1012
1013 UpdateRects(vd, NULL, true);
1014
1015 if (Direct3D9CreateResources(vd, fmt)) {
1016 msg_Err(vd, "Failed to allocate resources");
1017 goto error;
1018 }
1019
1020 /* Change the window title bar text */
1021 EventThreadUpdateTitle(sys->sys.event, VOUT_TITLE " (Direct3D9 output)");
1022
1023 msg_Dbg(vd, "Direct3D9 device adapter successfully initialized");
1024 return VLC_SUCCESS;
1025
1026 error:
1027 D3D9_ReleaseDevice(&sys->d3d_dev);
1028 return VLC_EGENERIC;
1029 }
1030
1031 /**
1032 * It releases the Direct3D9 device and its resources.
1033 */
Direct3D9Close(vout_display_t * vd)1034 static void Direct3D9Close(vout_display_t *vd)
1035 {
1036 vout_display_sys_t *sys = vd->sys;
1037
1038 Direct3D9DestroyResources(vd);
1039 D3D9_ReleaseDevice(&sys->d3d_dev);
1040 }
1041
1042 /**
1043 * It reset the Direct3D9 device and its resources.
1044 */
Direct3D9Reset(vout_display_t * vd)1045 static int Direct3D9Reset(vout_display_t *vd)
1046 {
1047 vout_display_sys_t *sys = vd->sys;
1048 d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
1049
1050 if (D3D9_FillPresentationParameters(&sys->hd3d, &vd->source, p_d3d9_dev))
1051 {
1052 msg_Err(vd, "Could not presentation parameters to reset device");
1053 return VLC_EGENERIC;
1054 }
1055
1056 /* release all D3D objects */
1057 Direct3D9DestroyResources(vd);
1058
1059 /* */
1060 HRESULT hr;
1061 if (sys->hd3d.use_ex){
1062 hr = IDirect3DDevice9Ex_ResetEx(p_d3d9_dev->devex, &p_d3d9_dev->pp, NULL);
1063 } else {
1064 hr = IDirect3DDevice9_Reset(p_d3d9_dev->dev, &p_d3d9_dev->pp);
1065 }
1066 if (FAILED(hr)) {
1067 msg_Err(vd, "IDirect3DDevice9_Reset failed! (hr=0x%0lx)", hr);
1068 return VLC_EGENERIC;
1069 }
1070
1071 UpdateRects(vd, NULL, true);
1072
1073 /* re-create them */
1074 if (Direct3D9CreateResources(vd, &vd->fmt)) {
1075 msg_Dbg(vd, "Direct3D9CreateResources failed !");
1076 return VLC_EGENERIC;
1077 }
1078 return VLC_SUCCESS;
1079 }
1080
1081 /* */
1082 static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt);
1083 static void Direct3D9DestroyScene(vout_display_t *vd);
1084
1085 static int Direct3D9CreateShaders(vout_display_t *vd);
1086 static void Direct3D9DestroyShaders(vout_display_t *vd);
1087
1088 /**
1089 * It creates the picture and scene resources.
1090 */
Direct3D9CreateResources(vout_display_t * vd,video_format_t * fmt)1091 static int Direct3D9CreateResources(vout_display_t *vd, video_format_t *fmt)
1092 {
1093 vout_display_sys_t *sys = vd->sys;
1094
1095 if (Direct3D9CreateScene(vd, fmt)) {
1096 msg_Err(vd, "Direct3D scene initialization failed !");
1097 return VLC_EGENERIC;
1098 }
1099 if (Direct3D9CreateShaders(vd)) {
1100 /* Failing to initialize shaders is not fatal. */
1101 msg_Warn(vd, "Direct3D shaders initialization failed !");
1102 }
1103
1104 sys->d3dregion_format = D3DFMT_UNKNOWN;
1105 for (int i = 0; i < 2; i++) {
1106 D3DFORMAT dfmt = i == 0 ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8;
1107 if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(sys->hd3d.obj,
1108 D3DADAPTER_DEFAULT,
1109 D3DDEVTYPE_HAL,
1110 sys->d3d_dev.pp.BackBufferFormat,
1111 D3DUSAGE_DYNAMIC,
1112 D3DRTYPE_TEXTURE,
1113 dfmt))) {
1114 sys->d3dregion_format = dfmt;
1115 break;
1116 }
1117 }
1118 return VLC_SUCCESS;
1119 }
1120 /**
1121 * It destroys the picture and scene resources.
1122 */
Direct3D9DestroyResources(vout_display_t * vd)1123 static void Direct3D9DestroyResources(vout_display_t *vd)
1124 {
1125 Direct3D9DestroyScene(vd);
1126 if (vd->sys->sys.pool)
1127 {
1128 picture_pool_Release(vd->sys->sys.pool);
1129 vd->sys->sys.pool = NULL;
1130 }
1131 Direct3D9DestroyShaders(vd);
1132 }
1133
1134 /**
1135 * It tests if the conversion from src to dst is supported.
1136 */
Direct3D9CheckConversion(vout_display_t * vd,D3DFORMAT src,D3DFORMAT dst)1137 static int Direct3D9CheckConversion(vout_display_t *vd,
1138 D3DFORMAT src, D3DFORMAT dst)
1139 {
1140 vout_display_sys_t *sys = vd->sys;
1141 LPDIRECT3D9 d3dobj = sys->hd3d.obj;
1142 HRESULT hr;
1143
1144 /* test whether device can create a surface of that format */
1145 hr = IDirect3D9_CheckDeviceFormat(d3dobj, D3DADAPTER_DEFAULT,
1146 D3DDEVTYPE_HAL, dst, 0,
1147 D3DRTYPE_SURFACE, src);
1148 if (SUCCEEDED(hr)) {
1149 /* test whether device can perform color-conversion
1150 ** from that format to target format
1151 */
1152 hr = IDirect3D9_CheckDeviceFormatConversion(d3dobj,
1153 D3DADAPTER_DEFAULT,
1154 D3DDEVTYPE_HAL,
1155 src, dst);
1156 }
1157 if (!SUCCEEDED(hr)) {
1158 if (D3DERR_NOTAVAILABLE != hr)
1159 msg_Err(vd, "Could not query adapter supported formats. (hr=0x%0lx)", hr);
1160 return VLC_EGENERIC;
1161 }
1162 return VLC_SUCCESS;
1163 }
1164
1165 static const d3d9_format_t d3d_formats[] = {
1166 /* YV12 is always used for planar 420, the planes are then swapped in Lock() */
1167 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_YV12, 0,0,0 },
1168 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_I420, 0,0,0 },
1169 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_J420, 0,0,0 },
1170 { "NV12", MAKEFOURCC('N','V','1','2'), VLC_CODEC_NV12, 0,0,0 },
1171 { "DXA9", MAKEFOURCC('N','V','1','2'), VLC_CODEC_D3D9_OPAQUE, 0,0,0 },
1172 { "DXA9_10", MAKEFOURCC('P','0','1','0'), VLC_CODEC_D3D9_OPAQUE_10B, 0,0,0 },
1173 { "UYVY", D3DFMT_UYVY, VLC_CODEC_UYVY, 0,0,0 },
1174 { "YUY2", D3DFMT_YUY2, VLC_CODEC_YUYV, 0,0,0 },
1175 { "X8R8G8B8", D3DFMT_X8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
1176 { "A8R8G8B8", D3DFMT_A8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
1177 { "8G8B8", D3DFMT_R8G8B8, VLC_CODEC_RGB24, 0xff0000, 0x00ff00, 0x0000ff },
1178 { "R5G6B5", D3DFMT_R5G6B5, VLC_CODEC_RGB16, 0x1f<<11, 0x3f<<5, 0x1f<<0 },
1179 { "X1R5G5B5", D3DFMT_X1R5G5B5,VLC_CODEC_RGB15, 0x1f<<10, 0x1f<<5, 0x1f<<0 },
1180
1181 { NULL, 0, 0, 0,0,0}
1182 };
1183
FindBufferFormat(vout_display_t * vd,D3DFORMAT fmt)1184 static const d3d9_format_t *FindBufferFormat(vout_display_t *vd, D3DFORMAT fmt)
1185 {
1186 for (unsigned j = 0; d3d_formats[j].name; j++) {
1187 const d3d9_format_t *format = &d3d_formats[j];
1188
1189 if (format->format != fmt)
1190 continue;
1191
1192 return format;
1193 }
1194 return NULL;
1195 }
1196
1197 /**
1198 * It returns the format (closest to chroma) that can be converted to target */
Direct3DFindFormat(vout_display_t * vd,vlc_fourcc_t chroma,D3DFORMAT target)1199 static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
1200 {
1201 vout_display_sys_t *sys = vd->sys;
1202 bool hardware_scale_ok = !(vd->fmt.i_visible_width & 1) && !(vd->fmt.i_visible_height & 1);
1203 if( !hardware_scale_ok )
1204 msg_Warn( vd, "Disabling hardware chroma conversion due to odd dimensions" );
1205
1206 for (unsigned pass = 0; pass < 2; pass++) {
1207 const vlc_fourcc_t *list;
1208 const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
1209
1210 if (pass == 0 && is_d3d9_opaque(chroma))
1211 list = dxva_chroma;
1212 else if (pass == 0 && hardware_scale_ok && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
1213 list = vlc_fourcc_GetYUVFallback(chroma);
1214 else if (pass == 1)
1215 list = vlc_fourcc_GetRGBFallback(chroma);
1216 else
1217 continue;
1218
1219 for (unsigned i = 0; list[i] != 0; i++) {
1220 for (unsigned j = 0; d3d_formats[j].name; j++) {
1221 const d3d9_format_t *format = &d3d_formats[j];
1222
1223 if (format->fourcc != list[i])
1224 continue;
1225
1226 msg_Warn(vd, "trying surface pixel format: %s",
1227 format->name);
1228 if (!Direct3D9CheckConversion(vd, format->format, target)) {
1229 msg_Dbg(vd, "selected surface pixel format is %s",
1230 format->name);
1231 return format;
1232 }
1233 }
1234 }
1235 }
1236 return NULL;
1237 }
1238
1239 /**
1240 * It allocates and initializes the resources needed to render the scene.
1241 */
Direct3D9CreateScene(vout_display_t * vd,const video_format_t * fmt)1242 static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt)
1243 {
1244 vout_display_sys_t *sys = vd->sys;
1245 const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
1246 LPDIRECT3DDEVICE9 d3ddev = p_d3d9_dev->dev;
1247 HRESULT hr;
1248
1249 /*
1250 * Create a texture for use when rendering a scene
1251 * for performance reason, texture format is identical to backbuffer
1252 * which would usually be a RGB format
1253 */
1254 LPDIRECT3DTEXTURE9 d3dtex;
1255 hr = IDirect3DDevice9_CreateTexture(d3ddev,
1256 fmt->i_width,
1257 fmt->i_height,
1258 1,
1259 D3DUSAGE_RENDERTARGET,
1260 p_d3d9_dev->pp.BackBufferFormat,
1261 D3DPOOL_DEFAULT,
1262 &d3dtex,
1263 NULL);
1264 if (FAILED(hr)) {
1265 msg_Err(vd, "Failed to create texture. (hr=0x%lx)", hr);
1266 return VLC_EGENERIC;
1267 }
1268
1269 #ifndef NDEBUG
1270 msg_Dbg(vd, "Direct3D created texture: %ix%i",
1271 fmt->i_width, fmt->i_height);
1272 #endif
1273
1274 /*
1275 ** Create a vertex buffer for use when rendering scene
1276 */
1277 LPDIRECT3DVERTEXBUFFER9 d3dvtc;
1278 hr = IDirect3DDevice9_CreateVertexBuffer(d3ddev,
1279 sizeof(CUSTOMVERTEX)*4,
1280 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
1281 D3DFVF_CUSTOMVERTEX,
1282 D3DPOOL_DEFAULT,
1283 &d3dvtc,
1284 NULL);
1285 if (FAILED(hr)) {
1286 msg_Err(vd, "Failed to create vertex buffer. (hr=0x%lx)", hr);
1287 IDirect3DTexture9_Release(d3dtex);
1288 return VLC_EGENERIC;
1289 }
1290
1291 /* */
1292 sys->d3dtex = d3dtex;
1293 sys->d3dvtc = d3dvtc;
1294
1295 sys->d3dregion_count = 0;
1296 sys->d3dregion = NULL;
1297
1298 sys->clear_scene = true;
1299
1300 // Texture coordinates outside the range [0.0, 1.0] are set
1301 // to the texture color at 0.0 or 1.0, respectively.
1302 IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1303 IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1304
1305 // Set linear filtering quality
1306 if (sys->d3d_dev.caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) {
1307 //msg_Dbg(vd, "Using D3DTEXF_LINEAR for minification");
1308 IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1309 } else {
1310 //msg_Dbg(vd, "Using D3DTEXF_POINT for minification");
1311 IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
1312 }
1313 if (sys->d3d_dev.caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) {
1314 //msg_Dbg(vd, "Using D3DTEXF_LINEAR for magnification");
1315 IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1316 } else {
1317 //msg_Dbg(vd, "Using D3DTEXF_POINT for magnification");
1318 IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
1319 }
1320
1321 // set maximum ambient light
1322 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
1323
1324 // Turn off culling
1325 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_CULLMODE, D3DCULL_NONE);
1326
1327 // Turn off the zbuffer
1328 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ZENABLE, D3DZB_FALSE);
1329
1330 // Turn off lights
1331 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_LIGHTING, FALSE);
1332
1333 // Enable dithering
1334 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DITHERENABLE, TRUE);
1335
1336 // disable stencil
1337 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_STENCILENABLE, FALSE);
1338
1339 // manage blending
1340 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
1341 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
1342 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
1343
1344 if (sys->d3d_dev.caps.AlphaCmpCaps & D3DPCMPCAPS_GREATER) {
1345 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHATESTENABLE,TRUE);
1346 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHAREF, 0x00);
1347 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER);
1348 }
1349
1350 // Set texture states
1351 IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLOROP,D3DTOP_SELECTARG1);
1352 IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE);
1353
1354 IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
1355 IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1356 IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1357
1358 msg_Dbg(vd, "Direct3D9 scene created successfully");
1359
1360 return VLC_SUCCESS;
1361 }
1362
1363 /**
1364 * It releases the scene resources.
1365 */
Direct3D9DestroyScene(vout_display_t * vd)1366 static void Direct3D9DestroyScene(vout_display_t *vd)
1367 {
1368 vout_display_sys_t *sys = vd->sys;
1369
1370 Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
1371
1372 LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc;
1373 if (d3dvtc)
1374 IDirect3DVertexBuffer9_Release(d3dvtc);
1375
1376 LPDIRECT3DTEXTURE9 d3dtex = sys->d3dtex;
1377 if (d3dtex)
1378 IDirect3DTexture9_Release(d3dtex);
1379
1380 sys->d3dvtc = NULL;
1381 sys->d3dtex = NULL;
1382
1383 sys->d3dregion_count = 0;
1384 sys->d3dregion = NULL;
1385
1386 msg_Dbg(vd, "Direct3D9 scene released successfully");
1387 }
1388
Direct3D9CompileShader(vout_display_t * vd,const char * shader_source,size_t source_length)1389 static int Direct3D9CompileShader(vout_display_t *vd, const char *shader_source, size_t source_length)
1390 {
1391 #ifdef HAVE_D3DX9EFFECT_H
1392 vout_display_sys_t *sys = vd->sys;
1393
1394 HRESULT (WINAPI * OurD3DXCompileShader)(
1395 LPCSTR pSrcData,
1396 UINT srcDataLen,
1397 const D3DXMACRO *pDefines,
1398 LPD3DXINCLUDE pInclude,
1399 LPCSTR pFunctionName,
1400 LPCSTR pProfile,
1401 DWORD Flags,
1402 LPD3DXBUFFER *ppShader,
1403 LPD3DXBUFFER *ppErrorMsgs,
1404 LPD3DXCONSTANTTABLE *ppConstantTable);
1405
1406 OurD3DXCompileShader = (void*)GetProcAddress(sys->hxdll, "D3DXCompileShader");
1407 if (!OurD3DXCompileShader) {
1408 msg_Warn(vd, "Cannot locate reference to D3DXCompileShader; pixel shading will be disabled");
1409 return VLC_EGENERIC;
1410 }
1411
1412 LPD3DXBUFFER error_msgs = NULL;
1413 LPD3DXBUFFER compiled_shader = NULL;
1414
1415 DWORD shader_flags = 0;
1416 HRESULT hr = OurD3DXCompileShader(shader_source, source_length, NULL, NULL,
1417 "main", "ps_3_0", shader_flags, &compiled_shader, &error_msgs, NULL);
1418
1419 if (FAILED(hr)) {
1420 msg_Warn(vd, "D3DXCompileShader Error (hr=0x%0lx)", hr);
1421 if (error_msgs) {
1422 msg_Warn(vd, "HLSL Compilation Error: %s", (char*)ID3DXBuffer_GetBufferPointer(error_msgs));
1423 ID3DXBuffer_Release(error_msgs);
1424 }
1425 return VLC_EGENERIC;
1426 }
1427
1428 hr = IDirect3DDevice9_CreatePixelShader(sys->d3d_dev.dev,
1429 ID3DXBuffer_GetBufferPointer(compiled_shader),
1430 &sys->d3dx_shader);
1431
1432 if (compiled_shader)
1433 ID3DXBuffer_Release(compiled_shader);
1434 if (error_msgs)
1435 ID3DXBuffer_Release(error_msgs);
1436
1437 if (FAILED(hr)) {
1438 msg_Warn(vd, "IDirect3DDevice9_CreatePixelShader error (hr=0x%0lx)", hr);
1439 return VLC_EGENERIC;
1440 }
1441 return VLC_SUCCESS;
1442 #else
1443 return VLC_EGENERIC;
1444 #endif
1445 }
1446
1447 #define MAX_SHADER_FILE_SIZE 1024*1024
1448
Direct3D9CreateShaders(vout_display_t * vd)1449 static int Direct3D9CreateShaders(vout_display_t *vd)
1450 {
1451 vout_display_sys_t *sys = vd->sys;
1452
1453 if (!sys->hxdll)
1454 return VLC_EGENERIC;
1455
1456 /* Find which shader was selected in the list. */
1457 char *selected_shader = var_InheritString(vd, "direct3d9-shader");
1458 if (!selected_shader)
1459 return VLC_SUCCESS; /* Nothing to do */
1460
1461 const char *shader_source_builtin = NULL;
1462 char *shader_source_file = NULL;
1463 FILE *fs = NULL;
1464
1465 for (size_t i = 0; i < BUILTIN_SHADERS_COUNT; ++i) {
1466 if (!strcmp(selected_shader, builtin_shaders[i].name)) {
1467 shader_source_builtin = builtin_shaders[i].code;
1468 break;
1469 }
1470 }
1471
1472 if (shader_source_builtin) {
1473 /* A builtin shader was selected. */
1474 int err = Direct3D9CompileShader(vd, shader_source_builtin, strlen(shader_source_builtin));
1475 if (err)
1476 goto error;
1477 } else {
1478 if (strcmp(selected_shader, SELECTED_SHADER_FILE))
1479 goto error; /* Unrecognized entry in the list. */
1480 /* The source code of the shader needs to be read from a file. */
1481 char *filepath = var_InheritString(vd, "direct3d9-shader-file");
1482 if (!filepath || !*filepath)
1483 {
1484 free(filepath);
1485 goto error;
1486 }
1487 /* Open file, find its size with fseek/ftell and read its content in a buffer. */
1488 fs = fopen(filepath, "rb");
1489 if (!fs)
1490 goto error;
1491 int ret = fseek(fs, 0, SEEK_END);
1492 if (ret == -1)
1493 goto error;
1494 long length = ftell(fs);
1495 if (length == -1 || length >= MAX_SHADER_FILE_SIZE)
1496 goto error;
1497 rewind(fs);
1498 shader_source_file = vlc_alloc(length, sizeof(*shader_source_file));
1499 if (!shader_source_file)
1500 goto error;
1501 ret = fread(shader_source_file, length, 1, fs);
1502 if (ret != 1)
1503 goto error;
1504 ret = Direct3D9CompileShader(vd, shader_source_file, length);
1505 if (ret)
1506 goto error;
1507 }
1508
1509 free(selected_shader);
1510 free(shader_source_file);
1511 fclose(fs);
1512
1513 return VLC_SUCCESS;
1514
1515 error:
1516 Direct3D9DestroyShaders(vd);
1517 free(selected_shader);
1518 free(shader_source_file);
1519 if (fs)
1520 fclose(fs);
1521 return VLC_EGENERIC;
1522 }
1523
Direct3D9DestroyShaders(vout_display_t * vd)1524 static void Direct3D9DestroyShaders(vout_display_t *vd)
1525 {
1526 vout_display_sys_t *sys = vd->sys;
1527
1528 if (sys->d3dx_shader)
1529 IDirect3DPixelShader9_Release(sys->d3dx_shader);
1530 sys->d3dx_shader = NULL;
1531 }
1532
1533 /**
1534 * Compute the vertex ordering needed to rotate the video. Without
1535 * rotation, the vertices of the rectangle are defined in a clockwise
1536 * order. This function computes a remapping of the coordinates to
1537 * implement the rotation, given fixed texture coordinates.
1538 * The unrotated order is the following:
1539 * 0--1
1540 * | |
1541 * 3--2
1542 * For a 180 degrees rotation it should like this:
1543 * 2--3
1544 * | |
1545 * 1--0
1546 * Vertex 0 should be assigned coordinates at index 2 from the
1547 * unrotated order and so on, thus yielding order: 2 3 0 1.
1548 */
orientationVertexOrder(video_orientation_t orientation,int vertex_order[static4])1549 static void orientationVertexOrder(video_orientation_t orientation, int vertex_order[static 4])
1550 {
1551 switch (orientation) {
1552 case ORIENT_ROTATED_90: /* ORIENT_RIGHT_TOP */
1553 vertex_order[0] = 1;
1554 vertex_order[1] = 2;
1555 vertex_order[2] = 3;
1556 vertex_order[3] = 0;
1557 break;
1558 case ORIENT_ROTATED_270: /* ORIENT_LEFT_BOTTOM */
1559 vertex_order[0] = 3;
1560 vertex_order[1] = 0;
1561 vertex_order[2] = 1;
1562 vertex_order[3] = 2;
1563 break;
1564 case ORIENT_ROTATED_180: /* ORIENT_BOTTOM_RIGHT */
1565 vertex_order[0] = 2;
1566 vertex_order[1] = 3;
1567 vertex_order[2] = 0;
1568 vertex_order[3] = 1;
1569 break;
1570 case ORIENT_TRANSPOSED: /* ORIENT_LEFT_TOP */
1571 vertex_order[0] = 0;
1572 vertex_order[1] = 3;
1573 vertex_order[2] = 2;
1574 vertex_order[3] = 1;
1575 break;
1576 case ORIENT_HFLIPPED: /* ORIENT_TOP_RIGHT */
1577 vertex_order[0] = 1;
1578 vertex_order[1] = 0;
1579 vertex_order[2] = 3;
1580 vertex_order[3] = 2;
1581 break;
1582 case ORIENT_VFLIPPED: /* ORIENT_BOTTOM_LEFT */
1583 vertex_order[0] = 3;
1584 vertex_order[1] = 2;
1585 vertex_order[2] = 1;
1586 vertex_order[3] = 0;
1587 break;
1588 case ORIENT_ANTI_TRANSPOSED: /* ORIENT_RIGHT_BOTTOM */
1589 vertex_order[0] = 2;
1590 vertex_order[1] = 1;
1591 vertex_order[2] = 0;
1592 vertex_order[3] = 3;
1593 break;
1594 default:
1595 vertex_order[0] = 0;
1596 vertex_order[1] = 1;
1597 vertex_order[2] = 2;
1598 vertex_order[3] = 3;
1599 break;
1600 }
1601 }
1602
Direct3D9SetupVertices(CUSTOMVERTEX * vertices,const RECT * src,const RECT * src_clipped,const RECT * dst,int alpha,video_orientation_t orientation)1603 static void Direct3D9SetupVertices(CUSTOMVERTEX *vertices,
1604 const RECT *src, const RECT *src_clipped,
1605 const RECT *dst,
1606 int alpha,
1607 video_orientation_t orientation)
1608 {
1609 /* Vertices of the dst rectangle in the unrotated (clockwise) order. */
1610 const int vertices_coords[4][2] = {
1611 { dst->left, dst->top },
1612 { dst->right, dst->top },
1613 { dst->right, dst->bottom },
1614 { dst->left, dst->bottom },
1615 };
1616
1617 /* Compute index remapping necessary to implement the rotation. */
1618 int vertex_order[4];
1619 orientationVertexOrder(orientation, vertex_order);
1620
1621 for (int i = 0; i < 4; ++i) {
1622 vertices[i].x = vertices_coords[vertex_order[i]][0];
1623 vertices[i].y = vertices_coords[vertex_order[i]][1];
1624 }
1625
1626 float right = (float)src_clipped->right / (float)src->right;
1627 float left = (float)src_clipped->left / (float)src->right;
1628 float top = (float)src_clipped->top / (float)src->bottom;
1629 float bottom = (float)src_clipped->bottom / (float)src->bottom;
1630
1631 vertices[0].tu = left;
1632 vertices[0].tv = top;
1633
1634 vertices[1].tu = right;
1635 vertices[1].tv = top;
1636
1637 vertices[2].tu = right;
1638 vertices[2].tv = bottom;
1639
1640 vertices[3].tu = left;
1641 vertices[3].tv = bottom;
1642
1643 for (int i = 0; i < 4; i++) {
1644 /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
1645 /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
1646 vertices[i].x -= 0.5;
1647 vertices[i].y -= 0.5;
1648
1649 vertices[i].z = 0.0f;
1650 vertices[i].rhw = 1.0f;
1651 vertices[i].diffuse = D3DCOLOR_ARGB(alpha, 255, 255, 255);
1652 }
1653 }
1654
1655 /**
1656 * It copies picture surface into a texture and setup the associated d3d_region_t.
1657 */
Direct3D9ImportPicture(vout_display_t * vd,d3d_region_t * region,LPDIRECT3DSURFACE9 source)1658 static int Direct3D9ImportPicture(vout_display_t *vd,
1659 d3d_region_t *region,
1660 LPDIRECT3DSURFACE9 source)
1661 {
1662 vout_display_sys_t *sys = vd->sys;
1663 HRESULT hr;
1664
1665 if (!source) {
1666 msg_Dbg(vd, "no surface to render?");
1667 return VLC_EGENERIC;
1668 }
1669
1670 /* retrieve texture top-level surface */
1671 LPDIRECT3DSURFACE9 destination;
1672 hr = IDirect3DTexture9_GetSurfaceLevel(sys->d3dtex, 0, &destination);
1673 if (FAILED(hr)) {
1674 msg_Dbg(vd, "Failed IDirect3DTexture9_GetSurfaceLevel: 0x%0lx", hr);
1675 return VLC_EGENERIC;
1676 }
1677
1678 if (sys->processor.proc)
1679 {
1680 DXVAHD_STREAM_DATA inputStream = { 0 };
1681 inputStream.Enable = TRUE;
1682 inputStream.pInputSurface = source;
1683 hr = IDXVAHD_VideoProcessor_VideoProcessBltHD( sys->processor.proc, destination, 0, 1, &inputStream );
1684 }
1685 else
1686 {
1687 /* Copy picture surface into texture surface
1688 * color space conversion happen here */
1689 RECT copy_rect = sys->sys.rect_src_clipped;
1690 // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
1691 // When copying the entire buffer, the margin end up being blended in the actual picture
1692 // on nVidia (regardless of even/odd dimensions)
1693 if ( copy_rect.right & 1 ) copy_rect.right++;
1694 if ( copy_rect.left & 1 ) copy_rect.left--;
1695 if ( copy_rect.bottom & 1 ) copy_rect.bottom++;
1696 if ( copy_rect.top & 1 ) copy_rect.top--;
1697 hr = IDirect3DDevice9_StretchRect(sys->d3d_dev.dev, source, ©_rect, destination,
1698 ©_rect, D3DTEXF_NONE);
1699 }
1700 IDirect3DSurface9_Release(destination);
1701 if (FAILED(hr)) {
1702 msg_Dbg(vd, "Failed IDirect3DDevice9_StretchRect: source 0x%p 0x%0lx",
1703 (LPVOID)source, hr);
1704 return VLC_EGENERIC;
1705 }
1706
1707 /* */
1708 region->texture = sys->d3dtex;
1709 Direct3D9SetupVertices(region->vertex, &vd->sys->sys.rect_src, &vd->sys->sys.rect_src_clipped,
1710 &vd->sys->sys.rect_dest_clipped, 255, vd->fmt.orientation);
1711 return VLC_SUCCESS;
1712 }
1713
Direct3D9DeleteRegions(int count,d3d_region_t * region)1714 static void Direct3D9DeleteRegions(int count, d3d_region_t *region)
1715 {
1716 for (int i = 0; i < count; i++) {
1717 if (region[i].texture)
1718 IDirect3DTexture9_Release(region[i].texture);
1719 }
1720 free(region);
1721 }
1722
Direct3D9ImportSubpicture(vout_display_t * vd,int * count_ptr,d3d_region_t ** region,subpicture_t * subpicture)1723 static void Direct3D9ImportSubpicture(vout_display_t *vd,
1724 int *count_ptr, d3d_region_t **region,
1725 subpicture_t *subpicture)
1726 {
1727 vout_display_sys_t *sys = vd->sys;
1728
1729 int count = 0;
1730 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
1731 count++;
1732
1733 *count_ptr = count;
1734 *region = calloc(count, sizeof(**region));
1735 if (*region == NULL) {
1736 *count_ptr = 0;
1737 return;
1738 }
1739
1740 int i = 0;
1741 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
1742 d3d_region_t *d3dr = &(*region)[i];
1743 HRESULT hr;
1744
1745 d3dr->texture = NULL;
1746 for (int j = 0; j < sys->d3dregion_count; j++) {
1747 d3d_region_t *cache = &sys->d3dregion[j];
1748 if (cache->texture &&
1749 cache->format == sys->d3dregion_format &&
1750 cache->width == r->fmt.i_width &&
1751 cache->height == r->fmt.i_height) {
1752 *d3dr = *cache;
1753 memset(cache, 0, sizeof(*cache));
1754 break;
1755 }
1756 }
1757 if (!d3dr->texture) {
1758 d3dr->format = sys->d3dregion_format;
1759 d3dr->width = r->fmt.i_width;
1760 d3dr->height = r->fmt.i_height;
1761 hr = IDirect3DDevice9_CreateTexture(sys->d3d_dev.dev,
1762 d3dr->width, d3dr->height,
1763 1,
1764 D3DUSAGE_DYNAMIC,
1765 d3dr->format,
1766 D3DPOOL_DEFAULT,
1767 &d3dr->texture,
1768 NULL);
1769 if (FAILED(hr)) {
1770 d3dr->texture = NULL;
1771 msg_Err(vd, "Failed to create %dx%d texture for OSD (hr=0x%0lx)",
1772 d3dr->width, d3dr->height, hr);
1773 continue;
1774 }
1775 #ifndef NDEBUG
1776 msg_Dbg(vd, "Created %dx%d texture for OSD",
1777 r->fmt.i_width, r->fmt.i_height);
1778 #endif
1779 }
1780
1781 D3DLOCKED_RECT lock;
1782 hr = IDirect3DTexture9_LockRect(d3dr->texture, 0, &lock, NULL, 0);
1783 if (SUCCEEDED(hr)) {
1784 uint8_t *dst_data = lock.pBits;
1785 int dst_pitch = lock.Pitch;
1786 uint8_t *src_data = r->p_picture->p->p_pixels;
1787 int src_pitch = r->p_picture->p->i_pitch;
1788
1789 if (d3dr->format == D3DFMT_A8B8G8R8) {
1790 if (dst_pitch == r->p_picture->p->i_pitch) {
1791 memcpy(dst_data, src_data, r->fmt.i_height * dst_pitch);
1792 } else {
1793 int copy_pitch = __MIN(dst_pitch, r->p_picture->p->i_pitch);
1794 for (unsigned y = 0; y < r->fmt.i_height; y++) {
1795 memcpy(&dst_data[y * dst_pitch], &src_data[y * src_pitch], copy_pitch);
1796 }
1797 }
1798 } else {
1799 int copy_pitch = __MIN(dst_pitch, r->p_picture->p->i_pitch);
1800 for (unsigned y = 0; y < r->fmt.i_height; y++) {
1801 for (int x = 0; x < copy_pitch; x += 4) {
1802 dst_data[y * dst_pitch + x + 0] = src_data[y * src_pitch + x + 2];
1803 dst_data[y * dst_pitch + x + 1] = src_data[y * src_pitch + x + 1];
1804 dst_data[y * dst_pitch + x + 2] = src_data[y * src_pitch + x + 0];
1805 dst_data[y * dst_pitch + x + 3] = src_data[y * src_pitch + x + 3];
1806 }
1807 }
1808 }
1809 hr = IDirect3DTexture9_UnlockRect(d3dr->texture, 0);
1810 if (FAILED(hr))
1811 msg_Err(vd, "Failed to unlock the texture");
1812 } else {
1813 msg_Err(vd, "Failed to lock the texture");
1814 }
1815
1816 /* Map the subpicture to sys->sys.rect_dest */
1817 const RECT video = sys->sys.rect_dest;
1818 const float scale_w = (float)(video.right - video.left) / subpicture->i_original_picture_width;
1819 const float scale_h = (float)(video.bottom - video.top) / subpicture->i_original_picture_height;
1820
1821 RECT dst;
1822 dst.left = video.left + scale_w * r->i_x,
1823 dst.right = dst.left + scale_w * r->fmt.i_visible_width,
1824 dst.top = video.top + scale_h * r->i_y,
1825 dst.bottom = dst.top + scale_h * r->fmt.i_visible_height;
1826
1827 RECT src;
1828 src.left = 0;
1829 src.right = r->fmt.i_width;
1830 src.top = 0;
1831 src.bottom = r->fmt.i_height;
1832
1833 RECT src_clipped;
1834 src_clipped.left = r->fmt.i_x_offset;
1835 src_clipped.right = r->fmt.i_x_offset + r->fmt.i_visible_width;
1836 src_clipped.top = r->fmt.i_y_offset;
1837 src_clipped.bottom = r->fmt.i_y_offset + r->fmt.i_visible_height;
1838
1839 Direct3D9SetupVertices(d3dr->vertex, &src, &src_clipped,
1840 &dst, subpicture->i_alpha * r->i_alpha / 255, ORIENT_NORMAL);
1841 }
1842 }
1843
Direct3D9RenderRegion(vout_display_t * vd,d3d_region_t * region,bool use_pixel_shader)1844 static int Direct3D9RenderRegion(vout_display_t *vd,
1845 d3d_region_t *region,
1846 bool use_pixel_shader)
1847 {
1848 vout_display_sys_t *sys = vd->sys;
1849
1850 LPDIRECT3DDEVICE9 d3ddev = vd->sys->d3d_dev.dev;
1851
1852 LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc;
1853 LPDIRECT3DTEXTURE9 d3dtex = region->texture;
1854
1855 HRESULT hr;
1856
1857 /* Import vertices */
1858 void *vertex;
1859 hr = IDirect3DVertexBuffer9_Lock(d3dvtc, 0, 0, &vertex, D3DLOCK_DISCARD);
1860 if (FAILED(hr)) {
1861 msg_Dbg(vd, "Failed IDirect3DVertexBuffer9_Lock: 0x%0lx", hr);
1862 return -1;
1863 }
1864 memcpy(vertex, region->vertex, sizeof(region->vertex));
1865 hr = IDirect3DVertexBuffer9_Unlock(d3dvtc);
1866 if (FAILED(hr)) {
1867 msg_Dbg(vd, "Failed IDirect3DVertexBuffer9_Unlock: 0x%0lx", hr);
1868 return -1;
1869 }
1870
1871 // Setup our texture. Using textures introduces the texture stage states,
1872 // which govern how textures get blended together (in the case of multiple
1873 // textures) and lighting information. In this case, we are modulating
1874 // (blending) our texture with the diffuse color of the vertices.
1875 hr = IDirect3DDevice9_SetTexture(d3ddev, 0, (LPDIRECT3DBASETEXTURE9)d3dtex);
1876 if (FAILED(hr)) {
1877 msg_Dbg(vd, "Failed IDirect3DDevice9_SetTexture: 0x%0lx", hr);
1878 return -1;
1879 }
1880
1881 if (sys->d3dx_shader) {
1882 if (use_pixel_shader)
1883 {
1884 hr = IDirect3DDevice9_SetPixelShader(d3ddev, sys->d3dx_shader);
1885 float shader_data[4] = { region->width, region->height, 0, 0 };
1886 hr = IDirect3DDevice9_SetPixelShaderConstantF(d3ddev, 0, shader_data, 1);
1887 if (FAILED(hr)) {
1888 msg_Dbg(vd, "Failed IDirect3DDevice9_SetPixelShaderConstantF: 0x%0lx", hr);
1889 return -1;
1890 }
1891 }
1892 else /* Disable any existing pixel shader. */
1893 hr = IDirect3DDevice9_SetPixelShader(d3ddev, NULL);
1894 if (FAILED(hr)) {
1895 msg_Dbg(vd, "Failed IDirect3DDevice9_SetPixelShader: 0x%0lx", hr);
1896 return -1;
1897 }
1898 }
1899
1900 // Render the vertex buffer contents
1901 hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, d3dvtc, 0, sizeof(CUSTOMVERTEX));
1902 if (FAILED(hr)) {
1903 msg_Dbg(vd, "Failed IDirect3DDevice9_SetStreamSource: 0x%0lx", hr);
1904 return -1;
1905 }
1906
1907 // we use FVF instead of vertex shader
1908 hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
1909 if (FAILED(hr)) {
1910 msg_Dbg(vd, "Failed IDirect3DDevice9_SetFVF: 0x%0lx", hr);
1911 return -1;
1912 }
1913
1914 // draw rectangle
1915 hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
1916 if (FAILED(hr)) {
1917 msg_Dbg(vd, "Failed IDirect3DDevice9_DrawPrimitive: 0x%0lx", hr);
1918 return -1;
1919 }
1920 return 0;
1921 }
1922
1923 /**
1924 * It renders the scene.
1925 *
1926 * This function is intented for higher end 3D cards, with pixel shader support
1927 * and at least 64 MiB of video RAM.
1928 */
Direct3D9RenderScene(vout_display_t * vd,d3d_region_t * picture,int subpicture_count,d3d_region_t * subpicture)1929 static void Direct3D9RenderScene(vout_display_t *vd,
1930 d3d_region_t *picture,
1931 int subpicture_count,
1932 d3d_region_t *subpicture)
1933 {
1934 vout_display_sys_t *sys = vd->sys;
1935 LPDIRECT3DDEVICE9 d3ddev = sys->d3d_dev.dev;
1936 HRESULT hr;
1937
1938 if (sys->clear_scene) {
1939 /* Clear the backbuffer and the zbuffer */
1940 hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET,
1941 D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1942 if (FAILED(hr)) {
1943 msg_Dbg(vd, "Failed IDirect3DDevice9_Clear: 0x%0lx", hr);
1944 return;
1945 }
1946 sys->clear_scene = false;
1947 }
1948
1949 // Begin the scene
1950 hr = IDirect3DDevice9_BeginScene(d3ddev);
1951 if (FAILED(hr)) {
1952 msg_Dbg(vd, "Failed IDirect3DDevice9_BeginScene: 0x%0lx", hr);
1953 return;
1954 }
1955
1956 Direct3D9RenderRegion(vd, picture, true);
1957
1958 if (subpicture_count > 0)
1959 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
1960 for (int i = 0; i < subpicture_count; i++) {
1961 d3d_region_t *r = &subpicture[i];
1962 if (r->texture)
1963 Direct3D9RenderRegion(vd, r, false);
1964 }
1965 if (subpicture_count > 0)
1966 IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
1967
1968 // End the scene
1969 hr = IDirect3DDevice9_EndScene(d3ddev);
1970 if (FAILED(hr)) {
1971 msg_Dbg(vd, "Failed IDirect3DDevice9_EndScene: 0x%0lx", hr);
1972 return;
1973 }
1974 }
1975
1976 /*****************************************************************************
1977 * DesktopCallback: desktop mode variable callback
1978 *****************************************************************************/
DesktopCallback(vlc_object_t * object,char const * psz_cmd,vlc_value_t oldval,vlc_value_t newval,void * p_data)1979 static int DesktopCallback(vlc_object_t *object, char const *psz_cmd,
1980 vlc_value_t oldval, vlc_value_t newval,
1981 void *p_data)
1982 {
1983 vout_display_t *vd = (vout_display_t *)object;
1984 vout_display_sys_t *sys = vd->sys;
1985 VLC_UNUSED(psz_cmd);
1986 VLC_UNUSED(oldval);
1987 VLC_UNUSED(p_data);
1988
1989 vlc_mutex_lock(&sys->lock);
1990 const bool ch_desktop = !sys->desktop_requested != !newval.b_bool;
1991 sys->ch_desktop |= ch_desktop;
1992 sys->desktop_requested = newval.b_bool;
1993 vlc_mutex_unlock(&sys->lock);
1994 return VLC_SUCCESS;
1995 }
1996
1997 typedef struct
1998 {
1999 char **values;
2000 char **descs;
2001 size_t count;
2002 } enum_context_t;
2003
ListShaders(enum_context_t * ctx)2004 static void ListShaders(enum_context_t *ctx)
2005 {
2006 size_t num_shaders = BUILTIN_SHADERS_COUNT;
2007 ctx->values = xrealloc(ctx->values, (ctx->count + num_shaders + 1) * sizeof(char *));
2008 ctx->descs = xrealloc(ctx->descs, (ctx->count + num_shaders + 1) * sizeof(char *));
2009 for (size_t i = 0; i < num_shaders; ++i) {
2010 ctx->values[ctx->count] = strdup(builtin_shaders[i].name);
2011 ctx->descs[ctx->count] = strdup(builtin_shaders[i].name);
2012 ctx->count++;
2013 }
2014 ctx->values[ctx->count] = strdup(SELECTED_SHADER_FILE);
2015 ctx->descs[ctx->count] = strdup(SELECTED_SHADER_FILE);
2016 ctx->count++;
2017 }
2018
2019 /* Populate the list of available shader techniques in the options */
FindShadersCallback(vlc_object_t * object,const char * name,char *** values,char *** descs)2020 static int FindShadersCallback(vlc_object_t *object, const char *name,
2021 char ***values, char ***descs)
2022 {
2023 VLC_UNUSED(object);
2024 VLC_UNUSED(name);
2025
2026 enum_context_t ctx = { NULL, NULL, 0 };
2027
2028 ListShaders(&ctx);
2029
2030 *values = ctx.values;
2031 *descs = ctx.descs;
2032 return ctx.count;
2033
2034 }
2035
2036 #ifdef HAVE_GL
2037 #include "../opengl/converter.h"
2038 #include <GL/wglew.h>
2039
2040 struct wgl_vt {
2041 PFNWGLDXSETRESOURCESHAREHANDLENVPROC DXSetResourceShareHandleNV;
2042 PFNWGLDXOPENDEVICENVPROC DXOpenDeviceNV;
2043 PFNWGLDXCLOSEDEVICENVPROC DXCloseDeviceNV;
2044 PFNWGLDXREGISTEROBJECTNVPROC DXRegisterObjectNV;
2045 PFNWGLDXUNREGISTEROBJECTNVPROC DXUnregisterObjectNV;
2046 PFNWGLDXLOCKOBJECTSNVPROC DXLockObjectsNV;
2047 PFNWGLDXUNLOCKOBJECTSNVPROC DXUnlockObjectsNV;
2048 };
2049 struct glpriv
2050 {
2051 struct wgl_vt vt;
2052 d3d9_handle_t hd3d;
2053 d3d9_device_t d3d_dev;
2054 HANDLE gl_handle_d3d;
2055 HANDLE gl_render;
2056 IDirect3DSurface9 *dx_render;
2057 };
2058
2059 static int
GLConvUpdate(const opengl_tex_converter_t * tc,GLuint * textures,const GLsizei * tex_width,const GLsizei * tex_height,picture_t * pic,const size_t * plane_offset)2060 GLConvUpdate(const opengl_tex_converter_t *tc, GLuint *textures,
2061 const GLsizei *tex_width, const GLsizei *tex_height,
2062 picture_t *pic, const size_t *plane_offset)
2063 {
2064 VLC_UNUSED(textures); VLC_UNUSED(tex_width); VLC_UNUSED(tex_height); VLC_UNUSED(plane_offset);
2065 struct glpriv *priv = tc->priv;
2066 HRESULT hr;
2067
2068 picture_sys_t *picsys = ActivePictureSys(pic);
2069 if (unlikely(!picsys || !priv->gl_render))
2070 return VLC_EGENERIC;
2071
2072 if (!priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
2073 {
2074 msg_Warn(tc->gl, "DXUnlockObjectsNV failed");
2075 return VLC_EGENERIC;
2076 }
2077
2078 const RECT rect = {
2079 .left = 0,
2080 .top = 0,
2081 .right = pic->format.i_visible_width,
2082 .bottom = pic->format.i_visible_height
2083 };
2084 hr = IDirect3DDevice9Ex_StretchRect(priv->d3d_dev.devex, picsys->surface,
2085 &rect, priv->dx_render, NULL, D3DTEXF_NONE);
2086 if (FAILED(hr))
2087 {
2088 msg_Warn(tc->gl, "IDirect3DDevice9Ex_StretchRect failed");
2089 return VLC_EGENERIC;
2090 }
2091
2092 if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
2093 {
2094 msg_Warn(tc->gl, "DXLockObjectsNV failed");
2095 priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
2096 priv->gl_render = NULL;
2097 return VLC_EGENERIC;
2098 }
2099
2100 return VLC_SUCCESS;
2101 }
2102
2103 static picture_pool_t *
GLConvGetPool(const opengl_tex_converter_t * tc,unsigned requested_count)2104 GLConvGetPool(const opengl_tex_converter_t *tc, unsigned requested_count)
2105 {
2106 struct glpriv *priv = tc->priv;
2107 return Direct3D9CreatePicturePool(VLC_OBJECT(tc->gl), &priv->d3d_dev, NULL,
2108 &tc->fmt, requested_count);
2109 }
2110
2111 static int
GLConvAllocateTextures(const opengl_tex_converter_t * tc,GLuint * textures,const GLsizei * tex_width,const GLsizei * tex_height)2112 GLConvAllocateTextures(const opengl_tex_converter_t *tc, GLuint *textures,
2113 const GLsizei *tex_width, const GLsizei *tex_height)
2114 {
2115 VLC_UNUSED(tex_width); VLC_UNUSED(tex_height);
2116 struct glpriv *priv = tc->priv;
2117
2118 priv->gl_render =
2119 priv->vt.DXRegisterObjectNV(priv->gl_handle_d3d, priv->dx_render,
2120 textures[0], GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV);
2121 if (!priv->gl_render)
2122 {
2123 msg_Warn(tc->gl, "DXRegisterObjectNV failed: %lu", GetLastError());
2124 return VLC_EGENERIC;
2125 }
2126
2127 if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
2128 {
2129 msg_Warn(tc->gl, "DXLockObjectsNV failed");
2130 priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
2131 priv->gl_render = NULL;
2132 return VLC_EGENERIC;
2133 }
2134
2135 return VLC_SUCCESS;
2136 }
2137
2138 static void
GLConvClose(vlc_object_t * obj)2139 GLConvClose(vlc_object_t *obj)
2140 {
2141 opengl_tex_converter_t *tc = (void *)obj;
2142 struct glpriv *priv = tc->priv;
2143
2144 if (priv->gl_handle_d3d)
2145 {
2146 if (priv->gl_render)
2147 {
2148 priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render);
2149 priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
2150 }
2151
2152 priv->vt.DXCloseDeviceNV(priv->gl_handle_d3d);
2153 }
2154
2155 if (priv->dx_render)
2156 IDirect3DSurface9_Release(priv->dx_render);
2157
2158 D3D9_ReleaseDevice(&priv->d3d_dev);
2159 D3D9_Destroy(&priv->hd3d);
2160 free(tc->priv);
2161 }
2162
2163 static int
GLConvOpen(vlc_object_t * obj)2164 GLConvOpen(vlc_object_t *obj)
2165 {
2166 opengl_tex_converter_t *tc = (void *) obj;
2167
2168 if (tc->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE
2169 && tc->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
2170 return VLC_EGENERIC;
2171
2172 if (tc->gl->ext != VLC_GL_EXT_WGL || !tc->gl->wgl.getExtensionsString)
2173 return VLC_EGENERIC;
2174
2175 const char *wglExt = tc->gl->wgl.getExtensionsString(tc->gl);
2176
2177 if (wglExt == NULL || !HasExtension(wglExt, "WGL_NV_DX_interop"))
2178 return VLC_EGENERIC;
2179
2180 struct wgl_vt vt;
2181 #define LOAD_EXT(name, type) do { \
2182 vt.name = (type) vlc_gl_GetProcAddress(tc->gl, "wgl" #name); \
2183 if (!vt.name) { \
2184 msg_Warn(obj, "'wgl " #name "' could not be loaded"); \
2185 return VLC_EGENERIC; \
2186 } \
2187 } while(0)
2188
2189 LOAD_EXT(DXSetResourceShareHandleNV, PFNWGLDXSETRESOURCESHAREHANDLENVPROC);
2190 LOAD_EXT(DXOpenDeviceNV, PFNWGLDXOPENDEVICENVPROC);
2191 LOAD_EXT(DXCloseDeviceNV, PFNWGLDXCLOSEDEVICENVPROC);
2192 LOAD_EXT(DXRegisterObjectNV, PFNWGLDXREGISTEROBJECTNVPROC);
2193 LOAD_EXT(DXUnregisterObjectNV, PFNWGLDXUNREGISTEROBJECTNVPROC);
2194 LOAD_EXT(DXLockObjectsNV, PFNWGLDXLOCKOBJECTSNVPROC);
2195 LOAD_EXT(DXUnlockObjectsNV, PFNWGLDXUNLOCKOBJECTSNVPROC);
2196
2197 struct glpriv *priv = calloc(1, sizeof(struct glpriv));
2198 if (!priv)
2199 return VLC_ENOMEM;
2200 tc->priv = priv;
2201 priv->vt = vt;
2202
2203 if (D3D9_Create(obj, &priv->hd3d) != VLC_SUCCESS)
2204 goto error;
2205
2206 if (!priv->hd3d.use_ex)
2207 {
2208 msg_Warn(obj, "DX/GL interrop only working on d3d9x");
2209 goto error;
2210 }
2211
2212 if (FAILED(D3D9_CreateDevice(obj, &priv->hd3d, tc->gl->surface->handle.hwnd,
2213 &tc->fmt, &priv->d3d_dev)))
2214 goto error;
2215
2216 HRESULT hr;
2217 HANDLE shared_handle = NULL;
2218 hr = IDirect3DDevice9Ex_CreateRenderTarget(priv->d3d_dev.devex,
2219 tc->fmt.i_visible_width,
2220 tc->fmt.i_visible_height,
2221 D3DFMT_X8R8G8B8,
2222 D3DMULTISAMPLE_NONE, 0, FALSE,
2223 &priv->dx_render, &shared_handle);
2224 if (FAILED(hr))
2225 {
2226 msg_Warn(obj, "IDirect3DDevice9_CreateOffscreenPlainSurface failed");
2227 goto error;
2228 }
2229
2230 if (shared_handle)
2231 priv->vt.DXSetResourceShareHandleNV(priv->dx_render, shared_handle);
2232
2233 priv->gl_handle_d3d = priv->vt.DXOpenDeviceNV(priv->d3d_dev.dev);
2234 if (!priv->gl_handle_d3d)
2235 {
2236 msg_Warn(obj, "DXOpenDeviceNV failed: %lu", GetLastError());
2237 goto error;
2238 }
2239
2240 tc->pf_update = GLConvUpdate;
2241 tc->pf_get_pool = GLConvGetPool;
2242 tc->pf_allocate_textures = GLConvAllocateTextures;
2243
2244 tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, VLC_CODEC_RGB32,
2245 COLOR_SPACE_UNDEF);
2246 if (tc->fshader == 0)
2247 goto error;
2248
2249 return VLC_SUCCESS;
2250
2251 error:
2252 GLConvClose(obj);
2253 return VLC_EGENERIC;
2254 }
2255 #endif
2256