[vlc-commits] direct3d9: reorder code to avoid forward declarations
Steve Lhomme
git at videolan.org
Tue Nov 20 09:18:09 CET 2018
vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Thu Nov 15 09:37:13 2018 +0100| [71bf7530e1566f8b6b41326bc630cab33085eb4e] | committer: Steve Lhomme
direct3d9: reorder code to avoid forward declarations
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=71bf7530e1566f8b6b41326bc630cab33085eb4e
---
modules/video_output/win32/direct3d9.c | 1730 ++++++++++++++++----------------
1 file changed, 847 insertions(+), 883 deletions(-)
diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c
index 19cd570f84..797e5656a3 100644
--- a/modules/video_output/win32/direct3d9.c
+++ b/modules/video_output/win32/direct3d9.c
@@ -167,25 +167,6 @@ struct vout_display_sys_t
bool desktop_requested;
};
-static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target);
-
-static int Open(vlc_object_t *);
-
-static picture_pool_t *Direct3D9CreatePicturePool (vlc_object_t *, d3d9_device_t *,
- const d3d9_format_t *, const video_format_t *, unsigned);
-
-static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture, vlc_tick_t);
-static void Display(vout_display_t *, picture_t *);
-static picture_pool_t*DisplayPool(vout_display_t *, unsigned);
-static int Control(vout_display_t *, int, va_list);
-static void Manage (vout_display_t *);
-
-static int Direct3D9Reset (vout_display_t *);
-static void Direct3D9Destroy(vout_display_sys_t *);
-
-static int Direct3D9Open (vout_display_t *, video_format_t *);
-static void Direct3D9Close(vout_display_t *);
-
/* */
typedef struct
{
@@ -204,16 +185,7 @@ typedef struct d3d_region_t {
IDirect3DTexture9 *texture;
} d3d_region_t;
-static void Direct3D9DeleteRegions(size_t, d3d_region_t *);
-
-static int Direct3D9ImportPicture(vout_display_t *vd, d3d_region_t *, IDirect3DSurface9 *surface);
-static void Direct3D9ImportSubpicture(vout_display_t *vd, size_t *, d3d_region_t **, subpicture_t *);
-
-static void Direct3D9RenderScene(vout_display_t *vd, d3d_region_t *, size_t, d3d_region_t *);
-
/* */
-static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
-
static bool is_d3d9_opaque(vlc_fourcc_t chroma)
{
switch (chroma)
@@ -239,136 +211,6 @@ static HINSTANCE Direct3D9LoadShaderLibrary(void)
return instance;
}
-/**
- * It creates a Direct3D vout display.
- */
-static int Open(vlc_object_t *object)
-{
- vout_display_t *vd = (vout_display_t *)object;
- vout_display_sys_t *sys;
-
- if ( !vd->obj.force && vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR)
- return VLC_EGENERIC; /* let a module who can handle it do it */
-
- if ( !vd->obj.force && vd->source.mastering.max_luminance != 0)
- return VLC_EGENERIC; /* let a module who can handle it do it */
-
-#if !VLC_WINSTORE_APP
- /* do not use D3D9 on XP unless forced */
- if (!vd->obj.force)
- {
- bool isVistaOrGreater = false;
- HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
- if (likely(hKernel32 != NULL))
- isVistaOrGreater = GetProcAddress(hKernel32, "EnumResourceLanguagesExW") != NULL;
- if (!isVistaOrGreater)
- return VLC_EGENERIC;
- }
-#endif
-
- /* Allocate structure */
- vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
- if (!sys)
- return VLC_ENOMEM;
-
- if (D3D9_Create(vd, &sys->hd3d)) {
- msg_Err(vd, "Direct3D9 could not be initialized");
- free(sys);
- return VLC_EGENERIC;
- }
-
- sys->hxdll = Direct3D9LoadShaderLibrary();
- if (!sys->hxdll)
- msg_Warn(object, "cannot load Direct3D9 Shader Library; HLSL pixel shading will be disabled.");
-
- sys->sys.use_desktop = var_CreateGetBool(vd, "video-wallpaper");
- sys->reset_device = false;
- sys->reopen_device = false;
- sys->lost_not_ready = false;
- sys->allow_hw_yuv = var_CreateGetBool(vd, "directx-hw-yuv");
- sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
- sys->desktop_save.is_on_top = false;
- sys->desktop_save.win.left = var_InheritInteger(vd, "video-x");
- sys->desktop_save.win.right = vd->cfg->display.width;
- sys->desktop_save.win.top = var_InheritInteger(vd, "video-y");
- sys->desktop_save.win.bottom = vd->cfg->display.height;
-
- if (CommonInit(vd, false))
- goto error;
-
- /* */
- video_format_t fmt;
- if (Direct3D9Open(vd, &fmt)) {
- msg_Err(vd, "Direct3D9 could not be opened");
- goto error;
- }
-
- /* */
- vout_display_info_t info = vd->info;
- info.is_slow = !is_d3d9_opaque(fmt.i_chroma);
- info.has_double_click = true;
- info.has_pictures_invalid = !is_d3d9_opaque(fmt.i_chroma);
- if (var_InheritBool(vd, "direct3d9-hw-blending") &&
- sys->d3dregion_format != D3DFMT_UNKNOWN &&
- (sys->d3d_dev.caps.SrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) &&
- (sys->d3d_dev.caps.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) &&
- (sys->d3d_dev.caps.TextureCaps & D3DPTEXTURECAPS_ALPHA) &&
- (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1) &&
- (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE))
- info.subpicture_chromas = d3d_subpicture_chromas;
- else
- info.subpicture_chromas = NULL;
-
- /* Interaction */
- vlc_mutex_init(&sys->lock);
- sys->ch_desktop = false;
- sys->desktop_requested = sys->sys.use_desktop;
-
- var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, _("Desktop"));
- var_AddCallback(vd, "video-wallpaper", DesktopCallback, NULL);
-
- /* Setup vout_display now that everything is fine */
- video_format_Clean(&vd->fmt);
- video_format_Copy(&vd->fmt, &fmt);
- vd->info = info;
-
- vd->pool = DisplayPool;
- vd->prepare = Prepare;
- vd->display = Display;
- vd->control = Control;
-
- /* Fix state in case of desktop mode */
- if (sys->sys.use_desktop && vd->cfg->is_fullscreen)
- vout_display_SendEventFullscreen(vd, false);
-
- return VLC_SUCCESS;
-error:
- Direct3D9Close(vd);
- CommonClean(vd);
- Direct3D9Destroy(sys);
- free(vd->sys);
- return VLC_EGENERIC;
-}
-
-/**
- * It destroyes a Direct3D vout display.
- */
-static void Close(vlc_object_t *object)
-{
- vout_display_t * vd = (vout_display_t *)object;
-
- var_DelCallback(vd, "video-wallpaper", DesktopCallback, NULL);
- vlc_mutex_destroy(&vd->sys->lock);
-
- Direct3D9Close(vd);
-
- CommonClean(vd);
-
- Direct3D9Destroy(vd->sys);
-
- free(vd->sys);
-}
-
static void DestroyPicture(picture_t *picture)
{
ReleasePictureSys(picture->p_sys);
@@ -500,419 +342,222 @@ static picture_pool_t *DisplayPool(vout_display_t *vd, unsigned count)
return vd->sys->sys.pool;
}
-static void Prepare(vout_display_t *vd, picture_t *picture,
- subpicture_t *subpicture, vlc_tick_t date)
+/**
+ * Compute the vertex ordering needed to rotate the video. Without
+ * rotation, the vertices of the rectangle are defined in a clockwise
+ * order. This function computes a remapping of the coordinates to
+ * implement the rotation, given fixed texture coordinates.
+ * The unrotated order is the following:
+ * 0--1
+ * | |
+ * 3--2
+ * For a 180 degrees rotation it should like this:
+ * 2--3
+ * | |
+ * 1--0
+ * Vertex 0 should be assigned coordinates at index 2 from the
+ * unrotated order and so on, thus yielding order: 2 3 0 1.
+ */
+static void orientationVertexOrder(video_orientation_t orientation, int vertex_order[static 4])
{
- Manage(vd);
- VLC_UNUSED(date);
- vout_display_sys_t *sys = vd->sys;
- picture_sys_t *p_sys = picture->p_sys;
- IDirect3DSurface9 *surface = p_sys->surface;
- d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
-
- /* FIXME it is a bit ugly, we need the surface to be unlocked for
- * rendering.
- * The clean way would be to release the picture (and ensure that
- * the vout doesn't keep a reference). But because of the vout
- * wrapper, we can't */
- if ( !is_d3d9_opaque(picture->format.i_chroma) )
- Direct3D9UnlockSurface(picture);
- else if (picture->context)
- {
- const struct va_pic_context *pic_ctx = (struct va_pic_context*)picture->context;
- if (pic_ctx->picsys.surface != surface)
- {
- D3DSURFACE_DESC srcDesc, dstDesc;
- IDirect3DSurface9_GetDesc(pic_ctx->picsys.surface, &srcDesc);
- IDirect3DSurface9_GetDesc(surface, &dstDesc);
- if ( srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height )
- surface = pic_ctx->picsys.surface;
- else
- {
- HRESULT hr;
- RECT visibleSource;
- visibleSource.left = 0;
- visibleSource.top = 0;
- visibleSource.right = picture->format.i_visible_width;
- visibleSource.bottom = picture->format.i_visible_height;
-
- hr = IDirect3DDevice9_StretchRect( p_d3d9_dev->dev, pic_ctx->picsys.surface, &visibleSource, surface, &visibleSource, D3DTEXF_NONE);
- if (FAILED(hr)) {
- msg_Err(vd, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
- }
- }
- }
+ switch (orientation) {
+ case ORIENT_ROTATED_90: /* ORIENT_RIGHT_TOP */
+ vertex_order[0] = 1;
+ vertex_order[1] = 2;
+ vertex_order[2] = 3;
+ vertex_order[3] = 0;
+ break;
+ case ORIENT_ROTATED_270: /* ORIENT_LEFT_BOTTOM */
+ vertex_order[0] = 3;
+ vertex_order[1] = 0;
+ vertex_order[2] = 1;
+ vertex_order[3] = 2;
+ break;
+ case ORIENT_ROTATED_180: /* ORIENT_BOTTOM_RIGHT */
+ vertex_order[0] = 2;
+ vertex_order[1] = 3;
+ vertex_order[2] = 0;
+ vertex_order[3] = 1;
+ break;
+ case ORIENT_TRANSPOSED: /* ORIENT_LEFT_TOP */
+ vertex_order[0] = 0;
+ vertex_order[1] = 3;
+ vertex_order[2] = 2;
+ vertex_order[3] = 1;
+ break;
+ case ORIENT_HFLIPPED: /* ORIENT_TOP_RIGHT */
+ vertex_order[0] = 1;
+ vertex_order[1] = 0;
+ vertex_order[2] = 3;
+ vertex_order[3] = 2;
+ break;
+ case ORIENT_VFLIPPED: /* ORIENT_BOTTOM_LEFT */
+ vertex_order[0] = 3;
+ vertex_order[1] = 2;
+ vertex_order[2] = 1;
+ vertex_order[3] = 0;
+ break;
+ case ORIENT_ANTI_TRANSPOSED: /* ORIENT_RIGHT_BOTTOM */
+ vertex_order[0] = 2;
+ vertex_order[1] = 1;
+ vertex_order[2] = 0;
+ vertex_order[3] = 3;
+ break;
+ default:
+ vertex_order[0] = 0;
+ vertex_order[1] = 1;
+ vertex_order[2] = 2;
+ vertex_order[3] = 3;
+ break;
}
+}
- /* check if device is still available */
- HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(p_d3d9_dev->dev);
- if (FAILED(hr)) {
- if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) {
- if (vd->info.has_pictures_invalid)
- vout_display_SendEventPicturesInvalid(vd);
- sys->reset_device = true;
- sys->lost_not_ready = false;
- }
- if (hr == D3DERR_DEVICELOST && !sys->lost_not_ready) {
- /* Device is lost but not yet ready for reset. */
- sys->lost_not_ready = true;
- }
- return;
- }
-
- d3d_region_t picture_region;
- if (!Direct3D9ImportPicture(vd, &picture_region, surface)) {
- picture_region.width = picture->format.i_visible_width;
- picture_region.height = picture->format.i_visible_height;
- size_t subpicture_region_count = 0;
- d3d_region_t *subpicture_region = NULL;
- if (subpicture)
- Direct3D9ImportSubpicture(vd, &subpicture_region_count, &subpicture_region,
- subpicture);
+static void Direct3D9SetupVertices(CUSTOMVERTEX *vertices,
+ const RECT *src, const RECT *src_clipped,
+ const RECT *dst,
+ int alpha,
+ video_orientation_t orientation)
+{
+ /* Vertices of the dst rectangle in the unrotated (clockwise) order. */
+ const int vertices_coords[4][2] = {
+ { dst->left, dst->top },
+ { dst->right, dst->top },
+ { dst->right, dst->bottom },
+ { dst->left, dst->bottom },
+ };
- Direct3D9RenderScene(vd, &picture_region,
- subpicture_region_count, subpicture_region);
+ /* Compute index remapping necessary to implement the rotation. */
+ int vertex_order[4];
+ orientationVertexOrder(orientation, vertex_order);
- Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
- sys->d3dregion_count = subpicture_region_count;
- sys->d3dregion = subpicture_region;
+ for (int i = 0; i < 4; ++i) {
+ vertices[i].x = vertices_coords[vertex_order[i]][0];
+ vertices[i].y = vertices_coords[vertex_order[i]][1];
}
-}
-static void Display(vout_display_t *vd, picture_t *picture)
-{
- vout_display_sys_t *sys = vd->sys;
- const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+ float right = (float)src_clipped->right / (float)src->right;
+ float left = (float)src_clipped->left / (float)src->right;
+ float top = (float)src_clipped->top / (float)src->bottom;
+ float bottom = (float)src_clipped->bottom / (float)src->bottom;
- if (sys->lost_not_ready)
- return;
+ vertices[0].tu = left;
+ vertices[0].tv = top;
- // Present the back buffer contents to the display
- // No stretching should happen here !
- const RECT src = sys->sys.rect_dest_clipped;
- const RECT dst = sys->sys.rect_dest_clipped;
+ vertices[1].tu = right;
+ vertices[1].tv = top;
- HRESULT hr;
- if (sys->hd3d.use_ex) {
- hr = IDirect3DDevice9Ex_PresentEx(p_d3d9_dev->devex, &src, &dst, NULL, NULL, 0);
- } else {
- hr = IDirect3DDevice9_Present(p_d3d9_dev->dev, &src, &dst, NULL, NULL);
- }
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed Present: 0x%0lx", hr);
- }
+ vertices[2].tu = right;
+ vertices[2].tv = bottom;
- /* XXX See Prepare() */
- if ( !is_d3d9_opaque(picture->format.i_chroma) )
- Direct3D9LockSurface(picture);
+ vertices[3].tu = left;
+ vertices[3].tv = bottom;
- CommonDisplay(vd);
+ for (int i = 0; i < 4; i++) {
+ /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
+ /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
+ vertices[i].x -= 0.5;
+ vertices[i].y -= 0.5;
+
+ vertices[i].z = 0.0f;
+ vertices[i].rhw = 1.0f;
+ vertices[i].diffuse = D3DCOLOR_ARGB(alpha, 255, 255, 255);
+ }
}
-static int ControlReopenDevice(vout_display_t *vd)
+/**
+ * It copies picture surface into a texture and setup the associated d3d_region_t.
+ */
+static int Direct3D9ImportPicture(vout_display_t *vd,
+ d3d_region_t *region,
+ IDirect3DSurface9 *source)
{
vout_display_sys_t *sys = vd->sys;
+ HRESULT hr;
- if (!sys->sys.use_desktop) {
- /* Save non-desktop state */
- sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
- sys->desktop_save.is_on_top = sys->sys.is_on_top;
-
- WINDOWPLACEMENT wp = { .length = sizeof(wp), };
- GetWindowPlacement(sys->sys.hparent ? sys->sys.hparent : sys->sys.hwnd, &wp);
- sys->desktop_save.win = wp.rcNormalPosition;
- }
-
- /* */
- Direct3D9Close(vd);
- if (!sys->sys.b_windowless)
- EventThreadStop(sys->sys.event);
-
- /* */
- vlc_mutex_lock(&sys->lock);
- sys->sys.use_desktop = sys->desktop_requested;
- sys->ch_desktop = false;
- vlc_mutex_unlock(&sys->lock);
-
- /* */
- event_cfg_t cfg;
- memset(&cfg, 0, sizeof(cfg));
- cfg.use_desktop = sys->sys.use_desktop;
- if (!sys->sys.use_desktop) {
- cfg.x = sys->desktop_save.win.left;
- cfg.y = sys->desktop_save.win.top;
- cfg.width = sys->desktop_save.win.right - sys->desktop_save.win.left;
- cfg.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top;
+ if (!source) {
+ msg_Dbg(vd, "no surface to render?");
+ return VLC_EGENERIC;
}
- event_hwnd_t hwnd;
- if (!sys->sys.b_windowless && EventThreadStart(sys->sys.event, &hwnd, &cfg)) {
- msg_Err(vd, "Failed to restart event thread");
+ /* retrieve texture top-level surface */
+ IDirect3DSurface9 *destination;
+ hr = IDirect3DTexture9_GetSurfaceLevel(sys->sceneTexture, 0, &destination);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed IDirect3DTexture9_GetSurfaceLevel: 0x%0lx", hr);
return VLC_EGENERIC;
}
- sys->sys.parent_window = hwnd.parent_window;
- sys->sys.hparent = hwnd.hparent;
- sys->sys.hwnd = hwnd.hwnd;
- sys->sys.hvideownd = hwnd.hvideownd;
- sys->sys.hfswnd = hwnd.hfswnd;
- SetRectEmpty(&sys->sys.rect_parent);
- /* */
- video_format_t fmt;
- if (Direct3D9Open(vd, &fmt)) {
- CommonClean(vd);
- msg_Err(vd, "Failed to reopen device");
+ /* Copy picture surface into texture surface
+ * color space conversion happen here */
+ RECT copy_rect = sys->sys.rect_src_clipped;
+ // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
+ // When copying the entire buffer, the margin end up being blended in the actual picture
+ // on nVidia (regardless of even/odd dimensions)
+ if ( copy_rect.right & 1 ) copy_rect.right++;
+ if ( copy_rect.left & 1 ) copy_rect.left--;
+ if ( copy_rect.bottom & 1 ) copy_rect.bottom++;
+ if ( copy_rect.top & 1 ) copy_rect.top--;
+ hr = IDirect3DDevice9_StretchRect(sys->d3d_dev.dev, source, ©_rect, destination,
+ ©_rect, D3DTEXF_NONE);
+ IDirect3DSurface9_Release(destination);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed StretchRect: source 0x%p 0x%0lx",
+ (LPVOID)source, hr);
return VLC_EGENERIC;
}
- vd->fmt = fmt;
- sys->sys.is_first_display = true;
- if (sys->sys.use_desktop) {
- /* Disable fullscreen/on_top while using desktop */
- if (sys->desktop_save.is_fullscreen)
- vout_display_SendEventFullscreen(vd, false);
- if (sys->desktop_save.is_on_top)
- vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_NORMAL);
- } else {
- /* Restore fullscreen/on_top */
- if (sys->desktop_save.is_fullscreen)
- vout_display_SendEventFullscreen(vd, true);
- if (sys->desktop_save.is_on_top)
- vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_ABOVE);
- }
+ /* */
+ region->texture = sys->sceneTexture;
+ Direct3D9SetupVertices(region->vertex, &vd->sys->sys.rect_src, &vd->sys->sys.rect_src_clipped,
+ &vd->sys->sys.rect_dest_clipped, 255, vd->source.orientation);
return VLC_SUCCESS;
}
-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:
- /* FIXME what to do here in case of failure */
- if (sys->reset_device) {
- if (Direct3D9Reset(vd)) {
- msg_Err(vd, "Failed to reset device");
- return VLC_EGENERIC;
- }
- sys->reset_device = false;
- } else if(sys->reopen_device) {
- if (ControlReopenDevice(vd)) {
- msg_Err(vd, "Failed to reopen device");
- return VLC_EGENERIC;
- }
- sys->reopen_device = false;
- }
- return VLC_SUCCESS;
- default:
- return CommonControl(vd, query, args);
+static void Direct3D9DeleteRegions(size_t count, d3d_region_t *region)
+{
+ for (size_t i = 0; i < count; i++) {
+ if (region[i].texture)
+ IDirect3DTexture9_Release(region[i].texture);
}
+ free(region);
}
-static void Manage (vout_display_t *vd)
+
+/**
+ * It releases the scene resources.
+ */
+static void Direct3D9DestroyScene(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
- CommonManage(vd);
+ Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
- /* Desktop mode change */
- vlc_mutex_lock(&sys->lock);
- const bool ch_desktop = sys->ch_desktop;
- sys->ch_desktop = false;
- vlc_mutex_unlock(&sys->lock);
+ if (sys->sceneVertexBuffer)
+ {
+ IDirect3DVertexBuffer9_Release(sys->sceneVertexBuffer);
+ sys->sceneVertexBuffer = NULL;
+ }
- if (ch_desktop) {
- sys->reopen_device = true;
- if (vd->info.has_pictures_invalid)
- vout_display_SendEventPicturesInvalid(vd);
+ if (sys->sceneTexture)
+ {
+ IDirect3DTexture9_Release(sys->sceneTexture);
+ sys->sceneTexture = NULL;
}
- /* Position Change */
- if (sys->sys.changes & DX_POSITION_CHANGE) {
-#if 0 /* need that when bicubic filter is available */
- RECT rect;
- UINT width, height;
+ sys->d3dregion_count = 0;
+ sys->d3dregion = NULL;
- GetClientRect(p_sys->sys.hvideownd, &rect);
- width = rect.right-rect.left;
- height = rect.bottom-rect.top;
+ msg_Dbg(vd, "Direct3D9 scene released successfully");
+}
- if (width != p_sys->pp.BackBufferWidth || height != p_sys->pp.BackBufferHeight)
- {
- msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height);
- // need to reset D3D device to resize back buffer
- if (VLC_SUCCESS != Direct3D9ResetDevice(vd, width, height))
- return VLC_EGENERIC;
- }
-#endif
- sys->clear_scene = true;
- sys->sys.changes &= ~DX_POSITION_CHANGE;
- }
-}
-
-/**
- * It releases an instance of Direct3D9
- */
-static void Direct3D9Destroy(vout_display_sys_t *sys)
-{
- D3D9_Destroy( &sys->hd3d );
-
- if (sys->hxdll)
- {
- FreeLibrary(sys->hxdll);
- sys->hxdll = NULL;
- }
-}
-
-/* */
-static int Direct3D9CreateResources (vout_display_t *, video_format_t *);
-static void Direct3D9DestroyResources(vout_display_t *);
-
-/**
- * It creates a Direct3D9 device and the associated resources.
- */
-static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
-{
- vout_display_sys_t *sys = vd->sys;
-
- HRESULT hr = D3D9_CreateDevice(vd, &sys->hd3d, sys->sys.hvideownd,
- &vd->source, &sys->d3d_dev);
-
- if (FAILED(hr)) {
- msg_Err( vd, "D3D9 Creation failed! (hr=0x%0lx)", hr);
- return VLC_EGENERIC;
- }
-
- const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
- /* */
- RECT *display = &vd->sys->sys.rect_display;
- display->left = 0;
- display->top = 0;
- display->right = p_d3d9_dev->pp.BackBufferWidth;
- display->bottom = p_d3d9_dev->pp.BackBufferHeight;
-
- *fmt = vd->source;
-
- /* Find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
- * the requested chroma which is usable by the hardware in an offscreen surface, as they
- * typically support more formats than textures */
- const d3d9_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, p_d3d9_dev->pp.BackBufferFormat);
- if (!d3dfmt) {
- msg_Err(vd, "surface pixel format is not supported.");
- goto error;
- }
- fmt->i_chroma = d3dfmt->fourcc;
- fmt->i_rmask = d3dfmt->rmask;
- fmt->i_gmask = d3dfmt->gmask;
- fmt->i_bmask = d3dfmt->bmask;
- sys->d3dtexture_format = d3dfmt;
-
- UpdateRects(vd, NULL, true);
-
- if (Direct3D9CreateResources(vd, fmt)) {
- msg_Err(vd, "Failed to allocate resources");
- goto error;
- }
-
- /* Change the window title bar text */
- if (!vd->sys->sys.b_windowless)
- EventThreadUpdateTitle(sys->sys.event, VOUT_TITLE " (Direct3D9 output)");
-
- msg_Dbg(vd, "Direct3D9 device adapter successfully initialized");
- return VLC_SUCCESS;
-
-error:
- D3D9_ReleaseDevice(&sys->d3d_dev);
- return VLC_EGENERIC;
-}
-
-/**
- * It releases the Direct3D9 device and its resources.
- */
-static void Direct3D9Close(vout_display_t *vd)
-{
- vout_display_sys_t *sys = vd->sys;
-
- Direct3D9DestroyResources(vd);
- D3D9_ReleaseDevice(&sys->d3d_dev);
-}
-
-/**
- * It reset the Direct3D9 device and its resources.
- */
-static int Direct3D9Reset(vout_display_t *vd)
+static void Direct3D9DestroyShaders(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
- d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
-
- if (D3D9_FillPresentationParameters(&sys->hd3d, &vd->source, p_d3d9_dev))
- {
- msg_Err(vd, "Could not presentation parameters to reset device");
- return VLC_EGENERIC;
- }
-
- /* release all D3D objects */
- Direct3D9DestroyResources(vd);
-
- /* */
- HRESULT hr;
- if (sys->hd3d.use_ex){
- hr = IDirect3DDevice9Ex_ResetEx(p_d3d9_dev->devex, &p_d3d9_dev->pp, NULL);
- } else {
- hr = IDirect3DDevice9_Reset(p_d3d9_dev->dev, &p_d3d9_dev->pp);
- }
- if (FAILED(hr)) {
- msg_Err(vd, "IDirect3DDevice9_Reset failed! (hr=0x%0lx)", hr);
- return VLC_EGENERIC;
- }
- UpdateRects(vd, NULL, true);
-
- /* re-create them */
- if (Direct3D9CreateResources(vd, &vd->fmt)) {
- msg_Dbg(vd, "Direct3D9CreateResources failed !");
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
+ if (sys->d3dx_shader)
+ IDirect3DPixelShader9_Release(sys->d3dx_shader);
+ sys->d3dx_shader = NULL;
}
-/* */
-static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt);
-static void Direct3D9DestroyScene(vout_display_t *vd);
-
-static int Direct3D9CreateShaders(vout_display_t *vd);
-static void Direct3D9DestroyShaders(vout_display_t *vd);
-
-/**
- * It creates the picture and scene resources.
- */
-static int Direct3D9CreateResources(vout_display_t *vd, video_format_t *fmt)
-{
- vout_display_sys_t *sys = vd->sys;
-
- if (Direct3D9CreateScene(vd, fmt)) {
- msg_Err(vd, "Direct3D scene initialization failed !");
- return VLC_EGENERIC;
- }
- if (Direct3D9CreateShaders(vd)) {
- /* Failing to initialize shaders is not fatal. */
- msg_Warn(vd, "Direct3D shaders initialization failed !");
- }
-
- sys->d3dregion_format = D3DFMT_UNKNOWN;
- for (int i = 0; i < 2; i++) {
- D3DFORMAT dfmt = i == 0 ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8;
- if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(sys->hd3d.obj,
- D3DADAPTER_DEFAULT,
- D3DDEVTYPE_HAL,
- sys->d3d_dev.pp.BackBufferFormat,
- D3DUSAGE_DYNAMIC,
- D3DRTYPE_TEXTURE,
- dfmt))) {
- sys->d3dregion_format = dfmt;
- break;
- }
- }
- return VLC_SUCCESS;
-}
/**
* It destroys the picture and scene resources.
*/
@@ -928,98 +573,6 @@ static void Direct3D9DestroyResources(vout_display_t *vd)
}
/**
- * It tests if the conversion from src to dst is supported.
- */
-static int Direct3D9CheckConversion(vout_display_t *vd,
- D3DFORMAT src, D3DFORMAT dst)
-{
- vout_display_sys_t *sys = vd->sys;
- IDirect3D9 *d3dobj = sys->hd3d.obj;
- HRESULT hr;
-
- /* test whether device can create a surface of that format */
- hr = IDirect3D9_CheckDeviceFormat(d3dobj, D3DADAPTER_DEFAULT,
- D3DDEVTYPE_HAL, dst, 0,
- D3DRTYPE_SURFACE, src);
- if (SUCCEEDED(hr)) {
- /* test whether device can perform color-conversion
- ** from that format to target format
- */
- hr = IDirect3D9_CheckDeviceFormatConversion(d3dobj,
- D3DADAPTER_DEFAULT,
- D3DDEVTYPE_HAL,
- src, dst);
- }
- if (!SUCCEEDED(hr)) {
- if (D3DERR_NOTAVAILABLE != hr)
- msg_Err(vd, "Could not query adapter supported formats. (hr=0x%0lx)", hr);
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
-}
-
-static const d3d9_format_t d3d_formats[] = {
- /* YV12 is always used for planar 420, the planes are then swapped in Lock() */
- { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_YV12, 0,0,0 },
- { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_I420, 0,0,0 },
- { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_J420, 0,0,0 },
- { "NV12", MAKEFOURCC('N','V','1','2'), VLC_CODEC_NV12, 0,0,0 },
- { "DXA9", MAKEFOURCC('N','V','1','2'), VLC_CODEC_D3D9_OPAQUE, 0,0,0 },
- { "DXA9_10", MAKEFOURCC('P','0','1','0'), VLC_CODEC_D3D9_OPAQUE_10B, 0,0,0 },
- { "UYVY", D3DFMT_UYVY, VLC_CODEC_UYVY, 0,0,0 },
- { "YUY2", D3DFMT_YUY2, VLC_CODEC_YUYV, 0,0,0 },
- { "X8R8G8B8", D3DFMT_X8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
- { "A8R8G8B8", D3DFMT_A8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
- { "8G8B8", D3DFMT_R8G8B8, VLC_CODEC_RGB24, 0xff0000, 0x00ff00, 0x0000ff },
- { "R5G6B5", D3DFMT_R5G6B5, VLC_CODEC_RGB16, 0x1f<<11, 0x3f<<5, 0x1f<<0 },
- { "X1R5G5B5", D3DFMT_X1R5G5B5,VLC_CODEC_RGB15, 0x1f<<10, 0x1f<<5, 0x1f<<0 },
-
- { NULL, 0, 0, 0,0,0}
-};
-
-/**
- * It returns the format (closest to chroma) that can be converted to target */
-static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
-{
- vout_display_sys_t *sys = vd->sys;
- bool hardware_scale_ok = !(vd->fmt.i_visible_width & 1) && !(vd->fmt.i_visible_height & 1);
- if( !hardware_scale_ok )
- msg_Warn( vd, "Disabling hardware chroma conversion due to odd dimensions" );
-
- for (unsigned pass = 0; pass < 2; pass++) {
- const vlc_fourcc_t *list;
- const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
-
- if (pass == 0 && is_d3d9_opaque(chroma))
- list = dxva_chroma;
- else if (pass == 0 && hardware_scale_ok && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
- list = vlc_fourcc_GetYUVFallback(chroma);
- else if (pass == 1)
- list = vlc_fourcc_GetRGBFallback(chroma);
- else
- continue;
-
- for (unsigned i = 0; list[i] != 0; i++) {
- for (unsigned j = 0; d3d_formats[j].name; j++) {
- const d3d9_format_t *format = &d3d_formats[j];
-
- if (format->fourcc != list[i])
- continue;
-
- msg_Warn(vd, "trying surface pixel format: %s",
- format->name);
- if (!Direct3D9CheckConversion(vd, format->format, target)) {
- msg_Dbg(vd, "selected surface pixel format is %s",
- format->name);
- return format;
- }
- }
- }
- }
- return NULL;
-}
-
-/**
* It allocates and initializes the resources needed to render the scene.
*/
static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt)
@@ -1139,33 +692,6 @@ static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt)
return VLC_SUCCESS;
}
-/**
- * It releases the scene resources.
- */
-static void Direct3D9DestroyScene(vout_display_t *vd)
-{
- vout_display_sys_t *sys = vd->sys;
-
- Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
-
- if (sys->sceneVertexBuffer)
- {
- IDirect3DVertexBuffer9_Release(sys->sceneVertexBuffer);
- sys->sceneVertexBuffer = NULL;
- }
-
- if (sys->sceneTexture)
- {
- IDirect3DTexture9_Release(sys->sceneTexture);
- sys->sceneTexture = NULL;
- }
-
- sys->d3dregion_count = 0;
- sys->d3dregion = NULL;
-
- msg_Dbg(vd, "Direct3D9 scene released successfully");
-}
-
#ifdef HAVE_D3DX9EFFECT_H
static int Direct3D9CompileShader(vout_display_t *vd, const char *shader_source, size_t source_length)
{
@@ -1301,210 +827,134 @@ error:
return VLC_EGENERIC;
}
-static void Direct3D9DestroyShaders(vout_display_t *vd)
-{
- vout_display_sys_t *sys = vd->sys;
-
- if (sys->d3dx_shader)
- IDirect3DPixelShader9_Release(sys->d3dx_shader);
- sys->d3dx_shader = NULL;
-}
-
/**
- * Compute the vertex ordering needed to rotate the video. Without
- * rotation, the vertices of the rectangle are defined in a clockwise
- * order. This function computes a remapping of the coordinates to
- * implement the rotation, given fixed texture coordinates.
- * The unrotated order is the following:
- * 0--1
- * | |
- * 3--2
- * For a 180 degrees rotation it should like this:
- * 2--3
- * | |
- * 1--0
- * Vertex 0 should be assigned coordinates at index 2 from the
- * unrotated order and so on, thus yielding order: 2 3 0 1.
+ * It creates the picture and scene resources.
*/
-static void orientationVertexOrder(video_orientation_t orientation, int vertex_order[static 4])
-{
- switch (orientation) {
- case ORIENT_ROTATED_90: /* ORIENT_RIGHT_TOP */
- vertex_order[0] = 1;
- vertex_order[1] = 2;
- vertex_order[2] = 3;
- vertex_order[3] = 0;
- break;
- case ORIENT_ROTATED_270: /* ORIENT_LEFT_BOTTOM */
- vertex_order[0] = 3;
- vertex_order[1] = 0;
- vertex_order[2] = 1;
- vertex_order[3] = 2;
- break;
- case ORIENT_ROTATED_180: /* ORIENT_BOTTOM_RIGHT */
- vertex_order[0] = 2;
- vertex_order[1] = 3;
- vertex_order[2] = 0;
- vertex_order[3] = 1;
- break;
- case ORIENT_TRANSPOSED: /* ORIENT_LEFT_TOP */
- vertex_order[0] = 0;
- vertex_order[1] = 3;
- vertex_order[2] = 2;
- vertex_order[3] = 1;
- break;
- case ORIENT_HFLIPPED: /* ORIENT_TOP_RIGHT */
- vertex_order[0] = 1;
- vertex_order[1] = 0;
- vertex_order[2] = 3;
- vertex_order[3] = 2;
- break;
- case ORIENT_VFLIPPED: /* ORIENT_BOTTOM_LEFT */
- vertex_order[0] = 3;
- vertex_order[1] = 2;
- vertex_order[2] = 1;
- vertex_order[3] = 0;
- break;
- case ORIENT_ANTI_TRANSPOSED: /* ORIENT_RIGHT_BOTTOM */
- vertex_order[0] = 2;
- vertex_order[1] = 1;
- vertex_order[2] = 0;
- vertex_order[3] = 3;
- break;
- default:
- vertex_order[0] = 0;
- vertex_order[1] = 1;
- vertex_order[2] = 2;
- vertex_order[3] = 3;
- break;
- }
-}
-
-static void Direct3D9SetupVertices(CUSTOMVERTEX *vertices,
- const RECT *src, const RECT *src_clipped,
- const RECT *dst,
- int alpha,
- video_orientation_t orientation)
+static int Direct3D9CreateResources(vout_display_t *vd, video_format_t *fmt)
{
- /* Vertices of the dst rectangle in the unrotated (clockwise) order. */
- const int vertices_coords[4][2] = {
- { dst->left, dst->top },
- { dst->right, dst->top },
- { dst->right, dst->bottom },
- { dst->left, dst->bottom },
- };
-
- /* Compute index remapping necessary to implement the rotation. */
- int vertex_order[4];
- orientationVertexOrder(orientation, vertex_order);
+ vout_display_sys_t *sys = vd->sys;
- for (int i = 0; i < 4; ++i) {
- vertices[i].x = vertices_coords[vertex_order[i]][0];
- vertices[i].y = vertices_coords[vertex_order[i]][1];
+ if (Direct3D9CreateScene(vd, fmt)) {
+ msg_Err(vd, "Direct3D scene initialization failed !");
+ return VLC_EGENERIC;
+ }
+ if (Direct3D9CreateShaders(vd)) {
+ /* Failing to initialize shaders is not fatal. */
+ msg_Warn(vd, "Direct3D shaders initialization failed !");
}
- float right = (float)src_clipped->right / (float)src->right;
- float left = (float)src_clipped->left / (float)src->right;
- float top = (float)src_clipped->top / (float)src->bottom;
- float bottom = (float)src_clipped->bottom / (float)src->bottom;
-
- vertices[0].tu = left;
- vertices[0].tv = top;
-
- vertices[1].tu = right;
- vertices[1].tv = top;
-
- vertices[2].tu = right;
- vertices[2].tv = bottom;
-
- vertices[3].tu = left;
- vertices[3].tv = bottom;
-
- for (int i = 0; i < 4; i++) {
- /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */
- /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */
- vertices[i].x -= 0.5;
- vertices[i].y -= 0.5;
-
- vertices[i].z = 0.0f;
- vertices[i].rhw = 1.0f;
- vertices[i].diffuse = D3DCOLOR_ARGB(alpha, 255, 255, 255);
+ sys->d3dregion_format = D3DFMT_UNKNOWN;
+ for (int i = 0; i < 2; i++) {
+ D3DFORMAT dfmt = i == 0 ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8;
+ if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(sys->hd3d.obj,
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ sys->d3d_dev.pp.BackBufferFormat,
+ D3DUSAGE_DYNAMIC,
+ D3DRTYPE_TEXTURE,
+ dfmt))) {
+ sys->d3dregion_format = dfmt;
+ break;
+ }
}
+ return VLC_SUCCESS;
}
/**
- * It copies picture surface into a texture and setup the associated d3d_region_t.
+ * It reset the Direct3D9 device and its resources.
*/
-static int Direct3D9ImportPicture(vout_display_t *vd,
- d3d_region_t *region,
- IDirect3DSurface9 *source)
+static int Direct3D9Reset(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
- HRESULT hr;
+ d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
- if (!source) {
- msg_Dbg(vd, "no surface to render?");
+ if (D3D9_FillPresentationParameters(&sys->hd3d, &vd->source, p_d3d9_dev))
+ {
+ msg_Err(vd, "Could not presentation parameters to reset device");
return VLC_EGENERIC;
}
- /* retrieve texture top-level surface */
- IDirect3DSurface9 *destination;
- hr = IDirect3DTexture9_GetSurfaceLevel(sys->sceneTexture, 0, &destination);
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed IDirect3DTexture9_GetSurfaceLevel: 0x%0lx", hr);
- return VLC_EGENERIC;
- }
+ /* release all D3D objects */
+ Direct3D9DestroyResources(vd);
- /* Copy picture surface into texture surface
- * color space conversion happen here */
- RECT copy_rect = sys->sys.rect_src_clipped;
- // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
- // When copying the entire buffer, the margin end up being blended in the actual picture
- // on nVidia (regardless of even/odd dimensions)
- if ( copy_rect.right & 1 ) copy_rect.right++;
- if ( copy_rect.left & 1 ) copy_rect.left--;
- if ( copy_rect.bottom & 1 ) copy_rect.bottom++;
- if ( copy_rect.top & 1 ) copy_rect.top--;
- hr = IDirect3DDevice9_StretchRect(sys->d3d_dev.dev, source, ©_rect, destination,
- ©_rect, D3DTEXF_NONE);
- IDirect3DSurface9_Release(destination);
+ /* */
+ HRESULT hr;
+ if (sys->hd3d.use_ex){
+ hr = IDirect3DDevice9Ex_ResetEx(p_d3d9_dev->devex, &p_d3d9_dev->pp, NULL);
+ } else {
+ hr = IDirect3DDevice9_Reset(p_d3d9_dev->dev, &p_d3d9_dev->pp);
+ }
if (FAILED(hr)) {
- msg_Dbg(vd, "Failed StretchRect: source 0x%p 0x%0lx",
- (LPVOID)source, hr);
+ msg_Err(vd, "IDirect3DDevice9_Reset failed! (hr=0x%0lx)", hr);
return VLC_EGENERIC;
}
- /* */
- region->texture = sys->sceneTexture;
- Direct3D9SetupVertices(region->vertex, &vd->sys->sys.rect_src, &vd->sys->sys.rect_src_clipped,
- &vd->sys->sys.rect_dest_clipped, 255, vd->fmt.orientation);
- return VLC_SUCCESS;
-}
+ UpdateRects(vd, NULL, true);
-static void Direct3D9DeleteRegions(size_t count, d3d_region_t *region)
-{
- for (size_t i = 0; i < count; i++) {
- if (region[i].texture)
- IDirect3DTexture9_Release(region[i].texture);
+ /* re-create them */
+ if (Direct3D9CreateResources(vd, &vd->fmt)) {
+ msg_Dbg(vd, "Direct3D9CreateResources failed !");
+ return VLC_EGENERIC;
}
- free(region);
+ return VLC_SUCCESS;
}
-static void Direct3D9ImportSubpicture(vout_display_t *vd,
- size_t *count_ptr, d3d_region_t **region,
- subpicture_t *subpicture)
+static void Manage (vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
- size_t count = 0;
- for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
- count++;
+ CommonManage(vd);
- *count_ptr = count;
- *region = calloc(count, sizeof(**region));
- if (*region == NULL) {
- *count_ptr = 0;
- return;
+ /* Desktop mode change */
+ vlc_mutex_lock(&sys->lock);
+ const bool ch_desktop = sys->ch_desktop;
+ sys->ch_desktop = false;
+ vlc_mutex_unlock(&sys->lock);
+
+ if (ch_desktop) {
+ sys->reopen_device = true;
+ if (vd->info.has_pictures_invalid)
+ vout_display_SendEventPicturesInvalid(vd);
+ }
+
+ /* Position Change */
+ if (sys->sys.changes & DX_POSITION_CHANGE) {
+#if 0 /* need that when bicubic filter is available */
+ RECT rect;
+ UINT width, height;
+
+ GetClientRect(p_sys->sys.hvideownd, &rect);
+ width = rect.right-rect.left;
+ height = rect.bottom-rect.top;
+
+ if (width != p_sys->pp.BackBufferWidth || height != p_sys->pp.BackBufferHeight)
+ {
+ msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height);
+ // need to reset D3D device to resize back buffer
+ if (VLC_SUCCESS != Direct3D9ResetDevice(vd, width, height))
+ return VLC_EGENERIC;
+ }
+#endif
+ sys->clear_scene = true;
+ sys->sys.changes &= ~DX_POSITION_CHANGE;
+ }
+}
+
+static void Direct3D9ImportSubpicture(vout_display_t *vd,
+ size_t *count_ptr, d3d_region_t **region,
+ subpicture_t *subpicture)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ size_t count = 0;
+ for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
+ count++;
+
+ *count_ptr = count;
+ *region = calloc(count, sizeof(**region));
+ if (*region == NULL) {
+ *count_ptr = 0;
+ return;
}
int i = 0;
@@ -1664,80 +1114,464 @@ static int Direct3D9RenderRegion(vout_display_t *vd,
}
}
- // Render the vertex buffer contents
- hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, sys->sceneVertexBuffer, 0, sizeof(CUSTOMVERTEX));
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed SetStreamSource: 0x%0lx", hr);
- return -1;
+ // Render the vertex buffer contents
+ hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, sys->sceneVertexBuffer, 0, sizeof(CUSTOMVERTEX));
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed SetStreamSource: 0x%0lx", hr);
+ return -1;
+ }
+
+ // we use FVF instead of vertex shader
+ hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed SetFVF: 0x%0lx", hr);
+ return -1;
+ }
+
+ // draw rectangle
+ hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed DrawPrimitive: 0x%0lx", hr);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * It renders the scene.
+ *
+ * This function is intented for higher end 3D cards, with pixel shader support
+ * and at least 64 MiB of video RAM.
+ */
+static void Direct3D9RenderScene(vout_display_t *vd,
+ d3d_region_t *picture,
+ size_t subpicture_count,
+ d3d_region_t *subpicture)
+{
+ vout_display_sys_t *sys = vd->sys;
+ IDirect3DDevice9 *d3ddev = sys->d3d_dev.dev;
+ HRESULT hr;
+
+ if (sys->clear_scene) {
+ /* Clear the backbuffer and the zbuffer */
+ hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET,
+ D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed Clear: 0x%0lx", hr);
+ return;
+ }
+ sys->clear_scene = false;
+ }
+
+ // Begin the scene
+ hr = IDirect3DDevice9_BeginScene(d3ddev);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed BeginScene: 0x%0lx", hr);
+ return;
+ }
+
+ Direct3D9RenderRegion(vd, picture, true);
+
+ if (subpicture_count)
+ {
+ IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
+ for (size_t i = 0; i < subpicture_count; i++) {
+ d3d_region_t *r = &subpicture[i];
+ if (r->texture)
+ Direct3D9RenderRegion(vd, r, false);
+ }
+ IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
+ }
+
+ // End the scene
+ hr = IDirect3DDevice9_EndScene(d3ddev);
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed EndScene: 0x%0lx", hr);
+ return;
+ }
+}
+
+static void Prepare(vout_display_t *vd, picture_t *picture,
+ subpicture_t *subpicture, vlc_tick_t date)
+{
+ Manage(vd);
+ VLC_UNUSED(date);
+ vout_display_sys_t *sys = vd->sys;
+ picture_sys_t *p_sys = picture->p_sys;
+ IDirect3DSurface9 *surface = p_sys->surface;
+ d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+
+ /* FIXME it is a bit ugly, we need the surface to be unlocked for
+ * rendering.
+ * The clean way would be to release the picture (and ensure that
+ * the vout doesn't keep a reference). But because of the vout
+ * wrapper, we can't */
+ if ( !is_d3d9_opaque(picture->format.i_chroma) )
+ Direct3D9UnlockSurface(picture);
+ else if (picture->context)
+ {
+ const struct va_pic_context *pic_ctx = (struct va_pic_context*)picture->context;
+ if (pic_ctx->picsys.surface != surface)
+ {
+ D3DSURFACE_DESC srcDesc, dstDesc;
+ IDirect3DSurface9_GetDesc(pic_ctx->picsys.surface, &srcDesc);
+ IDirect3DSurface9_GetDesc(surface, &dstDesc);
+ if ( srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height )
+ surface = pic_ctx->picsys.surface;
+ else
+ {
+ HRESULT hr;
+ RECT visibleSource;
+ visibleSource.left = 0;
+ visibleSource.top = 0;
+ visibleSource.right = picture->format.i_visible_width;
+ visibleSource.bottom = picture->format.i_visible_height;
+
+ hr = IDirect3DDevice9_StretchRect( p_d3d9_dev->dev, pic_ctx->picsys.surface, &visibleSource, surface, &visibleSource, D3DTEXF_NONE);
+ if (FAILED(hr)) {
+ msg_Err(vd, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
+ }
+ }
+ }
+ }
+
+ /* check if device is still available */
+ HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(p_d3d9_dev->dev);
+ if (FAILED(hr)) {
+ if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) {
+ if (vd->info.has_pictures_invalid)
+ vout_display_SendEventPicturesInvalid(vd);
+ sys->reset_device = true;
+ sys->lost_not_ready = false;
+ }
+ if (hr == D3DERR_DEVICELOST && !sys->lost_not_ready) {
+ /* Device is lost but not yet ready for reset. */
+ sys->lost_not_ready = true;
+ }
+ return;
+ }
+
+ d3d_region_t picture_region;
+ if (!Direct3D9ImportPicture(vd, &picture_region, surface)) {
+ picture_region.width = picture->format.i_visible_width;
+ picture_region.height = picture->format.i_visible_height;
+ size_t subpicture_region_count = 0;
+ d3d_region_t *subpicture_region = NULL;
+ if (subpicture)
+ Direct3D9ImportSubpicture(vd, &subpicture_region_count, &subpicture_region,
+ subpicture);
+
+ Direct3D9RenderScene(vd, &picture_region,
+ subpicture_region_count, subpicture_region);
+
+ Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
+ sys->d3dregion_count = subpicture_region_count;
+ sys->d3dregion = subpicture_region;
+ }
+}
+
+static void Display(vout_display_t *vd, picture_t *picture)
+{
+ vout_display_sys_t *sys = vd->sys;
+ const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+
+ if (sys->lost_not_ready)
+ return;
+
+ // Present the back buffer contents to the display
+ // No stretching should happen here !
+ const RECT src = sys->sys.rect_dest_clipped;
+ const RECT dst = sys->sys.rect_dest_clipped;
+
+ HRESULT hr;
+ if (sys->hd3d.use_ex) {
+ hr = IDirect3DDevice9Ex_PresentEx(p_d3d9_dev->devex, &src, &dst, NULL, NULL, 0);
+ } else {
+ hr = IDirect3DDevice9_Present(p_d3d9_dev->dev, &src, &dst, NULL, NULL);
+ }
+ if (FAILED(hr)) {
+ msg_Dbg(vd, "Failed Present: 0x%0lx", hr);
+ }
+
+ /* XXX See Prepare() */
+ if ( !is_d3d9_opaque(picture->format.i_chroma) )
+ Direct3D9LockSurface(picture);
+
+ CommonDisplay(vd);
+}
+
+/**
+ * It releases an instance of Direct3D9
+ */
+static void Direct3D9Destroy(vout_display_sys_t *sys)
+{
+ D3D9_Destroy( &sys->hd3d );
+
+ if (sys->hxdll)
+ {
+ FreeLibrary(sys->hxdll);
+ sys->hxdll = NULL;
+ }
+}
+
+/**
+ * It tests if the conversion from src to dst is supported.
+ */
+static int Direct3D9CheckConversion(vout_display_t *vd,
+ D3DFORMAT src, D3DFORMAT dst)
+{
+ vout_display_sys_t *sys = vd->sys;
+ IDirect3D9 *d3dobj = sys->hd3d.obj;
+ HRESULT hr;
+
+ /* test whether device can create a surface of that format */
+ hr = IDirect3D9_CheckDeviceFormat(d3dobj, D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL, dst, 0,
+ D3DRTYPE_SURFACE, src);
+ if (SUCCEEDED(hr)) {
+ /* test whether device can perform color-conversion
+ ** from that format to target format
+ */
+ hr = IDirect3D9_CheckDeviceFormatConversion(d3dobj,
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ src, dst);
+ }
+ if (!SUCCEEDED(hr)) {
+ if (D3DERR_NOTAVAILABLE != hr)
+ msg_Err(vd, "Could not query adapter supported formats. (hr=0x%0lx)", hr);
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
+}
+
+static const d3d9_format_t d3d_formats[] = {
+ /* YV12 is always used for planar 420, the planes are then swapped in Lock() */
+ { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_YV12, 0,0,0 },
+ { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_I420, 0,0,0 },
+ { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_J420, 0,0,0 },
+ { "NV12", MAKEFOURCC('N','V','1','2'), VLC_CODEC_NV12, 0,0,0 },
+ { "DXA9", MAKEFOURCC('N','V','1','2'), VLC_CODEC_D3D9_OPAQUE, 0,0,0 },
+ { "DXA9_10", MAKEFOURCC('P','0','1','0'), VLC_CODEC_D3D9_OPAQUE_10B, 0,0,0 },
+ { "UYVY", D3DFMT_UYVY, VLC_CODEC_UYVY, 0,0,0 },
+ { "YUY2", D3DFMT_YUY2, VLC_CODEC_YUYV, 0,0,0 },
+ { "X8R8G8B8", D3DFMT_X8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
+ { "A8R8G8B8", D3DFMT_A8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
+ { "8G8B8", D3DFMT_R8G8B8, VLC_CODEC_RGB24, 0xff0000, 0x00ff00, 0x0000ff },
+ { "R5G6B5", D3DFMT_R5G6B5, VLC_CODEC_RGB16, 0x1f<<11, 0x3f<<5, 0x1f<<0 },
+ { "X1R5G5B5", D3DFMT_X1R5G5B5,VLC_CODEC_RGB15, 0x1f<<10, 0x1f<<5, 0x1f<<0 },
+
+ { NULL, 0, 0, 0,0,0}
+};
+
+/**
+ * It returns the format (closest to chroma) that can be converted to target */
+static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
+{
+ vout_display_sys_t *sys = vd->sys;
+ bool hardware_scale_ok = !(vd->fmt.i_visible_width & 1) && !(vd->fmt.i_visible_height & 1);
+ if( !hardware_scale_ok )
+ msg_Warn( vd, "Disabling hardware chroma conversion due to odd dimensions" );
+
+ for (unsigned pass = 0; pass < 2; pass++) {
+ const vlc_fourcc_t *list;
+ const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
+
+ if (pass == 0 && is_d3d9_opaque(chroma))
+ list = dxva_chroma;
+ else if (pass == 0 && hardware_scale_ok && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
+ list = vlc_fourcc_GetYUVFallback(chroma);
+ else if (pass == 1)
+ list = vlc_fourcc_GetRGBFallback(chroma);
+ else
+ continue;
+
+ for (unsigned i = 0; list[i] != 0; i++) {
+ for (unsigned j = 0; d3d_formats[j].name; j++) {
+ const d3d9_format_t *format = &d3d_formats[j];
+
+ if (format->fourcc != list[i])
+ continue;
+
+ msg_Warn(vd, "trying surface pixel format: %s",
+ format->name);
+ if (!Direct3D9CheckConversion(vd, format->format, target)) {
+ msg_Dbg(vd, "selected surface pixel format is %s",
+ format->name);
+ return format;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * It creates a Direct3D9 device and the associated resources.
+ */
+static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ HRESULT hr = D3D9_CreateDevice(vd, &sys->hd3d, sys->sys.hvideownd,
+ &vd->source, &sys->d3d_dev);
+
+ if (FAILED(hr)) {
+ msg_Err( vd, "D3D9 Creation failed! (hr=0x%0lx)", hr);
+ return VLC_EGENERIC;
+ }
+
+ const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+ /* */
+ RECT *display = &vd->sys->sys.rect_display;
+ display->left = 0;
+ display->top = 0;
+ display->right = p_d3d9_dev->pp.BackBufferWidth;
+ display->bottom = p_d3d9_dev->pp.BackBufferHeight;
+
+ *fmt = vd->source;
+
+ /* Find the appropriate D3DFORMAT for the render chroma, the format will be the closest to
+ * the requested chroma which is usable by the hardware in an offscreen surface, as they
+ * typically support more formats than textures */
+ const d3d9_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, p_d3d9_dev->pp.BackBufferFormat);
+ if (!d3dfmt) {
+ msg_Err(vd, "surface pixel format is not supported.");
+ goto error;
+ }
+ fmt->i_chroma = d3dfmt->fourcc;
+ fmt->i_rmask = d3dfmt->rmask;
+ fmt->i_gmask = d3dfmt->gmask;
+ fmt->i_bmask = d3dfmt->bmask;
+ sys->d3dtexture_format = d3dfmt;
+
+ UpdateRects(vd, NULL, true);
+
+ if (Direct3D9CreateResources(vd, fmt)) {
+ msg_Err(vd, "Failed to allocate resources");
+ goto error;
+ }
+
+ /* Change the window title bar text */
+ if (!sys->sys.b_windowless)
+ EventThreadUpdateTitle(sys->sys.event, VOUT_TITLE " (Direct3D9 output)");
+
+ msg_Dbg(vd, "Direct3D9 device adapter successfully initialized");
+ return VLC_SUCCESS;
+
+error:
+ D3D9_ReleaseDevice(&sys->d3d_dev);
+ return VLC_EGENERIC;
+}
+
+/**
+ * It releases the Direct3D9 device and its resources.
+ */
+static void Direct3D9Close(vout_display_t *vd)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ Direct3D9DestroyResources(vd);
+ D3D9_ReleaseDevice(&sys->d3d_dev);
+}
+
+static int ControlReopenDevice(vout_display_t *vd)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ if (!sys->sys.use_desktop) {
+ /* Save non-desktop state */
+ sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
+ sys->desktop_save.is_on_top = sys->sys.is_on_top;
+
+ WINDOWPLACEMENT wp = { .length = sizeof(wp), };
+ GetWindowPlacement(sys->sys.hparent ? sys->sys.hparent : sys->sys.hwnd, &wp);
+ sys->desktop_save.win = wp.rcNormalPosition;
+ }
+
+ /* */
+ Direct3D9Close(vd);
+ if (!sys->sys.b_windowless)
+ EventThreadStop(sys->sys.event);
+
+ /* */
+ vlc_mutex_lock(&sys->lock);
+ sys->sys.use_desktop = sys->desktop_requested;
+ sys->ch_desktop = false;
+ vlc_mutex_unlock(&sys->lock);
+
+ /* */
+ event_cfg_t cfg;
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.use_desktop = sys->sys.use_desktop;
+ if (!sys->sys.use_desktop) {
+ cfg.x = sys->desktop_save.win.left;
+ cfg.y = sys->desktop_save.win.top;
+ cfg.width = sys->desktop_save.win.right - sys->desktop_save.win.left;
+ cfg.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top;
+ }
+
+ event_hwnd_t hwnd;
+ if (!sys->sys.b_windowless && EventThreadStart(sys->sys.event, &hwnd, &cfg)) {
+ msg_Err(vd, "Failed to restart event thread");
+ return VLC_EGENERIC;
}
+ sys->sys.parent_window = hwnd.parent_window;
+ sys->sys.hparent = hwnd.hparent;
+ sys->sys.hwnd = hwnd.hwnd;
+ sys->sys.hvideownd = hwnd.hvideownd;
+ sys->sys.hfswnd = hwnd.hfswnd;
+ SetRectEmpty(&sys->sys.rect_parent);
- // we use FVF instead of vertex shader
- hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed SetFVF: 0x%0lx", hr);
- return -1;
+ /* */
+ video_format_t fmt;
+ if (Direct3D9Open(vd, &fmt)) {
+ CommonClean(vd);
+ msg_Err(vd, "Failed to reopen device");
+ return VLC_EGENERIC;
}
+ vd->fmt = fmt;
+ sys->sys.is_first_display = true;
- // draw rectangle
- hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed DrawPrimitive: 0x%0lx", hr);
- return -1;
+ if (sys->sys.use_desktop) {
+ /* Disable fullscreen/on_top while using desktop */
+ if (sys->desktop_save.is_fullscreen)
+ vout_display_SendEventFullscreen(vd, false);
+ if (sys->desktop_save.is_on_top)
+ vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_NORMAL);
+ } else {
+ /* Restore fullscreen/on_top */
+ if (sys->desktop_save.is_fullscreen)
+ vout_display_SendEventFullscreen(vd, true);
+ if (sys->desktop_save.is_on_top)
+ vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_ABOVE);
}
- return 0;
+ return VLC_SUCCESS;
}
-/**
- * It renders the scene.
- *
- * This function is intented for higher end 3D cards, with pixel shader support
- * and at least 64 MiB of video RAM.
- */
-static void Direct3D9RenderScene(vout_display_t *vd,
- d3d_region_t *picture,
- size_t subpicture_count,
- d3d_region_t *subpicture)
+static int Control(vout_display_t *vd, int query, va_list args)
{
vout_display_sys_t *sys = vd->sys;
- IDirect3DDevice9 *d3ddev = sys->d3d_dev.dev;
- HRESULT hr;
-
- if (sys->clear_scene) {
- /* Clear the backbuffer and the zbuffer */
- hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET,
- D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed Clear: 0x%0lx", hr);
- return;
- }
- sys->clear_scene = false;
- }
-
- // Begin the scene
- hr = IDirect3DDevice9_BeginScene(d3ddev);
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed BeginScene: 0x%0lx", hr);
- return;
- }
-
- Direct3D9RenderRegion(vd, picture, true);
- if (subpicture_count)
- {
- IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
- for (size_t i = 0; i < subpicture_count; i++) {
- d3d_region_t *r = &subpicture[i];
- if (r->texture)
- Direct3D9RenderRegion(vd, r, false);
+ switch (query) {
+ case VOUT_DISPLAY_RESET_PICTURES:
+ /* FIXME what to do here in case of failure */
+ if (sys->reset_device) {
+ if (Direct3D9Reset(vd)) {
+ msg_Err(vd, "Failed to reset device");
+ return VLC_EGENERIC;
+ }
+ sys->reset_device = false;
+ } else if(sys->reopen_device) {
+ if (ControlReopenDevice(vd)) {
+ msg_Err(vd, "Failed to reopen device");
+ return VLC_EGENERIC;
+ }
+ sys->reopen_device = false;
}
- IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
- }
-
- // End the scene
- hr = IDirect3DDevice9_EndScene(d3ddev);
- if (FAILED(hr)) {
- msg_Dbg(vd, "Failed EndScene: 0x%0lx", hr);
- return;
+ return VLC_SUCCESS;
+ default:
+ return CommonControl(vd, query, args);
}
}
@@ -1799,6 +1633,136 @@ static int FindShadersCallback(const char *name, char ***values, char ***descs)
}
+/**
+ * It creates a Direct3D vout display.
+ */
+static int Open(vlc_object_t *object)
+{
+ vout_display_t *vd = (vout_display_t *)object;
+ vout_display_sys_t *sys;
+
+ if ( !vd->obj.force && vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR)
+ return VLC_EGENERIC; /* let a module who can handle it do it */
+
+ if ( !vd->obj.force && vd->source.mastering.max_luminance != 0)
+ return VLC_EGENERIC; /* let a module who can handle it do it */
+
+#if !VLC_WINSTORE_APP
+ /* do not use D3D9 on XP unless forced */
+ if (!vd->obj.force)
+ {
+ bool isVistaOrGreater = false;
+ HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (likely(hKernel32 != NULL))
+ isVistaOrGreater = GetProcAddress(hKernel32, "EnumResourceLanguagesExW") != NULL;
+ if (!isVistaOrGreater)
+ return VLC_EGENERIC;
+ }
+#endif
+
+ /* Allocate structure */
+ vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
+ if (!sys)
+ return VLC_ENOMEM;
+
+ if (D3D9_Create(vd, &sys->hd3d)) {
+ msg_Err(vd, "Direct3D9 could not be initialized");
+ free(sys);
+ return VLC_EGENERIC;
+ }
+
+ sys->hxdll = Direct3D9LoadShaderLibrary();
+ if (!sys->hxdll)
+ msg_Warn(object, "cannot load Direct3D9 Shader Library; HLSL pixel shading will be disabled.");
+
+ sys->sys.use_desktop = var_CreateGetBool(vd, "video-wallpaper");
+ sys->reset_device = false;
+ sys->reopen_device = false;
+ sys->lost_not_ready = false;
+ sys->allow_hw_yuv = var_CreateGetBool(vd, "directx-hw-yuv");
+ sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
+ sys->desktop_save.is_on_top = false;
+ sys->desktop_save.win.left = var_InheritInteger(vd, "video-x");
+ sys->desktop_save.win.right = vd->cfg->display.width;
+ sys->desktop_save.win.top = var_InheritInteger(vd, "video-y");
+ sys->desktop_save.win.bottom = vd->cfg->display.height;
+
+ if (CommonInit(vd, false))
+ goto error;
+
+ /* */
+ video_format_t fmt;
+ if (Direct3D9Open(vd, &fmt)) {
+ msg_Err(vd, "Direct3D9 could not be opened");
+ goto error;
+ }
+
+ /* */
+ vout_display_info_t info = vd->info;
+ info.is_slow = !is_d3d9_opaque(fmt.i_chroma);
+ info.has_double_click = true;
+ info.has_pictures_invalid = !is_d3d9_opaque(fmt.i_chroma);
+ if (var_InheritBool(vd, "direct3d9-hw-blending") &&
+ sys->d3dregion_format != D3DFMT_UNKNOWN &&
+ (sys->d3d_dev.caps.SrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) &&
+ (sys->d3d_dev.caps.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) &&
+ (sys->d3d_dev.caps.TextureCaps & D3DPTEXTURECAPS_ALPHA) &&
+ (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1) &&
+ (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE))
+ info.subpicture_chromas = d3d_subpicture_chromas;
+ else
+ info.subpicture_chromas = NULL;
+
+ /* Interaction */
+ vlc_mutex_init(&sys->lock);
+ sys->ch_desktop = false;
+ sys->desktop_requested = sys->sys.use_desktop;
+
+ var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, _("Desktop"));
+ var_AddCallback(vd, "video-wallpaper", DesktopCallback, NULL);
+
+ /* Setup vout_display now that everything is fine */
+ video_format_Clean(&vd->fmt);
+ video_format_Copy(&vd->fmt, &fmt);
+ vd->info = info;
+
+ vd->pool = DisplayPool;
+ vd->prepare = Prepare;
+ vd->display = Display;
+ vd->control = Control;
+
+ /* Fix state in case of desktop mode */
+ if (sys->sys.use_desktop && vd->cfg->is_fullscreen)
+ vout_display_SendEventFullscreen(vd, false);
+
+ return VLC_SUCCESS;
+error:
+ Direct3D9Close(vd);
+ CommonClean(vd);
+ Direct3D9Destroy(sys);
+ free(vd->sys);
+ return VLC_EGENERIC;
+}
+
+/**
+ * It destroyes a Direct3D vout display.
+ */
+static void Close(vlc_object_t *object)
+{
+ vout_display_t * vd = (vout_display_t *)object;
+
+ var_DelCallback(vd, "video-wallpaper", DesktopCallback, NULL);
+ vlc_mutex_destroy(&vd->sys->lock);
+
+ Direct3D9Close(vd);
+
+ CommonClean(vd);
+
+ Direct3D9Destroy(vd->sys);
+
+ free(vd->sys);
+}
+
#ifdef HAVE_GL
#include "../opengl/converter.h"
#include <GL/wglew.h>
More information about the vlc-commits
mailing list