From fc67be9a013e36c170c545ef66ff9f772df23a73 Mon Sep 17 00:00:00 2001 From: Lionel Ulmer Date: Tue, 26 Sep 2000 00:38:03 +0000 Subject: [PATCH] Added support for DirectDraw overlays using the XVideo extension. --- dlls/ddraw/ddraw/x11.c | 258 +++++++++++++++++++++++++++++++++---- dlls/ddraw/ddraw_private.h | 1 + dlls/ddraw/dsurface/x11.c | 220 +++++++++++++++++++++++++++---- dlls/ddraw/helper.c | 45 ++++++- dlls/ddraw/x11.c | 65 ++++++++++ dlls/ddraw/x11_private.h | 24 +++- include/ddraw.h | 25 ++++ wine.ini | 3 + 8 files changed, 587 insertions(+), 54 deletions(-) diff --git a/dlls/ddraw/ddraw/x11.c b/dlls/ddraw/ddraw/x11.c index 5eb11a35698..f2ac8cbeb42 100644 --- a/dlls/ddraw/ddraw/x11.c +++ b/dlls/ddraw/ddraw/x11.c @@ -267,7 +267,7 @@ static XImage *create_ximage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lp void *img_data; int bpp = PFGET_BPP(This->d->directdraw_pixelformat); int screen_bpp = PFGET_BPP(This->d->screen_pixelformat); - + #ifdef HAVE_LIBXXSHM if (ddpriv->xshm_active) img = create_xshmimage(This, lpdsf); @@ -318,6 +318,164 @@ static XImage *create_ximage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lp return img; } +#ifdef HAVE_XVIDEO +#ifdef HAVE_LIBXXSHM +static XvImage *create_xvshmimage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf) { + DSPRIVATE(lpdsf); + DDPRIVATE(This); + XvImage *img; + int (*WineXHandler)(Display *, XErrorEvent *); + + img = TSXvShmCreateImage(display, + ddpriv->port_id, + (int) lpdsf->s.surface_desc.ddpfPixelFormat.dwFourCC, + NULL, + lpdsf->s.surface_desc.dwWidth, + lpdsf->s.surface_desc.dwHeight, + &(dspriv->shminfo)); + + if (img == NULL) { + FIXME("Couldn't create XShm XvImage (due to X11 remote display or failure).\nReverting to standard X images !\n"); + ddpriv->xshm_active = 0; + return NULL; + } + + dspriv->shminfo.shmid = shmget( IPC_PRIVATE, img->data_size, IPC_CREAT|0777 ); + + if (dspriv->shminfo.shmid < 0) { + FIXME("Couldn't create shared memory segment (due to X11 remote display or failure).\nReverting to standard X images !\n"); + ddpriv->xshm_active = 0; + TSXFree(img); + return NULL; + } + + dspriv->shminfo.shmaddr=img->data=(char*)shmat(dspriv->shminfo.shmid,0,0); + + if (img->data == (char *) -1) { + FIXME("Couldn't attach shared memory segment (due to X11 remote display or failure).\nReverting to standard X images !\n"); + ddpriv->xshm_active = 0; + TSXFree(img); + shmctl(dspriv->shminfo.shmid, IPC_RMID, 0); + return NULL; + } + dspriv->shminfo.readOnly = False; + + /* This is where things start to get trickier.... + * First, we flush the current X connections to be sure to catch all + * non-XShm related errors + */ + TSXSync(display, False); + /* Then we enter in the non-thread safe part of the tests */ + EnterCriticalSection( &X11DRV_CritSection ); + + /* Reset the error flag, sets our new error handler and try to attach + * the surface + */ + XShmErrorFlag = 0; + WineXHandler = XSetErrorHandler(XShmErrorHandler); + XShmAttach(display, &(dspriv->shminfo)); + XSync(display, False); + + /* Check the error flag */ + if (XShmErrorFlag) { + /* An error occured */ + XFlush(display); + XShmErrorFlag = 0; + XFree(img); + shmdt(dspriv->shminfo.shmaddr); + shmctl(dspriv->shminfo.shmid, IPC_RMID, 0); + XSetErrorHandler(WineXHandler); + + FIXME("Couldn't attach shared memory segment to X server (due to X11 remote display or failure).\nReverting to standard X images !\n"); + ddpriv->xshm_active = 0; + + /* Leave the critical section */ + LeaveCriticalSection( &X11DRV_CritSection ); + return NULL; + } + /* Here, to be REALLY sure, I should do a XShmPutImage to check if + * this works, but it may be a bit overkill.... + */ + XSetErrorHandler(WineXHandler); + LeaveCriticalSection( &X11DRV_CritSection ); + + shmctl(dspriv->shminfo.shmid, IPC_RMID, 0); + + lpdsf->s.surface_desc.u1.lpSurface = img->data; + VirtualAlloc(img->data, img->data_size, MEM_RESERVE|MEM_SYSTEM, PAGE_READWRITE); + + return img; +} +#endif + +static XvImage *create_xvimage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf, HRESULT *err_code) { + XvImage *img = NULL; + DDPRIVATE(This); + void *img_data; + XvImageFormatValues *fo; + int formats, i; + int bpp = PFGET_BPP(lpdsf->s.surface_desc.ddpfPixelFormat); + + *err_code = DDERR_OUTOFVIDEOMEMORY; + + if (!(lpdsf->s.surface_desc.ddpfPixelFormat.dwFlags & DDPF_FOURCC)) { + /* Hmmm, overlay without FOURCC code.. Baaaaaad */ + ERR("Overlay without a FOURCC pixel format !\n"); + *err_code = DDERR_INVALIDPIXELFORMAT; + return NULL; + } + + /* First, find out if we support this PixelFormat. + I make the assumption here that the id of the XvImage format is the + same as the Windows FOURCC code. */ + fo = TSXvListImageFormats(display, ddpriv->port_id, &formats); + for (i = 0; i < formats; i++) + if (fo[i].id == lpdsf->s.surface_desc.ddpfPixelFormat.dwFourCC) break; + if (fo) + TSXFree(fo); + + if (i == formats) { + ERR("FOURCC code not supported by the video card !\n"); + *err_code = DDERR_INVALIDPIXELFORMAT; + return NULL; + } + +#ifdef HAVE_LIBXXSHM + if (ddpriv->xshm_active) + img = create_xvshmimage(This, lpdsf); + + if (img == NULL) { +#endif + /* Allocate surface memory */ + lpdsf->s.surface_desc.u1.lpSurface = + VirtualAlloc(NULL, + lpdsf->s.surface_desc.dwWidth * + lpdsf->s.surface_desc.dwHeight * + bpp, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + img_data = lpdsf->s.surface_desc.u1.lpSurface; + + /* In this case, create an XvImage */ + img = TSXvCreateImage(display, + ddpriv->port_id, + (int) lpdsf->s.surface_desc.ddpfPixelFormat.dwFourCC, + img_data, + lpdsf->s.surface_desc.dwWidth, + lpdsf->s.surface_desc.dwHeight); +#ifdef HAVE_LIBXXSHM + } +#endif + lpdsf->s.surface_desc.lPitch = ((XvImage *) img)->pitches[0]; + return img; +} +#else +static XvImage *create_xvimage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf, HRESULT *err_code) { + *err_code = DDERR_INVALIDPIXELFORMAT; + return NULL; +} +#endif + static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreateSurface( LPDIRECTDRAW2 iface,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf, IUnknown *lpunk @@ -350,7 +508,8 @@ static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreateSurface( dsurf->s.palette = NULL; dsurf->s.lpClipper = NULL; - dspriv->image = NULL; /* This is for off-screen buffers */ + dspriv->is_overlay = FALSE; + dspriv->info.image = NULL; /* This is for off-screen buffers */ /* Copy the surface description */ dsurf->s.surface_desc = *lpddsd; @@ -361,30 +520,43 @@ static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreateSurface( dsurf->s.surface_desc.dwHeight = This->d->height; dsurf->s.surface_desc.dwFlags |= DDSD_WIDTH|DDSD_HEIGHT; - /* Check if this a 'primary surface' or not */ + /* Check if this a 'primary surface' or an overlay */ if ((lpddsd->dwFlags & DDSD_CAPS) && - (lpddsd->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) + ((lpddsd->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) || + (lpddsd->ddsCaps.dwCaps & DDSCAPS_OVERLAY)) ) { - XImage *img; - /* Add flags if there were not present */ dsurf->s.surface_desc.dwFlags |= DDSD_WIDTH|DDSD_HEIGHT|DDSD_PITCH|DDSD_LPSURFACE|DDSD_PIXELFORMAT; - dsurf->s.surface_desc.dwWidth = This->d->width; - dsurf->s.surface_desc.dwHeight = This->d->height; - dsurf->s.surface_desc.ddsCaps.dwCaps |= DDSCAPS_VISIBLE|DDSCAPS_VIDEOMEMORY; - dsurf->s.surface_desc.ddpfPixelFormat = This->d->directdraw_pixelformat; + dsurf->s.surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; - TRACE("using standard XImage for a primary surface (%p)\n", dsurf); - /* Create the XImage */ - img = create_ximage(This,(IDirectDrawSurface4Impl*)dsurf); - if (img == NULL) + if (lpddsd->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { + dsurf->s.surface_desc.ddsCaps.dwCaps |= DDSCAPS_VISIBLE; + dsurf->s.surface_desc.ddpfPixelFormat = This->d->directdraw_pixelformat; + dsurf->s.surface_desc.dwWidth = This->d->width; + dsurf->s.surface_desc.dwHeight = This->d->height; + } else { + dspriv->is_overlay = TRUE; + /* In the case of Overlay surfaces, copy the one provided by the application */ + dsurf->s.surface_desc.ddpfPixelFormat = lpddsd->ddpfPixelFormat; + } + + if (lpddsd->ddsCaps.dwCaps & DDSCAPS_OVERLAY) { + HRESULT err_code; + TRACE("using an XvImage for the overlay (%p)\n", dsurf); + dspriv->info.overlay.image = create_xvimage(This,(IDirectDrawSurface4Impl*)dsurf, &err_code); + if (dspriv->info.overlay.image == NULL) + return err_code; + } else { + TRACE("using standard XImage for a primary surface (%p)\n", dsurf); + /* Create the XImage */ + dspriv->info.image = create_ximage(This,(IDirectDrawSurface4Impl*)dsurf); + if (dspriv->info.image == NULL) return DDERR_OUTOFMEMORY; - dspriv->image = img; + } /* Check for backbuffers */ if (lpddsd->dwFlags & DDSD_BACKBUFFERCOUNT) { IDirectDrawSurface4Impl* back; - XImage *img; int i; for (i=lpddsd->dwBackBufferCount;i--;) { @@ -413,11 +585,18 @@ static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreateSurface( bspriv = (x11_ds_private*)back->private; /* Create the XImage. */ - img = create_ximage(This, back); - if (img == NULL) + if (lpddsd->ddsCaps.dwCaps & DDSCAPS_OVERLAY) { + HRESULT err_code; + dspriv->is_overlay = TRUE; + bspriv->info.overlay.image = create_xvimage(This, back, &err_code); + if (bspriv->info.overlay.image == NULL) + return err_code; + } else { + bspriv->info.image = create_ximage(This, back); + if (bspriv->info.image == NULL) return DDERR_OUTOFMEMORY; + } TRACE("bspriv = %p\n",bspriv); - bspriv->image = img; /* Add relevant info to front and back buffers */ /* FIXME: backbuffer/frontbuffer handling broken here, but @@ -521,7 +700,7 @@ static HRESULT WINAPI Xlib_IDirectDrawImpl_SetDisplayMode( return DD_OK; } -static void fill_caps(LPDDCAPS caps) { +static void fill_caps(LPDDCAPS caps, x11_dd_private *x11ddp) { /* This function tries to fill the capabilities of Wine's DDraw implementation. Need to be fixed, though.. */ if (caps == NULL) @@ -545,24 +724,39 @@ static void fill_caps(LPDDCAPS caps) { /* These are all the supported capabilities of the surfaces */ caps->ddsCaps.dwCaps = DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER | DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_OFFSCREENPLAIN | - /*DDSCAPS_OVERLAY |*/ DDSCAPS_PALETTE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY | + DDSCAPS_PALETTE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY | DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE; #ifdef HAVE_OPENGL caps->dwCaps |= DDCAPS_3D | DDCAPS_ZBLTS; caps->dwCaps2 |= DDCAPS2_NO2DDURING3DSCENE; caps->ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER; #endif + +#ifdef HAVE_XVIDEO + if (x11ddp->xvideo_active) { + caps->dwCaps |= DDCAPS_OVERLAY | DDCAPS_OVERLAYFOURCC | DDCAPS_OVERLAYSTRETCH | DDCAPS_BLTFOURCC; + caps->dwCaps2 |= DDCAPS2_VIDEOPORT; + caps->dwMaxVisibleOverlays = 16; + caps->dwCurrVisibleOverlays = 0; + caps->dwMinOverlayStretch = 1; /* Apparently there is no 'down' stretching in XVideo, but well, Windows + Media player refuses to work when I put 1000 here :-/ */ + caps->dwMaxOverlayStretch = 100000; /* This is a 'bogus' value, I do not know the maximum stretching */ + TSXvListImageFormats(display, x11ddp->port_id, (unsigned int *) &(caps->dwNumFourCCCodes)); + caps->ddsCaps.dwCaps |= DDSCAPS_OVERLAY; + } +#endif } static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetCaps( LPDIRECTDRAW2 iface,LPDDCAPS caps1,LPDDCAPS caps2 ) { ICOM_THIS(IDirectDraw2Impl,iface); + DDPRIVATE(This); TRACE("(%p)->GetCaps(%p,%p)\n",This,caps1,caps2); /* Put the same caps for the two capabilities */ - fill_caps(caps1); - fill_caps(caps2); + fill_caps(caps1, ddpriv); + fill_caps(caps2, ddpriv); return DD_OK; } @@ -843,6 +1037,18 @@ static HRESULT WINAPI Xlib_IDirectDraw2Impl_EnumDisplayModes( return DD_OK; } +HRESULT WINAPI Xlib_IDirectDraw2Impl_GetFourCCCodes( + LPDIRECTDRAW2 iface,LPDWORD x,LPDWORD y +) { +#ifdef HAVE_XVIDEO + ICOM_THIS(IDirectDraw2Impl,iface); + FIXME("(%p,%p,%p), stub\n",This,x,y); + return DD_OK; +#else + return IDirectDraw2Impl_GetFourCCCodes(iface, x, y); +#endif +} + /* Note: Hack so we can reuse the old functions without compiler warnings */ #if !defined(__STRICT_ANSI__) && defined(__GNUC__) # define XCAST(fun) (typeof(xlib_ddvt.fn##fun)) @@ -865,7 +1071,7 @@ ICOM_VTABLE(IDirectDraw) xlib_ddvt = { XCAST(FlipToGDISurface)IDirectDraw2Impl_FlipToGDISurface, XCAST(GetCaps)Xlib_IDirectDraw2Impl_GetCaps, XCAST(GetDisplayMode)IDirectDraw2Impl_GetDisplayMode, - XCAST(GetFourCCCodes)IDirectDraw2Impl_GetFourCCCodes, + XCAST(GetFourCCCodes)Xlib_IDirectDraw2Impl_GetFourCCCodes, XCAST(GetGDISurface)IDirectDraw2Impl_GetGDISurface, XCAST(GetMonitorFrequency)IDirectDraw2Impl_GetMonitorFrequency, XCAST(GetScanLine)IDirectDraw2Impl_GetScanLine, @@ -916,7 +1122,7 @@ ICOM_VTABLE(IDirectDraw2) xlib_dd2vt = { IDirectDraw2Impl_FlipToGDISurface, Xlib_IDirectDraw2Impl_GetCaps, IDirectDraw2Impl_GetDisplayMode, - IDirectDraw2Impl_GetFourCCCodes, + Xlib_IDirectDraw2Impl_GetFourCCCodes, IDirectDraw2Impl_GetGDISurface, IDirectDraw2Impl_GetMonitorFrequency, IDirectDraw2Impl_GetScanLine, @@ -950,7 +1156,7 @@ ICOM_VTABLE(IDirectDraw4) xlib_dd4vt = { XCAST(FlipToGDISurface)IDirectDraw2Impl_FlipToGDISurface, XCAST(GetCaps)Xlib_IDirectDraw2Impl_GetCaps, XCAST(GetDisplayMode)IDirectDraw2Impl_GetDisplayMode, - XCAST(GetFourCCCodes)IDirectDraw2Impl_GetFourCCCodes, + XCAST(GetFourCCCodes)Xlib_IDirectDraw2Impl_GetFourCCCodes, XCAST(GetGDISurface)IDirectDraw2Impl_GetGDISurface, XCAST(GetMonitorFrequency)IDirectDraw2Impl_GetMonitorFrequency, XCAST(GetScanLine)IDirectDraw2Impl_GetScanLine, diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index e51de5043f0..b6abb9c4bb3 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -402,4 +402,5 @@ extern void _dump_surface_desc(DDSURFACEDESC *lpddsd); extern void _dump_cooperativelevel(DWORD cooplevel); extern void _dump_surface_desc(DDSURFACEDESC *lpddsd); extern void _dump_DDCOLORKEY(void *in); +extern void _dump_DDOVERLAY(DWORD flagmask) ; #endif /* __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H */ diff --git a/dlls/ddraw/dsurface/x11.c b/dlls/ddraw/dsurface/x11.c index 96d377af98f..ec1be526de4 100644 --- a/dlls/ddraw/dsurface/x11.c +++ b/dlls/ddraw/dsurface/x11.c @@ -133,7 +133,7 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Lock( assert(This->s.surface_desc.u1.lpSurface); /* wait for any previous operations to complete */ #ifdef HAVE_LIBXXSHM - if (dspriv->image && VISIBLE(This) && ddpriv->xshm_active) { + if (dspriv->info.image && VISIBLE(This) && ddpriv->xshm_active) { /* int compl = InterlockedExchange( &(ddpriv->xshm_compl), 0 ); if (compl) X11DRV_EVENT_WaitShmCompletion( compl ); @@ -144,7 +144,7 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Lock( /* If part of a visible 'clipped' surface, copy what is seen on the screen to the surface */ - if ((dspriv->image && VISIBLE(This)) && + if ((dspriv->info.image && VISIBLE(This)) && (This->s.lpClipper)) { HWND hWnd = ((IDirectDrawClipperImpl *) This->s.lpClipper)->hWnd; WND *wndPtr = WIN_FindWndPtr(hWnd); @@ -164,7 +164,7 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Lock( } TSXGetSubImage(display, drawable, 0, 0, width, height, 0xFFFFFFFF, - ZPixmap, dspriv->image, dest_x, dest_y); + ZPixmap, dspriv->info.image, dest_x, dest_y); WIN_ReleaseWndPtr(wndPtr); } @@ -180,8 +180,8 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) { SIZE imgsiz; /* Get XImage size */ - imgsiz.cx = dspriv->image->width; - imgsiz.cy = dspriv->image->height; + imgsiz.cx = dspriv->info.image->width; + imgsiz.cy = dspriv->info.image->height; if (This->s.lpClipper) { HWND hWnd = ((IDirectDrawClipperImpl *) This->s.lpClipper)->hWnd; @@ -225,7 +225,7 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) { if (This->s.ddraw->d->pixel_convert != NULL) This->s.ddraw->d->pixel_convert(This->s.surface_desc.u1.lpSurface, - dspriv->image->data, + dspriv->info.image->data, This->s.surface_desc.dwWidth, This->s.surface_desc.dwHeight, This->s.surface_desc.lPitch, @@ -233,7 +233,7 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) { /* if the DIB section is in GdiMod state, we must * touch the surface to get any updates from the DIB */ - Xlib_TouchData(dspriv->image->data); + Xlib_TouchData(dspriv->info.image->data); #ifdef HAVE_LIBXXSHM if (ddpriv->xshm_active) { /* @@ -246,7 +246,7 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) { TSXShmPutImage(display, drawable, DefaultGCOfScreen(X11DRV_GetXScreen()), - dspriv->image, + dspriv->info.image, adjust[0].x, adjust[0].y, adjust[1].x, adjust[1].y, imgsiz.cx, imgsiz.cy, True @@ -258,7 +258,7 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) { TSXPutImage(display, drawable, DefaultGCOfScreen(X11DRV_GetXScreen()), - dspriv->image, + dspriv->info.image, adjust[0].x, adjust[0].y, adjust[1].x, adjust[1].y, imgsiz.cx, imgsiz.cy ); @@ -276,7 +276,7 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Unlock( return DD_OK; */ /* Only redraw the screen when unlocking the buffer that is on screen */ - if (dspriv->image && VISIBLE(This)) { + if (dspriv->info.image && VISIBLE(This)) { Xlib_copy_surface_on_screen(This); if (This->s.palette) { DPPRIVATE(This->s.palette); @@ -289,6 +289,56 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Unlock( return DD_OK; } +#ifdef HAVE_XVIDEO +static void Xlib_copy_overlay_on_screen(IDirectDrawSurface4Impl* This) { + DSPRIVATE(This); + DDPRIVATE(This->s.ddraw); + Drawable drawable = ddpriv->drawable; + + if (!drawable) { + WND *tmpWnd = WIN_FindWndPtr(This->s.ddraw->d->window); + drawable = X11DRV_WND_GetXWindow(tmpWnd); + WIN_ReleaseWndPtr(tmpWnd); + + /* We don't have a context for this window. Host off the desktop */ + if( !drawable ) { + FIXME("Have to use Desktop Root Window??? Bummer.\n"); + drawable = X11DRV_WND_GetXWindow(WIN_GetDesktop()); + WIN_ReleaseDesktop(); + } + ddpriv->drawable = drawable; + } + +#ifdef HAVE_LIBXXSHM + if (ddpriv->xshm_active) { + /* let WaitShmCompletions track 'em for now */ + /* (you may want to track it again whenever you implement DX7's partial + * surface locking, where threads have concurrent access) */ + X11DRV_EVENT_PrepareShmCompletion( ddpriv->drawable ); + TSXvShmPutImage(display, ddpriv->port_id, drawable, DefaultGCOfScreen(X11DRV_GetXScreen()), + dspriv->info.overlay.image, + dspriv->info.overlay.src_rect.left, dspriv->info.overlay.src_rect.top, + dspriv->info.overlay.src_rect.right - dspriv->info.overlay.src_rect.left, + dspriv->info.overlay.src_rect.bottom - dspriv->info.overlay.src_rect.top, + dspriv->info.overlay.dst_rect.left, dspriv->info.overlay.dst_rect.top, + dspriv->info.overlay.dst_rect.right - dspriv->info.overlay.dst_rect.left, + dspriv->info.overlay.dst_rect.bottom - dspriv->info.overlay.dst_rect.top, + True); + /* make sure the image is transferred ASAP */ + TSXFlush(display); + } else +#endif + TSXvPutImage(display, ddpriv->port_id, drawable, DefaultGCOfScreen(X11DRV_GetXScreen()), + dspriv->info.overlay.image, + dspriv->info.overlay.src_rect.left, dspriv->info.overlay.src_rect.top, + dspriv->info.overlay.src_rect.right - dspriv->info.overlay.src_rect.left, + dspriv->info.overlay.src_rect.bottom - dspriv->info.overlay.src_rect.top, + dspriv->info.overlay.dst_rect.left, dspriv->info.overlay.dst_rect.top, + dspriv->info.overlay.dst_rect.right - dspriv->info.overlay.dst_rect.left, + dspriv->info.overlay.dst_rect.bottom - dspriv->info.overlay.dst_rect.top); +} +#endif + HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Flip( LPDIRECTDRAWSURFACE4 iface,LPDIRECTDRAWSURFACE4 flipto,DWORD dwFlags ) { @@ -301,9 +351,9 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Flip( IDirectDrawSurface4Impl* iflipto=(IDirectDrawSurface4Impl*)flipto; TRACE("(%p)->Flip(%p,%08lx)\n",This,iflipto,dwFlags); - if (!This->s.ddraw->d->paintable) + if ((!This->s.ddraw->d->paintable) && (dspriv->is_overlay == FALSE)) return DD_OK; - + iflipto = _common_find_flipto(This,iflipto); fspriv = (x11_ds_private*)iflipto->private; @@ -313,16 +363,28 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Flip( This->s.surface_desc.u1.lpSurface = iflipto->s.surface_desc.u1.lpSurface; iflipto->s.surface_desc.u1.lpSurface = surf; - /* the associated ximage */ - image = dspriv->image; - dspriv->image = fspriv->image; - fspriv->image = image; + /* the associated ximage + + NOTE : for XVideo, the pointer to the XvImage is at the same position + in memory than the standard XImage. This means that this code + still works :-) + */ + image = dspriv->info.image; + dspriv->info.image = fspriv->info.image; + fspriv->info.image = image; if (dspriv->opengl_flip) { #ifdef HAVE_OPENGL ENTER_GL(); glXSwapBuffers(display, ddpriv->drawable); LEAVE_GL(); +#endif + } else if (dspriv->is_overlay) { +#ifdef HAVE_XVIDEO + if (dspriv->info.overlay.shown) + Xlib_copy_overlay_on_screen(This); +#else + ERR("Why was this code activated WITHOUT XVideo support ?\n"); #endif } else { #ifdef HAVE_LIBXXSHM @@ -432,24 +494,32 @@ ULONG WINAPI Xlib_IDirectDrawSurface4Impl_Release(LPDIRECTDRAWSURFACE4 iface) { VirtualFree(This->s.surface_desc.u1.lpSurface, 0, MEM_RELEASE); /* Now free the XImages and the respective screen-side surfaces */ - if (dspriv->image != NULL) { - if (dspriv->image->data != This->s.surface_desc.u1.lpSurface) - VirtualFree(dspriv->image->data, 0, MEM_RELEASE); + if (dspriv->info.image != NULL) { + if (dspriv->info.image->data != This->s.surface_desc.u1.lpSurface) + VirtualFree(dspriv->info.image->data, 0, MEM_RELEASE); #ifdef HAVE_LIBXXSHM if (ddpriv->xshm_active) { TSXShmDetach(display, &(dspriv->shminfo)); - TSXDestroyImage(dspriv->image); + if (This->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_OVERLAY) { + TSXFree(dspriv->info.image); + } else { + TSXDestroyImage(dspriv->info.image); + } shmdt(dspriv->shminfo.shmaddr); } else #endif { + if (This->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_OVERLAY) { + TSXFree(dspriv->info.image); + } else { /* normal X Image memory was never allocated by X, but always by * ourselves -> Don't let X free our imagedata. */ - dspriv->image->data = NULL; - TSXDestroyImage(dspriv->image); + dspriv->info.image->data = NULL; + TSXDestroyImage(dspriv->info.image); + } } - dspriv->image = 0; + dspriv->info.image = 0; } if (This->s.palette) @@ -492,6 +562,108 @@ HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_GetDC(LPDIRECTDRAWSURFACE4 iface,HDC return result; } +#ifdef HAVE_XVIDEO +typedef struct { + BOOL shown; + LPRECT src_rect; + LPRECT dst_rect; + LPDIRECTDRAWSURFACE dest_surface; +} UpdateOverlayEnumerate; + +static HRESULT WINAPI enum_func(LPDIRECTDRAWSURFACE lpDDSurface, + LPDDSURFACEDESC lpDDSurfaceDesc, + LPVOID lpContext) { + ICOM_THIS(IDirectDrawSurface4Impl,lpDDSurface); + DSPRIVATE(This); + UpdateOverlayEnumerate *ctx = (UpdateOverlayEnumerate *) lpContext; + + if ((lpDDSurfaceDesc->ddsCaps.dwCaps) & DDSCAPS_BACKBUFFER) { + TRACE("Upgrading surface %p\n", lpDDSurface); + + if (ctx->shown) { + dspriv->info.overlay.shown = TRUE; + dspriv->info.overlay.src_rect = *(ctx->src_rect); + dspriv->info.overlay.dst_rect = *(ctx->dst_rect); + dspriv->info.overlay.dest_surface = ctx->dest_surface; + } else { + dspriv->info.overlay.shown = FALSE; + } + } + + return DDENUMRET_OK; +} +#endif + +HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_UpdateOverlay( + LPDIRECTDRAWSURFACE4 iface, LPRECT lpSrcRect, + LPDIRECTDRAWSURFACE4 lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, + LPDDOVERLAYFX lpDDOverlayFx +) { + ICOM_THIS(IDirectDrawSurface4Impl,iface); +#ifdef HAVE_XVIDEO + DSPRIVATE(This); + DDPRIVATE(This->s.ddraw); + + if (ddpriv->xvideo_active) { + TRACE("(%p)->(%p,%p,%p,0x%08lx,%p)\n", This, + lpSrcRect, lpDDDestSurface, lpDestRect, dwFlags, lpDDOverlayFx ); + + if (TRACE_ON(ddraw)) { + DPRINTF(" - dwFlags : "); + _dump_DDOVERLAY(dwFlags); + + if (lpSrcRect) DPRINTF(" - src rectangle :%dx%d-%dx%d\n",lpSrcRect->left,lpSrcRect->top, + lpSrcRect->right,lpSrcRect->bottom); + if (lpDestRect) DPRINTF(" - dest rectangle :%dx%d-%dx%d\n",lpDestRect->left,lpDestRect->top, + lpDestRect->right,lpDestRect->bottom); + } + + if (dwFlags & DDOVER_SHOW) { + UpdateOverlayEnumerate ctx; + + dwFlags &= ~DDOVER_SHOW; + + if ((lpSrcRect == NULL) || (lpDestRect == NULL)) { + FIXME("This is NOT supported yet...\n"); + return DD_OK; + } + + /* Set the shown BOOL to TRUE and update the rectangles */ + dspriv->info.overlay.shown = TRUE; + dspriv->info.overlay.src_rect = *lpSrcRect; + dspriv->info.overlay.dst_rect = *lpDestRect; + dspriv->info.overlay.dest_surface = (LPDIRECTDRAWSURFACE) lpDDDestSurface; + + /* Now the same for the backbuffers */ + ctx.shown = TRUE; + ctx.src_rect = lpSrcRect; + ctx.dst_rect = lpDestRect; + ctx.dest_surface = (LPDIRECTDRAWSURFACE) lpDDDestSurface; + + IDirectDrawSurface4Impl_EnumAttachedSurfaces(iface, &ctx, enum_func); + } else if (dwFlags & DDOVER_HIDE) { + UpdateOverlayEnumerate ctx; + + dwFlags &= ~DDOVER_HIDE; + + /* Set the shown BOOL to FALSE for all overlays */ + dspriv->info.overlay.shown = FALSE; + ctx.shown = FALSE; + IDirectDrawSurface4Impl_EnumAttachedSurfaces(iface, &ctx, enum_func); + } + + if (dwFlags && TRACE_ON(ddraw)) { + WARN("Unsupported flags : "); + _dump_DDOVERLAY(dwFlags); + } + } else +#endif + FIXME("(%p)->(%p,%p,%p,0x%08lx,%p) not supported without XVideo !\n", This, + lpSrcRect, lpDDDestSurface, lpDestRect, dwFlags, lpDDOverlayFx ); + + return DD_OK; +} + ICOM_VTABLE(IDirectDrawSurface4) xlib_dds4vt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE @@ -528,7 +700,7 @@ ICOM_VTABLE(IDirectDrawSurface4) xlib_dds4vt = IDirectDrawSurface4Impl_SetOverlayPosition, Xlib_IDirectDrawSurface4Impl_SetPalette, Xlib_IDirectDrawSurface4Impl_Unlock, - IDirectDrawSurface4Impl_UpdateOverlay, + Xlib_IDirectDrawSurface4Impl_UpdateOverlay, IDirectDrawSurface4Impl_UpdateOverlayDisplay, IDirectDrawSurface4Impl_UpdateOverlayZOrder, IDirectDrawSurface4Impl_GetDDInterface, diff --git a/dlls/ddraw/helper.c b/dlls/ddraw/helper.c index dea45288946..b7fc84e4e72 100644 --- a/dlls/ddraw/helper.c +++ b/dlls/ddraw/helper.c @@ -51,6 +51,44 @@ void _dump_DDBLTFX(DWORD flagmask) { DPRINTF("\n"); } +void _dump_DDOVERLAY(DWORD flagmask) { + int i; + const struct { + DWORD mask; + char *name; + } flags[] = { +#define FE(x) { x, #x}, + FE(DDOVER_ALPHADEST) + FE(DDOVER_ALPHADESTCONSTOVERRIDE) + FE(DDOVER_ALPHADESTNEG) + FE(DDOVER_ALPHADESTSURFACEOVERRIDE) + FE(DDOVER_ALPHAEDGEBLEND) + FE(DDOVER_ALPHASRC) + FE(DDOVER_ALPHASRCCONSTOVERRIDE) + FE(DDOVER_ALPHASRCNEG) + FE(DDOVER_ALPHASRCSURFACEOVERRIDE) + FE(DDOVER_HIDE) + FE(DDOVER_KEYDEST) + FE(DDOVER_KEYDESTOVERRIDE) + FE(DDOVER_KEYSRC) + FE(DDOVER_KEYSRCOVERRIDE) + FE(DDOVER_SHOW) + FE(DDOVER_ADDDIRTYRECT) + FE(DDOVER_REFRESHDIRTYRECTS) + FE(DDOVER_REFRESHALL) + FE(DDOVER_DDFX) + FE(DDOVER_AUTOFLIP) + FE(DDOVER_BOB) + FE(DDOVER_OVERRIDEBOBWEAVE) + FE(DDOVER_INTERLEAVED) +#undef FE + }; + for (i=0;idwFlags); if (pf->dwFlags & DDPF_FOURCC) { - DPRINTF(", dwFourCC (%08lx) : %c%c%c%c", - pf->dwFourCC, + DPRINTF(", dwFourCC code '%c%c%c%c' (0x%08lx) - %ld bits per pixel", (unsigned char)( pf->dwFourCC &0xff), (unsigned char)((pf->dwFourCC>> 8)&0xff), (unsigned char)((pf->dwFourCC>>16)&0xff), - (unsigned char)((pf->dwFourCC>>24)&0xff) + (unsigned char)((pf->dwFourCC>>24)&0xff), + pf->dwFourCC, + pf->u.dwYUVBitCount ); } if (pf->dwFlags & DDPF_RGB) { diff --git a/dlls/ddraw/x11.c b/dlls/ddraw/x11.c index a5fb08e44b3..a3902ab8c0f 100644 --- a/dlls/ddraw/x11.c +++ b/dlls/ddraw/x11.c @@ -44,6 +44,64 @@ DDRAW_XSHM_Available(void) { return FALSE; } +#ifdef HAVE_XVIDEO +static BOOL +DDRAW_XVIDEO_Available(x11_dd_private *x11ddp) { + unsigned int p_version, p_release, p_request_base, p_event_base, p_error_base; + + if (TSXvQueryExtension(display, &p_version, &p_release, &p_request_base, + &p_event_base, &p_error_base) == Success) { + XvAdaptorInfo *ai; + int num_adaptators, i, default_port; + + if ((p_version < 2) || ((p_version == 2) && (p_release < 2))) { + TRACE("XVideo extension does NOT support needed features (need version 2.2) !\n"); + return FALSE; + } + + if (TSXvQueryAdaptors(display, X11DRV_GetXRootWindow(), &num_adaptators, &ai) != Success) { + TRACE("Failed to get list of adaptators.\n"); + return FALSE; + } + if (num_adaptators == 0) { + TRACE("No XVideo supporting adaptators found.\n"); + return FALSE; + } + + default_port = PROFILE_GetWineIniInt("x11drv", "XVideoPort", -1); + for (i = 0; i < num_adaptators; i++) { + if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask)) { + /* This supports everything I want : XvImages and the possibility to put something */ + if (default_port == -1) { + default_port = ai[i].base_id; + break; + } else { + if ((ai[i].base_id <= default_port) && + ((ai[i].base_id + ai[i].num_ports) > default_port)) { + break; + } + } + } + } + if (i == num_adaptators) { + if (default_port != -1) { + ERR("User specified port (%d) not found.\n", default_port); + } else { + TRACE("No input + image capable device found.\n"); + } + TSXvFreeAdaptorInfo(ai); + return FALSE; + } + x11ddp->port_id = default_port; + + TRACE("XVideo support available (using version %d.%d)\n", p_version, p_release); + TSXvFreeAdaptorInfo(ai); + return TRUE; + } + return FALSE; +} +#endif + static HRESULT X11_Create( LPDIRECTDRAW *lplpDD ) { IDirectDrawImpl* ddraw; int depth; @@ -88,6 +146,13 @@ static HRESULT X11_Create( LPDIRECTDRAW *lplpDD ) { TRACE("Using XShm extension.\n"); } #endif + +#ifdef HAVE_XVIDEO + /* Test if XVideo support is available */ + if ((x11priv->xvideo_active = DDRAW_XVIDEO_Available(x11priv))) { + TRACE("Using XVideo extension on port '%ld'.\n", x11priv->port_id); + } +#endif return DD_OK; } diff --git a/dlls/ddraw/x11_private.h b/dlls/ddraw/x11_private.h index 50ec9496a04..d9bb8e90db0 100644 --- a/dlls/ddraw/x11_private.h +++ b/dlls/ddraw/x11_private.h @@ -18,6 +18,13 @@ # include "ts_xshm.h" #endif /* defined(HAVE_LIBXXSHM) */ +#ifdef HAVE_XVIDEO +#include "ts_xvideo.h" +#else +/* Fake type so that NOT to have too many #ifdef XVideo lying around */ +typedef int XvImage; +#endif + #include "x11drv.h" #include "ddraw_private.h" @@ -34,6 +41,10 @@ typedef struct x11_dd_private { #ifdef HAVE_LIBXXSHM int xshm_active, xshm_compl; #endif /* defined(HAVE_LIBXXSHM) */ +#ifdef HAVE_XVIDEO + BOOL xvideo_active; + XvPortID port_id; +#endif Window drawable; void *device_capabilities; } x11_dd_private; @@ -47,7 +58,18 @@ extern HRESULT WINAPI Xlib_IDirectDrawPaletteImpl_SetEntries(LPDIRECTDRAWPALETTE extern ULONG WINAPI Xlib_IDirectDrawPaletteImpl_Release(LPDIRECTDRAWPALETTE iface); typedef struct x11_ds_private { - XImage *image; + BOOL is_overlay; + union { + XImage *image; + struct { + /* The 'image' field should be in FIRST !!!! The Flip function depends on that... */ + XvImage *image; + BOOL shown; + RECT src_rect; + RECT dst_rect; + LPDIRECTDRAWSURFACE dest_surface; + } overlay; + } info; #ifdef HAVE_LIBXXSHM XShmSegmentInfo shminfo; #endif diff --git a/include/ddraw.h b/include/ddraw.h index 3d8c1769ee5..d40ff310e46 100644 --- a/include/ddraw.h +++ b/include/ddraw.h @@ -811,6 +811,31 @@ typedef struct _DDPIXELFORMAT { #define DDOVERFX_MIRRORLEFTRIGHT 0x00000002 #define DDOVERFX_MIRRORUPDOWN 0x00000004 +/* UpdateOverlay flags */ +#define DDOVER_ALPHADEST 0x00000001 +#define DDOVER_ALPHADESTCONSTOVERRIDE 0x00000002 +#define DDOVER_ALPHADESTNEG 0x00000004 +#define DDOVER_ALPHADESTSURFACEOVERRIDE 0x00000008 +#define DDOVER_ALPHAEDGEBLEND 0x00000010 +#define DDOVER_ALPHASRC 0x00000020 +#define DDOVER_ALPHASRCCONSTOVERRIDE 0x00000040 +#define DDOVER_ALPHASRCNEG 0x00000080 +#define DDOVER_ALPHASRCSURFACEOVERRIDE 0x00000100 +#define DDOVER_HIDE 0x00000200 +#define DDOVER_KEYDEST 0x00000400 +#define DDOVER_KEYDESTOVERRIDE 0x00000800 +#define DDOVER_KEYSRC 0x00001000 +#define DDOVER_KEYSRCOVERRIDE 0x00002000 +#define DDOVER_SHOW 0x00004000 +#define DDOVER_ADDDIRTYRECT 0x00008000 +#define DDOVER_REFRESHDIRTYRECTS 0x00010000 +#define DDOVER_REFRESHALL 0x00020000 +#define DDOVER_DDFX 0x00080000 +#define DDOVER_AUTOFLIP 0x00100000 +#define DDOVER_BOB 0x00200000 +#define DDOVER_OVERRIDEBOBWEAVE 0x00400000 +#define DDOVER_INTERLEAVED 0x00800000 + /* DDCOLORKEY.dwFlags */ #define DDPF_ALPHAPIXELS 0x00000001 #define DDPF_ALPHA 0x00000002 diff --git a/wine.ini b/wine.ini index 65d29bfce8f..ebada126a9b 100644 --- a/wine.ini +++ b/wine.ini @@ -113,6 +113,9 @@ DesktopDoubleBuffered = N ; Code page used for captions in managed mode ; 0 means default ANSI code page (CP_ACP == 0) TextCP=0 +; Use this if you have more than one port for video on your setup +; (Wine uses for now the first 'input image' it founds). +;; XVideoPort = 43 [fonts] ;Read documentation/fonts before adding aliases