directx.c 47.7 KB
Newer Older
1
/*****************************************************************************
2
 * directx.c: Windows DirectDraw video output
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001-2009 VLC authors and VideoLAN
5
 * $Id$
6
 *
gbazin's avatar
gbazin committed
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
gbazin's avatar
   
gbazin committed
8
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
9
10
11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
gbazin's avatar
   
gbazin committed
13
 *
14
15
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
16
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
19
20
21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
23
24
 *****************************************************************************/

/*****************************************************************************
gbazin's avatar
   
gbazin committed
25
26
27
28
29
30
31
32
33
34
 * Preamble:
 *
 * This plugin will use YUV overlay if supported, using overlay will result in
 * the best video quality (hardware interpolation when rescaling the picture)
 * and the fastest display as it requires less processing.
 *
 * If YUV overlay is not supported this plugin will use RGB offscreen video
 * surfaces that will be blitted onto the primary surface (display) to
 * effectively display the pictures. This fallback method also enables us to
 * display video in window mode.
35
 *
36
 *****************************************************************************/
37
38
39
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
40
#include <assert.h>
41

42
#include <vlc_common.h>
43
#include <vlc_plugin.h>
44
#include <vlc_vout_display.h>
45
#include <vlc_charset.h>
gbazin's avatar
   
gbazin committed
46

47
48
#include <windows.h>
#include <winuser.h>
gbazin's avatar
   
gbazin committed
49
#include <ddraw.h>
50
#include <commctrl.h>       /* ListView_(Get|Set)* */
gbazin's avatar
   
gbazin committed
51

52
#include "common.h"
gbazin's avatar
   
gbazin committed
53

54
55
56
57
#ifdef UNICODE
#   error "Unicode mode not supported"
#endif

58
59
60
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Christophe Massiot's avatar
Christophe Massiot committed
61
#define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
62
#define HW_YUV_LONGTEXT N_(\
63
    "Try to use hardware acceleration for YUV->RGB conversions. " \
64
    "This option doesn't have any effect when using overlays.")
zorglub's avatar
zorglub committed
65

Christophe Massiot's avatar
Christophe Massiot committed
66
#define SYSMEM_TEXT N_("Use video buffers in system memory")
67
#define SYSMEM_LONGTEXT N_(\
68
    "Create video buffers in system memory instead of video memory. This " \
69
    "isn't recommended as usually using video memory allows benefiting from " \
70
    "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
71
    "This option doesn't have any effect when using overlays.")
zorglub's avatar
zorglub committed
72

Christophe Massiot's avatar
Christophe Massiot committed
73
#define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
74
#define TRIPLEBUF_LONGTEXT N_(\
75
    "Try to use triple buffering when using YUV overlays. That results in " \
76
    "much better video quality (no flickering).")
zorglub's avatar
zorglub committed
77

gbazin's avatar
   
gbazin committed
78
#define DEVICE_TEXT N_("Name of desired display device")
79
80
81
#define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " \
    "specify the Windows device name of the display that you want the video " \
    "window to open on. For example, \"\\\\.\\DISPLAY1\" or " \
82
    "\"\\\\.\\DISPLAY2\".")
gbazin's avatar
   
gbazin committed
83

84
85
86
#define DX_HELP N_("Recommended video output for Windows XP. " \
    "Incompatible with Vista's Aero interface" )

87
88
89
static int  Open (vlc_object_t *);
static void Close(vlc_object_t *);

90
91
static int FindDevicesCallback(vlc_object_t *, const char *,
                               char ***, char ***);
92
93
94
vlc_module_begin()
    set_shortname("DirectX")
    set_description(N_("DirectX (DirectDraw) video output"))
95
    set_help(DX_HELP)
96
97
    set_category(CAT_VIDEO)
    set_subcategory(SUBCAT_VIDEO_VOUT)
98
    add_bool("directx-hw-yuv", true, HW_YUV_TEXT, HW_YUV_LONGTEXT,
99
              true)
100
    add_bool("directx-use-sysmem", false, SYSMEM_TEXT, SYSMEM_LONGTEXT,
101
              true)
102
    add_bool("directx-3buffering", true, TRIPLEBUF_TEXT,
103
              TRIPLEBUF_LONGTEXT, true)
104
    add_string("directx-device", "", DEVICE_TEXT, DEVICE_LONGTEXT, true)
105
        change_string_cb(FindDevicesCallback)
106

107
    set_capability("vout display", 230)
108
109
110
    add_shortcut("directx")
    set_callbacks(Open, Close)
vlc_module_end()
111

gbazin's avatar
   
gbazin committed
112
/*****************************************************************************
113
 * Local prototypes.
gbazin's avatar
   
gbazin committed
114
115
 *****************************************************************************/

116
117
118
struct picture_sys_t {
    LPDIRECTDRAWSURFACE2 surface;
    LPDIRECTDRAWSURFACE2 front_surface;
119
    picture_t            *fallback;
120
};
121

122
123
124
125
126
127
128
129
130
131
/*****************************************************************************
 * DirectDraw GUIDs.
 * Defining them here allows us to get rid of the dxguid library during
 * the linking stage.
 *****************************************************************************/
#include <initguid.h>
#undef GUID_EXT
#define GUID_EXT
DEFINE_GUID(IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56);
DEFINE_GUID(IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27);
132

133
static picture_pool_t *Pool  (vout_display_t *, unsigned);
134
static void           Display(vout_display_t *, picture_t *, subpicture_t *);
135
136
static int            Control(vout_display_t *, int, va_list);
static void           Manage (vout_display_t *);
gbazin's avatar
   
gbazin committed
137

138
139
140
/* */
static int WallpaperCallback(vlc_object_t *, char const *,
                             vlc_value_t, vlc_value_t, void *);
gbazin's avatar
   
gbazin committed
141

142
143
static int  DirectXOpen(vout_display_t *, video_format_t *fmt);
static void DirectXClose(vout_display_t *);
gbazin's avatar
   
gbazin committed
144

145
146
static int  DirectXLock(picture_t *);
static void DirectXUnlock(picture_t *);
147

148
static int DirectXUpdateOverlay(vout_display_t *, LPDIRECTDRAWSURFACE2 surface);
gbazin's avatar
   
gbazin committed
149

150
static void WallpaperChange(vout_display_t *vd, bool use_wallpaper);
gbazin's avatar
   
gbazin committed
151

152
153
154
/** This function allocates and initialize the DirectX vout display.
 */
static int Open(vlc_object_t *object)
gbazin's avatar
   
gbazin committed
155
{
156
157
    vout_display_t *vd = (vout_display_t *)object;
    vout_display_sys_t *sys;
158

159
160
161
162
163
164
165
166
167
168
    /* Allocate structure */
    vd->sys = sys = calloc(1, sizeof(*sys));
    if (!sys)
        return VLC_ENOMEM;

    /* Load direct draw DLL */
    sys->hddraw_dll = LoadLibrary(_T("DDRAW.DLL"));
    if (!sys->hddraw_dll) {
        msg_Warn(vd, "DirectXInitDDraw failed loading ddraw.dll");
        free(sys);
169
170
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
171

172
173
174
175
    /* */
    sys->use_wallpaper = var_CreateGetBool(vd, "video-wallpaper");
    /* FIXME */
    sys->use_overlay = false;//var_CreateGetBool(vd, "overlay"); /* FIXME */
176
    sys->restore_overlay = false;
177
    var_Create(vd, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
gbazin's avatar
   
gbazin committed
178

179
180
181
    /* Initialisation */
    if (CommonInit(vd))
        goto error;
gbazin's avatar
   
gbazin committed
182

183
184
    /* */
    video_format_t fmt = vd->fmt;
gbazin's avatar
   
gbazin committed
185

186
187
    if (DirectXOpen(vd, &fmt))
        goto error;
188

189
190
191
192
    /* */
    vout_display_info_t info = vd->info;
    info.is_slow = true;
    info.has_double_click = true;
193
    info.has_hide_mouse = false;
194
    info.has_pictures_invalid = true;
195
    info.has_event_thread = true;
196
197
198
199
200
201

    /* Interaction TODO support starting with wallpaper mode */
    vlc_mutex_init(&sys->lock);
    sys->ch_wallpaper = sys->use_wallpaper;
    sys->wallpaper_requested = sys->use_wallpaper;
    sys->use_wallpaper = false;
gbazin's avatar
   
gbazin committed
202

203
204
205
206
207
208
209
210
211
212
213
214
215
216
    vlc_value_t val;
    val.psz_string = _("Wallpaper");
    var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, &val, NULL);
    var_AddCallback(vd, "video-wallpaper", WallpaperCallback, NULL);

    /* Setup vout_display now that everything is fine */
    vd->fmt     = fmt;
    vd->info    = info;

    vd->pool    = Pool;
    vd->prepare = NULL;
    vd->display = Display;
    vd->control = Control;
    vd->manage  = Manage;
217
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
218

219
error:
220
221
222
223
224
    DirectXClose(vd);
    CommonClean(vd);
    if (sys->hddraw_dll)
        FreeLibrary(sys->hddraw_dll);
    free(sys);
225
    return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
226
227
}

228
229
230
/** Terminate a vout display created by Open.
 */
static void Close(vlc_object_t *object)
231
{
232
233
234
235
236
    vout_display_t *vd = (vout_display_t *)object;
    vout_display_sys_t *sys = vd->sys;

    var_DelCallback(vd, "video-wallpaper", WallpaperCallback, NULL);
    vlc_mutex_destroy(&sys->lock);
237

238
    /* Make sure the wallpaper is restored */
239
    WallpaperChange(vd, false);
240

241
    DirectXClose(vd);
242

243
244
245
246
247
    CommonClean(vd);

    if (sys->hddraw_dll)
        FreeLibrary(sys->hddraw_dll);
    free(sys);
gbazin's avatar
   
gbazin committed
248
249
}

250
static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
gbazin's avatar
   
gbazin committed
251
{
252
253
    VLC_UNUSED(count);
    return vd->sys->pool;
gbazin's avatar
   
gbazin committed
254
}
255
static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
gbazin's avatar
   
gbazin committed
256
{
257
    vout_display_sys_t *sys = vd->sys;
gbazin's avatar
   
gbazin committed
258

259
    assert(sys->display);
gbazin's avatar
   
gbazin committed
260

gbazin's avatar
   
gbazin committed
261
262
    /* Our surface can be lost so be sure to check this
     * and restore it if need be */
263
264
265
266
267
    if (IDirectDrawSurface2_IsLost(sys->display) == DDERR_SURFACELOST) {
        if (IDirectDrawSurface2_Restore(sys->display) == DD_OK) {
            if (sys->use_overlay)
                DirectXUpdateOverlay(vd, NULL);
        }
gbazin's avatar
   
gbazin committed
268
    }
269
270
    if (sys->restore_overlay)
        DirectXUpdateOverlay(vd, NULL);
gbazin's avatar
   
gbazin committed
271

272
273
    /* */
    DirectXUnlock(picture);
gbazin's avatar
   
gbazin committed
274

275
276
277
278
279
280
281
282
283
284
285
286
287
    if (sys->use_overlay) {
        /* Flip the overlay buffers if we are using back buffers */
        if (picture->p_sys->surface != picture->p_sys->front_surface) {
            HRESULT hr = IDirectDrawSurface2_Flip(picture->p_sys->front_surface,
                                                  NULL, DDFLIP_WAIT);
            if (hr != DD_OK)
                msg_Warn(vd, "could not flip overlay (error %li)", hr);
        }
    } else {
        /* Blit video surface to display with the NOTEARING option */
        DDBLTFX  ddbltfx;
        ZeroMemory(&ddbltfx, sizeof(ddbltfx));
        ddbltfx.dwSize = sizeof(ddbltfx);
gbazin's avatar
   
gbazin committed
288
289
        ddbltfx.dwDDFX = DDBLTFX_NOTEARING;

290
291
292
293
294
295
296
        HRESULT hr = IDirectDrawSurface2_Blt(sys->display,
                                             &sys->rect_dest_clipped,
                                             picture->p_sys->surface,
                                             &sys->rect_src_clipped,
                                             DDBLT_ASYNC, &ddbltfx);
        if (hr != DD_OK)
            msg_Warn(vd, "could not blit surface (error %li)", hr);
gbazin's avatar
   
gbazin committed
297
    }
298
299
300
301
302
303
304
305
306
    DirectXLock(picture);

    if (sys->is_first_display) {
        IDirectDraw_WaitForVerticalBlank(sys->ddobject,
                                         DDWAITVB_BLOCKBEGIN, NULL);
        if (sys->use_overlay) {
            HBRUSH brush = CreateSolidBrush(sys->i_rgb_colorkey);
            /* set the colorkey as the backgound brush for the video window */
            SetClassLongPtr(sys->hvideownd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
307
        }
308
309
310
311
    }
    CommonDisplay(vd);

    picture_Release(picture);
312
    VLC_UNUSED(subpicture);
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
}
static int Control(vout_display_t *vd, int query, va_list args)
{
    vout_display_sys_t *sys = vd->sys;

    switch (query) {
    case VOUT_DISPLAY_RESET_PICTURES:
        DirectXClose(vd);
        /* Make sure the wallpaper is restored */
        if (sys->use_wallpaper) {
            vlc_mutex_lock(&sys->lock);
            if (!sys->ch_wallpaper) {
                sys->ch_wallpaper = true;
                sys->wallpaper_requested = true;
            }
            vlc_mutex_unlock(&sys->lock);
gbazin's avatar
   
gbazin committed
329

330
            WallpaperChange(vd, false);
331
        }
332
333
334
335
336
337
338
339
340
341
        return DirectXOpen(vd, &vd->fmt);
    default:
        return CommonControl(vd, query, args);
    }
}
static void Manage(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;

    CommonManage(vd);
gbazin's avatar
   
gbazin committed
342

343
344
345
346
    if (sys->changes & DX_POSITION_CHANGE) {
        /* Update overlay */
        if (sys->use_overlay)
            DirectXUpdateOverlay(vd, NULL);
gbazin's avatar
   
gbazin committed
347

348
        /* Check if we are still on the same monitor */
349
350
        HMONITOR hmon = MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST);
        if (sys->hmonitor != hmon) {
351
            vout_display_SendEventPicturesInvalid(vd);
gbazin's avatar
   
gbazin committed
352
        }
353
354
        /* */
        sys->changes &= ~DX_POSITION_CHANGE;
gbazin's avatar
   
gbazin committed
355
    }
356
357
358
359
360
361
362
363
364
365

    /* Wallpaper mode change */
    vlc_mutex_lock(&sys->lock);
    const bool ch_wallpaper = sys->ch_wallpaper;
    const bool wallpaper_requested = sys->wallpaper_requested;
    sys->ch_wallpaper = false;
    vlc_mutex_unlock(&sys->lock);

    if (ch_wallpaper)
        WallpaperChange(vd, wallpaper_requested);
366
367
368
369

    /* */
    if (sys->restore_overlay)
        DirectXUpdateOverlay(vd, NULL);
gbazin's avatar
   
gbazin committed
370
371
}

372
373
374
375
376
377
/* */
static int  DirectXOpenDDraw(vout_display_t *);
static void DirectXCloseDDraw(vout_display_t *);

static int  DirectXOpenDisplay(vout_display_t *vd);
static void DirectXCloseDisplay(vout_display_t *vd);
378

379
380
381
382
static int  DirectXCreatePool(vout_display_t *, bool *, video_format_t *);
static void DirectXDestroyPool(vout_display_t *);

static int DirectXOpen(vout_display_t *vd, video_format_t *fmt)
383
{
384
    vout_display_sys_t *sys = vd->sys;
385

386
387
388
    assert(!sys->ddobject);
    assert(!sys->display);
    assert(!sys->clipper);
389

390
391
392
393
    /* Initialise DirectDraw */
    if (DirectXOpenDDraw(vd)) {
        msg_Err(vd, "cannot initialize DirectX DirectDraw");
        return VLC_EGENERIC;
394
    }
395

396
397
398
399
400
401
    /* Create the directx display */
    if (DirectXOpenDisplay(vd)) {
        msg_Err(vd, "cannot initialize DirectX DirectDraw");
        return VLC_EGENERIC;
    }
    UpdateRects(vd, NULL, NULL, true);
gbazin's avatar
   
gbazin committed
402

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
    /* Create the picture pool */
    if (DirectXCreatePool(vd, &sys->use_overlay, fmt)) {
        msg_Err(vd, "cannot create any DirectX surface");
        return VLC_EGENERIC;
    }

    /* */
    if (sys->use_overlay)
        DirectXUpdateOverlay(vd, NULL);
    EventThreadUseOverlay(sys->event, sys->use_overlay);

    /* Change the window title bar text */
    const char *fallback;
    if (sys->use_overlay)
        fallback = VOUT_TITLE " (hardware YUV overlay DirectX output)";
    else if (vlc_fourcc_IsYUV(fmt->i_chroma))
        fallback = VOUT_TITLE " (hardware YUV DirectX output)";
    else
        fallback = VOUT_TITLE " (software RGB DirectX output)";
    EventThreadUpdateTitle(sys->event, fallback);

    return VLC_SUCCESS;
}
static void DirectXClose(vout_display_t *vd)
427
{
428
429
430
431
    DirectXDestroyPool(vd);
    DirectXCloseDisplay(vd);
    DirectXCloseDDraw(vd);
}
gbazin's avatar
   
gbazin committed
432

433
434
435
436
437
438
439
/* */
static BOOL WINAPI DirectXOpenDDrawCallback(GUID *guid, LPTSTR desc,
                                            LPTSTR drivername, VOID *context,
                                            HMONITOR hmon)
{
    vout_display_t *vd = context;
    vout_display_sys_t *sys = vd->sys;
440

441
442
443
444
445
446
447
    /* This callback function is called by DirectDraw once for each
     * available DirectDraw device.
     *
     * Returning TRUE keeps enumerating.
     */
    if (!hmon)
        return TRUE;
448

449
    msg_Dbg(vd, "DirectXEnumCallback: %s, %s", desc, drivername);
gbazin's avatar
   
gbazin committed
450

451
452
453
454
455
456
457
    char *device = var_GetString(vd, "directx-device");

    /* Check for forced device */
    if (device && *device && !strcmp(drivername, device)) {
        MONITORINFO monitor_info;
        monitor_info.cbSize = sizeof(MONITORINFO);

458
        if (GetMonitorInfoA(hmon, &monitor_info)) {
459
460
461
462
463
464
465
466
467
468
469
470
471
            RECT rect;

            /* Move window to the right screen */
            GetWindowRect(sys->hwnd, &rect);
            if (!IntersectRect(&rect, &rect, &monitor_info.rcWork)) {
                rect.left = monitor_info.rcWork.left;
                rect.top = monitor_info.rcWork.top;
                msg_Dbg(vd, "DirectXEnumCallback: setting window "
                            "position to %ld,%ld", rect.left, rect.top);
                SetWindowPos(sys->hwnd, NULL,
                             rect.left, rect.top, 0, 0,
                             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
            }
gbazin's avatar
   
gbazin committed
472
        }
473
474
475
        sys->hmonitor = hmon;
    }
    free(device);
gbazin's avatar
   
gbazin committed
476

477
478
479
480
481
482
483
    if (hmon == sys->hmonitor) {
        msg_Dbg(vd, "selecting %s, %s", desc, drivername);

        free(sys->display_driver);
        sys->display_driver = malloc(sizeof(*guid));
        if (sys->display_driver)
            *sys->display_driver = *guid;
484
485
    }

486
    return TRUE;
487
}
488
489
490
491
492
493
494
/**
 * Probe the capabilities of the hardware
 *
 * It is nice to know which features are supported by the hardware so we can
 * find ways to optimize our rendering.
 */
static void DirectXGetDDrawCaps(vout_display_t *vd)
gbazin's avatar
   
gbazin committed
495
{
496
    vout_display_sys_t *sys = vd->sys;
gbazin's avatar
   
gbazin committed
497

498
499
500
501
502
503
504
505
506
507
    /* This is just an indication of whether or not we'll support overlay,
     * but with this test we don't know if we support YUV overlay */
    DDCAPS ddcaps;
    ZeroMemory(&ddcaps, sizeof(ddcaps));
    ddcaps.dwSize = sizeof(ddcaps);
    HRESULT hr = IDirectDraw2_GetCaps(sys->ddobject, &ddcaps, NULL);
    if (hr != DD_OK) {
        msg_Warn(vd, "cannot get caps");
        return;
    }
gbazin's avatar
   
gbazin committed
508

509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
    /* Determine if the hardware supports overlay surfaces */
    const bool has_overlay = ddcaps.dwCaps & DDCAPS_OVERLAY;
    /* Determine if the hardware supports overlay surfaces */
    const bool has_overlay_fourcc = ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC;
    /* Determine if the hardware supports overlay deinterlacing */
    const bool can_deinterlace = ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN;
    /* Determine if the hardware supports colorkeying */
    const bool has_color_key = ddcaps.dwCaps & DDCAPS_COLORKEY;
    /* Determine if the hardware supports scaling of the overlay surface */
    const bool can_stretch = ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH;
    /* Determine if the hardware supports color conversion during a blit */
    sys->can_blit_fourcc = ddcaps.dwCaps & DDCAPS_BLTFOURCC;
    /* Determine overlay source boundary alignment */
    const bool align_boundary_src  = ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC;
    /* Determine overlay destination boundary alignment */
    const bool align_boundary_dest = ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST;
    /* Determine overlay destination size alignment */
    const bool align_size_src  = ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC;
    /* Determine overlay destination size alignment */
    const bool align_size_dest = ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST;

    msg_Dbg(vd, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
                "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
                "bltfourcc=%i",
                has_overlay, has_overlay_fourcc, can_deinterlace,
                has_color_key, can_stretch, sys->can_blit_fourcc);

    if (align_boundary_src || align_boundary_dest || align_size_src || align_size_dest) {
        if (align_boundary_src)
            vd->sys->i_align_src_boundary = ddcaps.dwAlignBoundarySrc;
        if (align_boundary_dest)
            vd->sys->i_align_dest_boundary = ddcaps.dwAlignBoundaryDest;
        if (align_size_src)
            vd->sys->i_align_src_size = ddcaps.dwAlignSizeSrc;
        if (align_size_dest)
            vd->sys->i_align_dest_size = ddcaps.dwAlignSizeDest;

        msg_Dbg(vd,
                "align_boundary_src=%i,%i align_boundary_dest=%i,%i "
                "align_size_src=%i,%i align_size_dest=%i,%i",
                align_boundary_src,  vd->sys->i_align_src_boundary,
                align_boundary_dest, vd->sys->i_align_dest_boundary,
                align_size_src,  vd->sys->i_align_src_size,
                align_size_dest, vd->sys->i_align_dest_size);
gbazin's avatar
   
gbazin committed
553
    }
554
555
556
557
558
559
560
561
562
}



/* */
static int DirectXOpenDDraw(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;
563

564
565
    /* */
    HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
566
    OurDirectDrawCreate =
567
568
569
570
        (void *)GetProcAddress(sys->hddraw_dll, _T("DirectDrawCreate"));
    if (!OurDirectDrawCreate) {
        msg_Err(vd, "DirectXInitDDraw failed GetProcAddress");
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
571
572
    }

573
    /* */
574
575
576
577
578
579
580
581
582
583
    HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA, LPVOID, DWORD);
    OurDirectDrawEnumerateEx =
      (void *)GetProcAddress(sys->hddraw_dll, _T("DirectDrawEnumerateExA"));

    if (OurDirectDrawEnumerateEx) {
        char *device = var_GetString(vd, "directx-device");
        if (device) {
            msg_Dbg(vd, "directx-device: %s", device);
            free(device);
        }
584

585
        sys->hmonitor = MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST);
gbazin's avatar
   
gbazin committed
586

587
588
589
        /* Enumerate displays */
        OurDirectDrawEnumerateEx(DirectXOpenDDrawCallback,
                                 vd, DDENUM_ATTACHEDSECONDARYDEVICES);
590
591
    }

gbazin's avatar
   
gbazin committed
592
    /* Initialize DirectDraw now */
593
594
595
596
597
    LPDIRECTDRAW ddobject;
    hr = OurDirectDrawCreate(sys->display_driver, &ddobject, NULL);
    if (hr != DD_OK) {
        msg_Err(vd, "DirectXInitDDraw cannot initialize DDraw");
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
598
599
600
    }

    /* Get the IDirectDraw2 interface */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
601
    void *ptr;
602
    hr = IDirectDraw_QueryInterface(ddobject, &IID_IDirectDraw2,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
603
                                    &ptr);
gbazin's avatar
   
gbazin committed
604
    /* Release the unused interface */
605
606
607
608
609
610
    IDirectDraw_Release(ddobject);

    if (hr != DD_OK) {
        msg_Err(vd, "cannot get IDirectDraw2 interface");
        sys->ddobject = NULL;
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
611
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
612
    sys->ddobject = ptr;
gbazin's avatar
   
gbazin committed
613
614
615

    /* Set DirectDraw Cooperative level, ie what control we want over Windows
     * display */
616
617
618
619
    hr = IDirectDraw2_SetCooperativeLevel(sys->ddobject, NULL, DDSCL_NORMAL);
    if (hr != DD_OK) {
        msg_Err(vd, "cannot set direct draw cooperative level");
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
620
621
    }

622
    /* Get the size of the current display device */
623
    if (sys->hmonitor) {
624
        MONITORINFO monitor_info;
625
        monitor_info.cbSize = sizeof(MONITORINFO);
626
        GetMonitorInfoA(vd->sys->hmonitor, &monitor_info);
627
628
629
630
631
632
        sys->rect_display = monitor_info.rcMonitor;
    } else {
        sys->rect_display.left   = 0;
        sys->rect_display.top    = 0;
        sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
        sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
633
634
    }

635
636
637
638
639
    msg_Dbg(vd, "screen dimensions (%lix%li,%lix%li)",
            sys->rect_display.left,
            sys->rect_display.top,
            sys->rect_display.right,
            sys->rect_display.bottom);
640

gbazin's avatar
   
gbazin committed
641
    /* Probe the capabilities of the hardware */
642
    DirectXGetDDrawCaps(vd);
gbazin's avatar
   
gbazin committed
643

644
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
645
646
}

647
static void DirectXCloseDDraw(vout_display_t *vd)
gbazin's avatar
   
gbazin committed
648
{
649
650
651
    vout_display_sys_t *sys = vd->sys;
    if (sys->ddobject)
        IDirectDraw2_Release(sys->ddobject);
gbazin's avatar
   
gbazin committed
652

653
    sys->ddobject = NULL;
gbazin's avatar
   
gbazin committed
654

655
656
    free(sys->display_driver);
    sys->display_driver = NULL;
gbazin's avatar
   
gbazin committed
657

658
659
    sys->hmonitor = NULL;
}
gbazin's avatar
   
gbazin committed
660

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
/**
 * Create a clipper that will be used when blitting the RGB surface to the main display.
 *
 * This clipper prevents us to modify by mistake anything on the screen
 * which doesn't belong to our window. For example when a part of our video
 * window is hidden by another window.
 */
static void DirectXCreateClipper(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;

    /* Create the clipper */
    hr = IDirectDraw2_CreateClipper(sys->ddobject, 0, &sys->clipper, NULL);
    if (hr != DD_OK) {
        msg_Warn(vd, "cannot create clipper (error %li)", hr);
        goto error;
gbazin's avatar
   
gbazin committed
678
679
    }

680
681
682
683
684
685
    /* Associate the clipper to the window */
    hr = IDirectDrawClipper_SetHWnd(sys->clipper, 0, sys->hvideownd);
    if (hr != DD_OK) {
        msg_Warn(vd, "cannot attach clipper to window (error %li)", hr);
        goto error;
    }
gbazin's avatar
   
gbazin committed
686

687
688
689
690
691
692
693
    /* associate the clipper with the surface */
    hr = IDirectDrawSurface_SetClipper(sys->display, sys->clipper);
    if (hr != DD_OK)
    {
        msg_Warn(vd, "cannot attach clipper to surface (error %li)", hr);
        goto error;
    }
gbazin's avatar
   
gbazin committed
694

695
    return;
gbazin's avatar
   
gbazin committed
696

697
698
699
700
error:
    if (sys->clipper)
        IDirectDrawClipper_Release(sys->clipper);
    sys->clipper = NULL;
gbazin's avatar
   
gbazin committed
701
702
}

703
704
705
706
/**
 * It finds out the 32bits RGB pixel value of the colorkey.
 */
static uint32_t DirectXFindColorkey(vout_display_t *vd, uint32_t *color)
gbazin's avatar
   
gbazin committed
707
{
708
709
710
711
712
713
714
715
716
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;

    /* */
    DDSURFACEDESC ddsd;
    ddsd.dwSize = sizeof(ddsd);
    hr = IDirectDrawSurface2_Lock(sys->display, NULL, &ddsd, DDLOCK_WAIT, NULL);
    if (hr != DD_OK)
        return 0;
gbazin's avatar
   
gbazin committed
717

718
    uint32_t backup = *(uint32_t *)ddsd.lpSurface;
gbazin's avatar
   
gbazin committed
719

720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
    switch (ddsd.ddpfPixelFormat.dwRGBBitCount) {
    case 4:
        *(uint8_t *)ddsd.lpSurface = *color | (*color << 4);
        break;
    case 8:
        *(uint8_t *)ddsd.lpSurface = *color;
        break;
    case 15:
    case 16:
        *(uint16_t *)ddsd.lpSurface = *color;
        break;
    case 24:
        /* Seems to be problematic so we'll just put black as the colorkey */
        *color = 0;
    default:
        *(uint32_t *)ddsd.lpSurface = *color;
        break;
gbazin's avatar
   
gbazin committed
737
    }
738
    IDirectDrawSurface2_Unlock(sys->display, NULL);
gbazin's avatar
   
gbazin committed
739

740
741
742
743
744
745
746
747
    /* */
    HDC hdc;
    COLORREF rgb;
    if (IDirectDrawSurface2_GetDC(sys->display, &hdc) == DD_OK) {
        rgb = GetPixel(hdc, 0, 0);
        IDirectDrawSurface2_ReleaseDC(sys->display, hdc);
    } else {
        rgb = 0;
gbazin's avatar
   
gbazin committed
748
749
    }

750
751
752
753
754
    /* Restore the pixel value */
    ddsd.dwSize = sizeof(ddsd);
    if (IDirectDrawSurface2_Lock(sys->display, NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) {
        *(uint32_t *)ddsd.lpSurface = backup;
        IDirectDrawSurface2_Unlock(sys->display, NULL);
755
    }
gbazin's avatar
   
gbazin committed
756

757
758
    return rgb;
}
gbazin's avatar
   
gbazin committed
759

760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
/**
 * Create and initialize display according to preferences specified in the vout
 * thread fields.
 */
static int DirectXOpenDisplay(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
    HRESULT hr;

    /* Now get the primary surface. This surface is what you actually see
     * on your screen */
    DDSURFACEDESC ddsd;
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    LPDIRECTDRAWSURFACE display;
    hr = IDirectDraw2_CreateSurface(sys->ddobject, &ddsd, &display, NULL);
    if (hr != DD_OK) {
        msg_Err(vd, "cannot get primary surface (error %li)", hr);
        return VLC_EGENERIC;
782
    }
783

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
784
    void *ptr;
785
    hr = IDirectDrawSurface_QueryInterface(display, &IID_IDirectDrawSurface2,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
786
                                           &ptr);
787
788
789
790
791
792
793
794
    /* Release the old interface */
    IDirectDrawSurface_Release(display);

    if (hr != DD_OK) {
        msg_Err(vd, "cannot query IDirectDrawSurface2 interface (error %li)", hr);
        sys->display = NULL;
        return VLC_EGENERIC;
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
795
    sys->display = ptr;
796
797
798
799
800
801
802
803
804

    /* The clipper will be used only in non-overlay mode */
    DirectXCreateClipper(vd);

    /* Make sure the colorkey will be painted */
    sys->i_colorkey = 1;
    sys->i_rgb_colorkey = DirectXFindColorkey(vd, &sys->i_colorkey);

    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
805
}
806
807
808
static void DirectXCloseDisplay(vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;
gbazin's avatar
   
gbazin committed
809

810
811
812
813
814
815
816
817
818
819
820
821
822
    if (sys->clipper != NULL)
        IDirectDrawClipper_Release(sys->clipper);

    if (sys->display != NULL)
        IDirectDrawSurface2_Release(sys->display);

    sys->clipper = NULL;
    sys->display = NULL;
}

/**
 * Create an YUV overlay or RGB surface for the video.
 *
gbazin's avatar
   
gbazin committed
823
824
825
 * The best method of display is with an YUV overlay because the YUV->RGB
 * conversion is done in hardware.
 * You can also create a plain RGB surface.
826
 * (Maybe we could also try an RGB overlay surface, which could have hardware
gbazin's avatar
   
gbazin committed
827
828
 * scaling and which would also be faster in window mode because you don't
 * need to do any blitting to the main display...)
829
830
831
832
833
834
835
836
 */
static int DirectXCreateSurface(vout_display_t *vd,
                                LPDIRECTDRAWSURFACE2 *surface,
                                const video_format_t *fmt,
                                DWORD fourcc,
                                bool use_overlay,
                                bool use_sysmem,
                                int backbuffer_count)
gbazin's avatar
   
gbazin committed
837
{
838
839
    vout_display_sys_t *sys = vd->sys;

gbazin's avatar
   
gbazin committed
840
841
    DDSURFACEDESC ddsd;

842
843
844
845
846
847
848
849
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize   = sizeof(ddsd);
    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
    ddsd.dwFlags  = DDSD_HEIGHT | DDSD_WIDTH;
    ddsd.dwWidth  = fmt->i_width;
    ddsd.dwHeight = fmt->i_height;
    if (fourcc) {
        ddsd.dwFlags |= DDSD_PIXELFORMAT;
gbazin's avatar
   
gbazin committed
850
        ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
851
        ddsd.ddpfPixelFormat.dwFourCC = fourcc;
gbazin's avatar
   
gbazin committed
852
    }
853
854
855
856
857
    if (use_overlay) {
        ddsd.dwFlags |= DDSD_CAPS;
        ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
        if (backbuffer_count > 0)
            ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
gbazin's avatar
   
gbazin committed
858

859
860
861
862
863
864
        if (backbuffer_count > 0) {
            ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
            ddsd.dwBackBufferCount = backbuffer_count;
        }
    } else {
        ddsd.dwFlags |= DDSD_CAPS;
gbazin's avatar
   
gbazin committed
865
        ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
866
        if (use_sysmem)
gbazin's avatar
   
gbazin committed
867
868
869
870
871
            ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
        else
            ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
    }

872
873
874
875
876
    /* Create the video surface */
    LPDIRECTDRAWSURFACE surface_v1;
    if (IDirectDraw2_CreateSurface(sys->ddobject, &ddsd, &surface_v1, NULL) != DD_OK)
        return VLC_EGENERIC;

gbazin's avatar
   
gbazin committed
877
    /* Now that the surface is created, try to get a newer DirectX interface */
878
879
880
881
882
883
    HRESULT hr = IDirectDrawSurface_QueryInterface(surface_v1,
                                                   &IID_IDirectDrawSurface2,
                                                   (LPVOID *)surface);
    IDirectDrawSurface_Release(surface_v1);
    if (hr != DD_OK) {
        msg_Err(vd, "cannot query IDirectDrawSurface2 interface (error %li)", hr);
884
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
885
886
    }

887
    if (use_overlay) {
888
889
        /* Check the overlay is useable as some graphics cards allow creating
         * several overlays but only one can be used at one time. */
890
891
892
        if (DirectXUpdateOverlay(vd, *surface)) {
            IDirectDrawSurface2_Release(*surface);
            msg_Err(vd, "overlay unuseable (might already be in use)");
893
894
895
896
            return VLC_EGENERIC;
        }
    }

897
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
898
899
}

900
static void DirectXDestroySurface(LPDIRECTDRAWSURFACE2 surface)
gbazin's avatar
   
gbazin committed
901
{
902
903
904
905
906
907
908
909
910
911
    IDirectDrawSurface2_Release(surface);
}
/**
 * This function locks a surface and get the surface descriptor.
 */
static int DirectXLockSurface(LPDIRECTDRAWSURFACE2 front_surface,
                              LPDIRECTDRAWSURFACE2 surface,
                              DDSURFACEDESC *ddsd)
{
    HRESULT hr;
gbazin's avatar
   
gbazin committed
912

913
914
915
    DDSURFACEDESC ddsd_dummy;
    if (!ddsd)
        ddsd = &ddsd_dummy;
gbazin's avatar
   
gbazin committed
916

917
918
919
920
921
922
923
924
925
926
927
928
    ZeroMemory(ddsd, sizeof(*ddsd));
    ddsd->dwSize = sizeof(*ddsd);
    hr = IDirectDrawSurface2_Lock(surface, NULL, ddsd, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
    if (hr != DD_OK) {
        if (hr == DDERR_INVALIDPARAMS) {
            /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
             * in an invalid params error */
            hr = IDirectDrawSurface2_Lock(surface, NULL, ddsd, DDLOCK_WAIT, NULL);
        }
        if (hr == DDERR_SURFACELOST) {
            /* Your surface can be lost so be sure
             * to check this and restore it if needed */
gbazin's avatar
gbazin committed
929

930
931
932
933
934
935
            /* When using overlays with back-buffers, we need to restore
             * the front buffer so the back-buffers get restored as well. */
            if (front_surface != surface)
                IDirectDrawSurface2_Restore(front_surface);
            else
                IDirectDrawSurface2_Restore(surface);
gbazin's avatar
gbazin committed
936

937
938
939
940
            hr = IDirectDrawSurface2_Lock(surface, NULL, ddsd, DDLOCK_WAIT, NULL);
        }
        if (hr != DD_OK)
            return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
941
    }
942
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
943
}
944
945
static void DirectXUnlockSurface(LPDIRECTDRAWSURFACE2 front_surface,
                                 LPDIRECTDRAWSURFACE2 surface)
gbazin's avatar
   
gbazin committed
946
{
947
    VLC_UNUSED(front_surface);
948
949
950
951
952
953
954
    IDirectDrawSurface2_Unlock(surface, NULL);
}
static int DirectXCheckLockingSurface(LPDIRECTDRAWSURFACE2 front_surface,
                                      LPDIRECTDRAWSURFACE2 surface)
{
    if (DirectXLockSurface(front_surface, surface, NULL))
        return VLC_EGENERIC;
955

956
957
    DirectXUnlockSurface(front_surface, surface);
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
958
959
960
961
}



962
963
964
965
typedef struct {
    vlc_fourcc_t codec;
    DWORD        fourcc;
} dx_format_t;
gbazin's avatar
   
gbazin committed
966

967
static DWORD DirectXGetFourcc(vlc_fourcc_t codec)
gbazin's avatar
   
gbazin committed
968
{
969
970
971
972
973
974
975
976
977
978
979
980
981
    static const dx_format_t dx_formats[] = {
        { VLC_CODEC_YUYV, MAKEFOURCC('Y','U','Y','2') },
        { VLC_CODEC_UYVY, MAKEFOURCC('U','Y','V','Y') },
        { VLC_CODEC_YVYU, MAKEFOURCC('Y','V','Y','U') },
        { VLC_CODEC_YV12, MAKEFOURCC('Y','V','1','2') },
        { VLC_CODEC_I420, MAKEFOURCC('Y','V','1','2') },
        { VLC_CODEC_J420, MAKEFOURCC('Y','V','1','2') },
        { 0, 0 }
    };

    for (unsigned i = 0; dx_formats[i].codec != 0; i++) {
        if (dx_formats[i].codec == codec)
            return dx_formats[i].fourcc;
gbazin's avatar
   
gbazin committed
982
    }
983
    return 0;
gbazin's avatar
   
gbazin committed
984
985
}

986
987
988
static int DirectXCreatePictureResourceYuvOverlay(vout_display_t *vd,
                                                  const video_format_t *fmt,
                                                  DWORD fourcc)
gbazin's avatar
   
gbazin committed
989
{
990
    vout_display_sys_t *sys = vd->sys;
gbazin's avatar
   
gbazin committed
991

992
    bool allow_3buf    = var_InheritBool(vd, "directx-3buffering");
gbazin's avatar
   
gbazin committed
993

994
    /* The overlay surface that we create won't be used to decode directly
gbazin's avatar
   
gbazin committed
995
996
997
998
     * into it because accessing video memory directly is way to slow (remember
     * that pictures are decoded macroblock per macroblock). Instead the video
     * will be decoded in picture buffers in system memory which will then be
     * memcpy() to the overlay surface. */
999
1000
1001
    LPDIRECTDRAWSURFACE2 front_surface;
    int ret = VLC_EGENERIC;
    if (allow_3buf) {
gbazin's avatar
   
gbazin committed
1002
1003
1004
        /* Triple buffering rocks! it doesn't have any processing overhead
         * (you don't have to wait for the vsync) and provides for a very nice
         * video quality (no tearing). */
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
        ret = DirectXCreateSurface(vd, &front_surface, fmt, fourcc, true, false, 2);
    }
    if (ret)
        ret = DirectXCreateSurface(vd, &front_surface, fmt, fourcc, true, false, 0);
    if (ret)
        return VLC_EGENERIC;
    msg_Dbg(vd, "YUV overlay surface created successfully");

    /* Get the back buffer */
    LPDIRECTDRAWSURFACE2 surface;
    DDSCAPS dds_caps;
    ZeroMemory(&dds_caps, sizeof(dds_caps));
    dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
    if (IDirectDrawSurface2_GetAttachedSurface(front_surface, &dds_caps, &surface) != DD_OK) {
        msg_Warn(vd, "Failed to get surface back buffer");
        /* front buffer is the same as back buffer */
        surface = front_surface;
    }
gbazin's avatar
   
gbazin committed
1023

1024
1025
1026
1027
    if (DirectXCheckLockingSurface(front_surface, surface)) {
        DirectXDestroySurface(front_surface);
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
1028

1029
1030
1031
1032
    /* */
    picture_resource_t *rsc = &sys->resource;
    rsc->p_sys->front_surface = front_surface;
    rsc->p_sys->surface       = surface;
1033
    rsc->p_sys->fallback      = NULL;
1034
1035
1036
1037
1038
1039
1040
    return VLC_SUCCESS;
}
static int DirectXCreatePictureResourceYuv(vout_display_t *vd,
                                           const video_format_t *fmt,
                                           DWORD fourcc)
{
    vout_display_sys_t *sys = vd->sys;
gbazin's avatar
   
gbazin committed
1041

1042
    bool allow_sysmem  = var_InheritBool(vd, "directx-use-sysmem");
gbazin's avatar
   
gbazin committed
1043
1044
1045
1046
1047
1048
1049
1050

    /* As we can't have an overlay, we'll try to create a plain offscreen
     * surface. This surface will reside in video memory because there's a
     * better chance then that we'll be able to use some kind of hardware
     * acceleration like rescaling, blitting or YUV->RGB conversions.
     * We then only need to blit this surface onto the main display when we
     * want to display it */

1051
1052
1053
1054
1055
1056
    /* Check if the chroma is supported first. This is required
     * because a few buggy drivers don't mind creating the surface
     * even if they don't know about the chroma. */
    DWORD count;
    if (IDirectDraw2_GetFourCCCodes(sys->ddobject, &count, NULL) != DD_OK)
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
1057

1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
    DWORD *list = calloc(count, sizeof(*list));
    if (!list)
        return VLC_ENOMEM;
    if (IDirectDraw2_GetFourCCCodes(sys->ddobject, &count, list) != DD_OK) {
        free(list);
        return VLC_EGENERIC;
    }
    unsigned index;
    for (index = 0; index < count; index++) {
        if (list[index] == fourcc)
            break;
    }
    free(list);
    if (index >= count)
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
1073

1074
1075
1076
1077
1078
    /* */
    LPDIRECTDRAWSURFACE2 surface;
    if (DirectXCreateSurface(vd, &surface, fmt, fourcc, false, allow_sysmem, 0))
        return VLC_EGENERIC;
    msg_Dbg(vd, "YUV plain surface created successfully");
gbazin's avatar
   
gbazin committed
1079

1080
1081
1082
1083
    if (DirectXCheckLockingSurface(surface, surface)) {
        DirectXDestroySurface(surface);
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
1084

1085
1086
1087
1088
    /* */
    picture_resource_t *rsc = &sys->resource;
    rsc->p_sys->front_surface = surface;
    rsc->p_sys->surface       = surface;
1089
    rsc->p_sys->fallback      = NULL;
1090
1091
1092
1093
1094
1095
1096
    return VLC_SUCCESS;
}
static int DirectXCreatePictureResourceRgb(vout_display_t *vd,
                                           video_format_t *fmt)
{
    vout_display_sys_t *sys = vd->sys;
    bool allow_sysmem  = var_InheritBool(vd, "directx-use-sysmem");
gbazin's avatar
   
gbazin committed
1097

1098
1099
1100
1101
    /* Our last choice is to use a plain RGB surface */
    DDPIXELFORMAT ddpfPixelFormat;
    ZeroMemory(&ddpfPixelFormat, sizeof(ddpfPixelFormat));
    ddpfPixelFormat.dwSize = sizeof(ddpfPixelFormat);
gbazin's avatar
   
gbazin committed
1102

1103
1104
1105
    IDirectDrawSurface2_GetPixelFormat(sys->display, &ddpfPixelFormat);
    if ((ddpfPixelFormat.dwFlags & DDPF_RGB) == 0)
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
1106

1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
    switch (ddpfPixelFormat.dwRGBBitCount) {
    case 8:
        fmt->i_chroma = VLC_CODEC_RGB8;
        break;
    case 15:
        fmt->i_chroma = VLC_CODEC_RGB15;
        break;
    case 16:
        fmt->i_chroma = VLC_CODEC_RGB16;
        break;
    case 24:
        fmt->i_chroma = VLC_CODEC_RGB24;
        break;
    case 32:
        fmt->i_chroma = VLC_CODEC_RGB32;
        break;
    default:
        msg_Err(vd, "unknown screen depth");
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
1126
    }
1127
1128
1129
    fmt->i_rmask = ddpfPixelFormat.dwRBitMask;
    fmt->i_gmask = ddpfPixelFormat.dwGBitMask;
    fmt->i_bmask = ddpfPixelFormat.dwBBitMask;
gbazin's avatar
   
gbazin committed
1130

1131
1132
1133
1134
1135
1136
1137
1138
    /* */
    LPDIRECTDRAWSURFACE2 surface;
    int ret = DirectXCreateSurface(vd, &surface, fmt, 0, false, allow_sysmem, 0);
    if (ret && !allow_sysmem)
        ret = DirectXCreateSurface(vd, &surface, fmt, 0, false, true, 0);
    if (ret)
        return VLC_EGENERIC;
    msg_Dbg(vd, "RGB plain surface created successfully");
gbazin's avatar
   
gbazin committed
1139

1140
1141
1142
    if (DirectXCheckLockingSurface(surface, surface)) {
        DirectXDestroySurface(surface);
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
1143
1144
    }

1145
1146
1147
1148
    /* */
    picture_resource_t *rsc = &sys->resource;
    rsc->p_sys->front_surface = surface;
    rsc->p_sys->surface       = surface;
1149
    rsc->p_sys->fallback      = NULL;
1150
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
1151
1152
}

1153
1154
1155
static int DirectXCreatePictureResource(vout_display_t *vd,
                                        bool *use_overlay,
                                        video_format_t *fmt)
gbazin's avatar
   
gbazin committed
1156
{
1157
    vout_display_sys_t *sys = vd->sys;
gbazin's avatar
gbazin committed
1158

1159
1160
1161
1162
1163
    /* */
    picture_resource_t *rsc = &sys->resource;
    rsc->p_sys = calloc(1, sizeof(*rsc->p_sys));
    if (!rsc->p_sys)
        return VLC_ENOMEM;
gbazin's avatar
   
gbazin committed
1164

Laurent Aimar's avatar