1 /*****************************************************************************
2 * direct2d.c : Direct2D video output plugin for vlc (Win7/Vista SP2 PF Update)
3 *****************************************************************************
4 * Copyright (C) 2010 VideoLAN and AUTHORS
7 * Author: David Kaplan <david@2of1.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_vout_display.h>
45 /*****************************************************************************
47 *****************************************************************************/
48 static int Open (vlc_object_t *);
49 static void Close(vlc_object_t *);
51 #define D2D_HELP N_("Video output for Windows 7/Windows Vista with Platform update")
54 set_category(CAT_VIDEO)
55 set_subcategory(SUBCAT_VIDEO_VOUT)
57 set_shortname("Direct2D")
58 set_description(N_("Direct2D video output"))
59 set_capability("vout display", 180)
60 add_shortcut("direct2d")
61 set_callbacks(Open, Close)
65 /*****************************************************************************
67 *****************************************************************************/
68 static picture_pool_t *Pool (vout_display_t *, unsigned);
69 static void Prepare(vout_display_t *, picture_t *, subpicture_t *);
70 static void Display(vout_display_t *, picture_t *, subpicture_t *);
71 static int Control(vout_display_t *, int, va_list);
72 static void Manage (vout_display_t *);
74 static int D2D_CreateRenderTarget(vout_display_t *vd);
75 static void D2D_ResizeRenderTarget(vout_display_t *vd);
76 static void D2D_DestroyRenderTarget(vout_display_t *vd);
79 * Initialises Direct2D vout module
81 static int Open(vlc_object_t *object)
83 vout_display_t *vd = (vout_display_t *)object;
84 vout_display_sys_t *sys;
86 vd->sys = sys = calloc(1, sizeof(*sys));
90 sys->d2_render_target = NULL;
92 sys->d2_dll = LoadLibrary(TEXT("D2D1.DLL"));
95 msg_Err(vd, "Cannot load D2D1.DLL, aborting");
99 D2D1_FACTORY_OPTIONS fo = {
100 D2D1_DEBUG_LEVEL_NONE
103 HRESULT (WINAPI *D2D1CreateFactory)(D2D1_FACTORY_TYPE, REFIID,
104 const D2D1_FACTORY_OPTIONS *,
107 D2D1CreateFactory = (void *)GetProcAddress(sys->d2_dll,
108 "D2D1CreateFactory");
109 if (!D2D1CreateFactory) {
111 "Cannot locate reference to a D2D1CreateFactory ABI in D2D1.DLL");
116 msg_Dbg(vd, "D2D1.DLL loaded");
119 HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
120 (REFIID)&IID_ID2D1Factory,
122 (void **)&sys->d2_factory);
124 msg_Err(vd, "Cannot create Direct2D factory (hr = 0x%x)!",
132 if (D2D_CreateRenderTarget(vd) != VLC_SUCCESS)
135 vout_display_info_t info = vd->info;
136 info.is_slow = false;
137 info.has_double_click = true;
138 info.has_hide_mouse = false;
139 info.has_pictures_invalid = false;
142 vd->fmt.i_chroma = VLC_CODEC_RGB32; /* masks change this to BGR32 for ID2D1Bitmap */
143 vd->fmt.i_rmask = 0x0000ff00;
144 vd->fmt.i_gmask = 0x00ff0000;
145 vd->fmt.i_bmask = 0xff000000;
148 vd->prepare = Prepare;
149 vd->display = Display;
151 vd->control = Control;
153 EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct2D output)");
156 msg_Dbg(vd, "Ready");
162 Close(VLC_OBJECT(vd));
167 * Close Direct2D vout
169 static void Close(vlc_object_t *object)
171 vout_display_t *vd = (vout_display_t *)object;
173 D2D_DestroyRenderTarget(vd);
176 picture_pool_Delete(vd->sys->pool);
184 * Handles pool allocations for bitmaps
186 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
188 vout_display_sys_t *sys = vd->sys;
191 sys->pool = picture_pool_NewFromFormat(&vd->fmt, count);
193 msg_Dbg(vd, "New picture pool created");
201 * Performs set up of ID2D1Bitmap memory ready for blitting
203 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
205 vout_display_sys_t *sys = vd->sys;
207 if (sys->d2_render_target && sys->d2_bitmap) {
209 HRESULT hr = ID2D1Bitmap_CopyFromMemory(sys->d2_bitmap,
211 picture->p[0].p_pixels,
212 picture->p[0].i_pitch);
214 msg_Err(vd, "Failed to copy bitmap memory (hr = 0x%x)!",
218 /*msg_Dbg(vd, "Bitmap dbg: target = %p, pitch = %d, bitmap = %p",
219 sys->d2_render_target, pitch, sys->d2_bitmap);*/
222 VLC_UNUSED(subpicture);
226 * Blits a scaled picture_t to the render target
228 static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
230 vout_display_sys_t *sys = vd->sys;
232 D2D1_RECT_F r_dest = {
235 sys->rect_dest.right,
236 sys->rect_dest.bottom
239 if (sys->d2_render_target && sys->d2_bitmap) {
240 ID2D1HwndRenderTarget_BeginDraw(sys->d2_render_target);
242 ID2D1HwndRenderTarget_DrawBitmap(sys->d2_render_target,
246 D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
249 HRESULT hr = ID2D1HwndRenderTarget_EndDraw(sys->d2_render_target,
252 if (hr == D2DERR_RECREATE_TARGET) {
253 D2D_DestroyRenderTarget(vd);
254 D2D_CreateRenderTarget(vd);
258 picture_Release(picture);
259 VLC_UNUSED(subpicture);
265 * Control event handler
267 static int Control(vout_display_t *vd, int query, va_list args)
269 return CommonControl(vd, query, args);
273 * Handles surface management
274 * ID2D1RenderTargets cannot be resized and must be recreated
276 static void Manage(vout_display_t *vd)
278 vout_display_sys_t *sys = vd->sys;
282 if (sys->changes & DX_POSITION_CHANGE) {
283 D2D_ResizeRenderTarget(vd);
284 sys->changes &= ~DX_POSITION_CHANGE;
289 * Creates a ID2D1HwndRenderTarget and associated ID2D1Bitmap
291 static int D2D_CreateRenderTarget(vout_display_t *vd)
293 vout_display_sys_t *sys = vd->sys;
295 sys->d2_render_target = NULL;
297 D2D1_PIXEL_FORMAT pf = {
298 DXGI_FORMAT_B8G8R8A8_UNORM,
299 D2D1_ALPHA_MODE_IGNORE
302 D2D1_RENDER_TARGET_PROPERTIES rtp = {
303 D2D1_RENDER_TARGET_TYPE_DEFAULT,
307 D2D1_RENDER_TARGET_USAGE_NONE,
308 D2D1_FEATURE_LEVEL_DEFAULT
312 sys->rect_dest.right - sys->rect_dest.left,
313 sys->rect_dest.bottom - sys->rect_dest.top
316 D2D1_HWND_RENDER_TARGET_PROPERTIES hrtp = {
319 D2D1_PRESENT_OPTIONS_IMMEDIATELY /* this might need fiddling */
322 HRESULT hr = ID2D1Factory_CreateHwndRenderTarget(sys->d2_factory,
325 &sys->d2_render_target);
327 msg_Err(vd, "Cannot create render target (hvideownd = 0x%x, width = %d, height = %d, pf.format = %d, hr = 0x%x)!",
328 (unsigned)hrtp.hwnd, hrtp.pixelSize.width,
329 hrtp.pixelSize.height, pf.format, (unsigned)hr);
331 sys->d2_render_target = NULL;
338 ID2D1Factory_GetDesktopDpi(sys->d2_factory,
342 D2D1_BITMAP_PROPERTIES bp = {
348 D2D1_SIZE_U bitmap_size = {
349 vd->fmt.i_visible_width,
350 vd->fmt.i_visible_height
353 hr = ID2D1HwndRenderTarget_CreateBitmap(sys->d2_render_target,
360 msg_Err(vd, "Failed to create bitmap (hr = 0x%x)!", (unsigned)hr);
362 sys->d2_bitmap = NULL;
363 D2D_DestroyRenderTarget(vd);
369 msg_Dbg(vd, "Render trgt dbg: dpi = %f, render_target = %p, bitmap = %p",
370 dpi_x, sys->d2_render_target, sys->d2_bitmap);
377 * Resizes a ID2D1HWndRenderTarget
379 static void D2D_ResizeRenderTarget(vout_display_t *vd)
381 vout_display_sys_t *sys = vd->sys;
384 sys->rect_dest.right - sys->rect_dest.left,
385 sys->rect_dest.bottom - sys->rect_dest.top
388 HRESULT hr = ID2D1HwndRenderTarget_Resize(sys->d2_render_target, &size);
390 msg_Err(vd, "Cannot resize render target (width = %d, height = %d, hr = 0x%x)!",
391 size.width, size.height, (unsigned)hr);
395 * Cleans up ID2D1HwndRenderTarget and ID2D1Bitmap
397 static void D2D_DestroyRenderTarget(vout_display_t *vd)
399 vout_display_sys_t *sys = vd->sys;
401 if (sys->d2_render_target) {
402 ID2D1HwndRenderTarget_Release(sys->d2_render_target);
403 sys->d2_render_target = NULL;
406 if (sys->d2_bitmap) {
407 ID2D1Bitmap_Release(sys->d2_bitmap);
408 sys->d2_bitmap = NULL;
412 msg_Dbg(vd, "Destroyed");