From: David Kaplan Date: Wed, 28 Jul 2010 08:17:11 +0000 (+0300) Subject: Direct2D video output module X-Git-Tag: 1.2.0-pre1~5632 X-Git-Url: https://git.sesse.net/?p=vlc;a=commitdiff_plain;h=b19c57842c9d0d05e7a9226320b8a2383b179cd8 Direct2D video output module Adds support for the D2D API on Win7/Vista SP2 with Platform Update Requires d2d1 contrib headers Signed-off-by: Laurent Aimar --- diff --git a/configure.ac b/configure.ac index 9a22804a96..52e48308cc 100644 --- a/configure.ac +++ b/configure.ac @@ -3449,6 +3449,23 @@ then fi fi +dnl +dnl Windows Direct2D plugin +dnl +AC_ARG_ENABLE(direct2d, + [ --enable-direct2d Win7/VistaPU Direct2D support (default auto on Win32)]) +if test "${enable_direct2d}" != "no"; then + if test "${SYS}" = "mingw32" -o "${SYS}" = "mingwce" + then + AC_CHECK_HEADERS(d2d1.h, + [ + VLC_ADD_PLUGIN([direct2d]) + VLC_ADD_LIBS([direct2d],[-lgdi32 -lole32]) + ], [AC_MSG_WARN([Cannot find Direct2D headers!])] + ) + fi +fi + dnl dnl win32 GDI plugin dnl diff --git a/modules/video_output/msw/Modules.am b/modules/video_output/msw/Modules.am index 51807c882c..0613bae510 100644 --- a/modules/video_output/msw/Modules.am +++ b/modules/video_output/msw/Modules.am @@ -1,3 +1,11 @@ +SOURCES_direct2d = \ + direct2d.c \ + common.h \ + events.h \ + events.c \ + common.c \ + $(NULL) + SOURCES_directx = \ directx.c \ common.h \ diff --git a/modules/video_output/msw/common.c b/modules/video_output/msw/common.c index 5704d5ca61..fddbd3dc02 100644 --- a/modules/video_output/msw/common.c +++ b/modules/video_output/msw/common.c @@ -48,6 +48,9 @@ #ifdef MODULE_NAME_IS_glwin32 #include "../opengl.h" #endif +#ifdef MODULE_NAME_IS_direct2d +#include +#endif #include "common.h" @@ -379,7 +382,7 @@ void UpdateRects(vout_display_t *vd, SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS); /* Destination image position and dimensions */ -#if defined(MODULE_NAME_IS_direct3d) +#if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d) rect_dest.left = 0; rect_dest.right = place.width; rect_dest.top = 0; @@ -398,7 +401,7 @@ void UpdateRects(vout_display_t *vd, #endif -#if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d) +#if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d) /* UpdateOverlay directdraw function doesn't automatically clip to the * display size so we need to do it otherwise it will fail * It is also needed for d3d to avoid exceding our surface size */ @@ -457,7 +460,7 @@ void UpdateRects(vout_display_t *vd, /* Apply overlay hardware constraints */ if (sys->use_overlay) AlignRect(&rect_src_clipped, sys->i_align_src_boundary, sys->i_align_src_size); -#elif defined(MODULE_NAME_IS_direct3d) +#elif defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d) /* Needed at least with YUV content */ rect_src_clipped.left &= ~1; rect_src_clipped.right &= ~1; diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h index e023ef4315..3a67c7d117 100644 --- a/modules/video_output/msw/common.h +++ b/modules/video_output/msw/common.h @@ -157,6 +157,13 @@ struct vout_display_sys_t vout_display_opengl_t vgl; #endif +#ifdef MODULE_NAME_IS_direct2d + HINSTANCE d2_dll; /* handle of the opened d2d1 dll */ + ID2D1Factory *d2_factory; /* D2D factory */ + ID2D1HwndRenderTarget *d2_render_target; /* D2D rendering target */ + ID2D1Bitmap *d2_bitmap; /* D2 bitmap */ +#endif + #ifdef MODULE_NAME_IS_direct3d bool allow_hw_yuv; /* Should we use hardware YUV->RGB conversions */ /* show video on desktop window ? */ diff --git a/modules/video_output/msw/direct2d.c b/modules/video_output/msw/direct2d.c new file mode 100644 index 0000000000..11757bd03f --- /dev/null +++ b/modules/video_output/msw/direct2d.c @@ -0,0 +1,417 @@ +/***************************************************************************** + * direct2d.c : Direct2D video output plugin for vlc (Win7/Vista SP2 PF Update) + ***************************************************************************** + * Copyright (C) 2010 VideoLAN and AUTHORS + * $Id$ + * + * Author: David Kaplan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "common.h" + +#include +#undef GUID_EXT +#define GUID_EXT +DEFINE_GUID(IID_ID2D1Factory, 0x6152247, 0x6f50, 0x465a, 0x92, 0x45, 0x11, 0x8b, 0xfd, 0x3b, 0x60, 0x7); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open (vlc_object_t *); +static void Close(vlc_object_t *); + +#define D2D_HELP N_("Video output for Windows 7/Windows Vista with Platform update") + +vlc_module_begin () + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) + set_help(D2D_HELP) + set_shortname("Direct2D") + set_description(N_("Direct2D video output")) + set_capability("vout display", 65) + add_shortcut("direct2d") + set_callbacks(Open, Close) +vlc_module_end () + + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Prepare(vout_display_t *, picture_t *); +static void Display(vout_display_t *, picture_t *); +static int Control(vout_display_t *, int, va_list); +static void Manage (vout_display_t *); + +static int D2D_CreateRenderTarget(vout_display_t *vd); +static void D2D_ResizeRenderTarget(vout_display_t *vd); +static void D2D_DestroyRenderTarget(vout_display_t *vd); + +/** + * Initialises Direct2D vout module + */ +static int Open(vlc_object_t *object) +{ + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys; + + vd->sys = sys = calloc(1, sizeof(*sys)); + if (!sys) + return VLC_ENOMEM; + + sys->d2_render_target = NULL; + + sys->d2_dll = LoadLibrary(TEXT("D2D1.DLL")); + if (!sys->d2_dll) { + if (object->b_force) + msg_Err(vd, "Cannot load D2D1.DLL, aborting"); + goto error; + } + + D2D1_FACTORY_OPTIONS fo = { + D2D1_DEBUG_LEVEL_NONE + }; + + HRESULT (WINAPI *D2D1CreateFactory)(D2D1_FACTORY_TYPE, REFIID, + const D2D1_FACTORY_OPTIONS *, + void **); + + D2D1CreateFactory = (void *)GetProcAddress(sys->d2_dll, + TEXT("D2D1CreateFactory")); + if (!D2D1CreateFactory) { + msg_Err(vd, + "Cannot locate reference to a D2D1CreateFactory ABI in D2D1.DLL"); + goto error; + } + +#ifndef NDEBUG + msg_Dbg(vd, "D2D1.DLL loaded"); +#endif + + HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + (REFIID)&IID_ID2D1Factory, + &fo, + (void **)&sys->d2_factory); + if (hr != S_OK) { + msg_Err(vd, "Cannot create Direct2D factory (hr = 0x%x)!", + (unsigned)hr); + goto error; + } + + if (CommonInit(vd)) + goto error; + + if (D2D_CreateRenderTarget(vd) != VLC_SUCCESS) + goto error; + + vout_display_info_t info = vd->info; + info.is_slow = false; + info.has_double_click = true; + info.has_hide_mouse = false; + info.has_pictures_invalid = false; + vd->info = info; + + vd->fmt.i_chroma = VLC_CODEC_RGB32; /* masks change this to BGR32 for ID2D1Bitmap */ + vd->fmt.i_rmask = 0x0000ff00; + vd->fmt.i_gmask = 0x00ff0000; + vd->fmt.i_bmask = 0xff000000; + + vd->pool = Pool; + vd->prepare = Prepare; + vd->display = Display; + vd->manage = Manage; + vd->control = Control; + + EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct2D output)"); + +#ifndef NDEBUG + msg_Dbg(vd, "Ready"); +#endif + + return VLC_SUCCESS; + +error: + Close(VLC_OBJECT(vd)); + return VLC_EGENERIC; +} + +/** + * Close Direct2D vout + */ +static void Close(vlc_object_t *object) +{ + vout_display_t *vd = (vout_display_t *)object; + + D2D_DestroyRenderTarget(vd); + + if (vd->sys->pool) + picture_pool_Delete(vd->sys->pool); + + CommonClean(vd); + + free(vd->sys); +} + +/** + * Handles pool allocations for bitmaps + */ +static picture_pool_t *Pool(vout_display_t *vd, unsigned count) +{ + vout_display_sys_t *sys = vd->sys; + + if (!sys->pool) { + sys->pool = picture_pool_NewFromFormat(&vd->fmt, count); +#ifndef NDEBUG + msg_Dbg(vd, "New picture pool created"); +#endif + } + + return sys->pool; +} + +/** + * Performs set up of ID2D1Bitmap memory ready for blitting + */ +static void Prepare(vout_display_t *vd, picture_t *picture) +{ + vout_display_sys_t *sys = vd->sys; + + if (sys->d2_render_target && sys->d2_bitmap) { + + HRESULT hr = ID2D1Bitmap_CopyFromMemory(sys->d2_bitmap, + NULL /*&r_src*/, + picture->p[0].p_pixels, + picture->p[0].i_pitch); + if (hr != S_OK) + msg_Err(vd, "Failed to copy bitmap memory (hr = 0x%x)!", + (unsigned)hr); + +#ifndef NDEBUG + /*msg_Dbg(vd, "Bitmap dbg: target = %p, pitch = %d, bitmap = %p", + sys->d2_render_target, pitch, sys->d2_bitmap);*/ +#endif + } +} + +/** + * Blits a scaled picture_t to the render target + */ +static void Display(vout_display_t *vd, picture_t *picture) +{ + vout_display_sys_t *sys = vd->sys; + + D2D1_RECT_F r_dest = { + sys->rect_dest.left, + sys->rect_dest.top, + sys->rect_dest.right, + sys->rect_dest.bottom + }; + + if (sys->d2_render_target && sys->d2_bitmap) { + ID2D1HwndRenderTarget_BeginDraw(sys->d2_render_target); + + ID2D1HwndRenderTarget_DrawBitmap(sys->d2_render_target, + sys->d2_bitmap, + &r_dest, + 1.0f, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + NULL); + + HRESULT hr = ID2D1HwndRenderTarget_EndDraw(sys->d2_render_target, + NULL, + NULL); + if (hr == D2DERR_RECREATE_TARGET) { + D2D_DestroyRenderTarget(vd); + D2D_CreateRenderTarget(vd); + } + } + + picture_Release(picture); + + CommonDisplay(vd); +} + + /** + * Control event handler + */ +static int Control(vout_display_t *vd, int query, va_list args) +{ + return CommonControl(vd, query, args); +} + +/** + * Handles surface management + * ID2D1RenderTargets cannot be resized and must be recreated + */ +static void Manage(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; + + CommonManage(vd); + + if (sys->changes & DX_POSITION_CHANGE) { + D2D_ResizeRenderTarget(vd); + sys->changes &= ~DX_POSITION_CHANGE; + } +} + +/** + * Creates a ID2D1HwndRenderTarget and associated ID2D1Bitmap + */ +static int D2D_CreateRenderTarget(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; + + sys->d2_render_target = NULL; + + D2D1_PIXEL_FORMAT pf = { + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_IGNORE + }; + + D2D1_RENDER_TARGET_PROPERTIES rtp = { + D2D1_RENDER_TARGET_TYPE_DEFAULT, + pf, + 0, + 0, + D2D1_RENDER_TARGET_USAGE_NONE, + D2D1_FEATURE_LEVEL_DEFAULT + }; + + D2D1_SIZE_U size = { + sys->rect_dest.right - sys->rect_dest.left, + sys->rect_dest.bottom - sys->rect_dest.top + }; + + D2D1_HWND_RENDER_TARGET_PROPERTIES hrtp = { + sys->hvideownd, + size, + D2D1_PRESENT_OPTIONS_IMMEDIATELY /* this might need fiddling */ + }; + + HRESULT hr = ID2D1Factory_CreateHwndRenderTarget(sys->d2_factory, + &rtp, + &hrtp, + &sys->d2_render_target); + if (hr != S_OK) { + msg_Err(vd, "Cannot create render target (hvideownd = 0x%x, width = %d, height = %d, pf.format = %d, hr = 0x%x)!", + (unsigned)hrtp.hwnd, hrtp.pixelSize.width, + hrtp.pixelSize.height, pf.format, (unsigned)hr); + + sys->d2_render_target = NULL; + + return VLC_EGENERIC; + } + + FLOAT dpi_x, dpi_y; + + ID2D1Factory_GetDesktopDpi(sys->d2_factory, + &dpi_x, + &dpi_y); + + D2D1_BITMAP_PROPERTIES bp = { + pf, + dpi_x, + dpi_y + }; + + D2D1_SIZE_U bitmap_size = { + vd->fmt.i_width, + vd->fmt.i_height + }; + + hr = ID2D1HwndRenderTarget_CreateBitmap(sys->d2_render_target, + bitmap_size, + NULL, + 0, + &bp, + &sys->d2_bitmap); + if (hr != S_OK) { + msg_Err(vd, "Failed to create bitmap (hr = 0x%x)!", (unsigned)hr); + + sys->d2_bitmap = NULL; + D2D_DestroyRenderTarget(vd); + + return VLC_EGENERIC; + } + +#ifndef NDEBUG + msg_Dbg(vd, "Render trgt dbg: dpi = %f, render_target = %p, bitmap = %p", + dpi_x, sys->d2_render_target, sys->d2_bitmap); +#endif + + return VLC_SUCCESS; +} + +/** + * Resizes a ID2D1HWndRenderTarget + */ +static void D2D_ResizeRenderTarget(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; + + D2D1_SIZE_U size = { + sys->rect_dest.right - sys->rect_dest.left, + sys->rect_dest.bottom - sys->rect_dest.top + }; + + HRESULT hr = ID2D1HwndRenderTarget_Resize(sys->d2_render_target, &size); + if (hr != S_OK) + msg_Err(vd, "Cannot resize render target (width = %d, height = %d, hr = 0x%x)!", + size.width, size.height, (unsigned)hr); +} + +/** + * Cleans up ID2D1HwndRenderTarget and ID2D1Bitmap + */ +static void D2D_DestroyRenderTarget(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; + + if (sys->d2_render_target) { + ID2D1HwndRenderTarget_Release(sys->d2_render_target); + sys->d2_render_target = NULL; + } + + if (sys->d2_bitmap) { + ID2D1Bitmap_Release(sys->d2_bitmap); + sys->d2_bitmap = NULL; + } + +#ifndef NDEBUG + msg_Dbg(vd, "Destroyed"); +#endif +} diff --git a/modules/video_output/msw/events.c b/modules/video_output/msw/events.c index d2d5e26c38..46c15c4a55 100644 --- a/modules/video_output/msw/events.c +++ b/modules/video_output/msw/events.c @@ -49,6 +49,9 @@ #ifdef MODULE_NAME_IS_glwin32 #include "../opengl.h" #endif +#ifdef MODULE_NAME_IS_direct2d +#include +#endif #include #include "common.h"