Sweden-Number/dlls/ddraw/ddraw/x11.c

996 lines
31 KiB
C

/* DirectDraw IDirectDraw Xlib interface
*
* Copyright 1997-2000 Marcus Meissner
* Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
*/
/*
* This file contains the Xlib specific interface functions.
*/
#include "config.h"
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "winerror.h"
#include "ddraw.h"
#include "d3d.h"
#include "win.h"
#include "debugtools.h"
#include "message.h"
#include "options.h"
#include "monitor.h"
DEFAULT_DEBUG_CHANNEL(ddraw);
#include "x11_private.h"
#define DDPRIVATE(x) x11_dd_private *ddpriv = ((x11_dd_private*)(x)->private)
#define DPPRIVATE(x) x11_dp_private *dppriv = ((x11_dp_private*)(x)->private)
#define DSPRIVATE(x) x11_ds_private *dspriv = ((x11_ds_private*)(x)->private)
static inline BOOL get_option( const char *name, BOOL def ) {
return PROFILE_GetWineIniBool( "x11drv", name, def );
}
int _common_depth_to_pixelformat(
DWORD depth, DDPIXELFORMAT *pixelformat,DDPIXELFORMAT *screen_pixelformat,
int *pix_depth
) {
XVisualInfo *vi;
XPixmapFormatValues *pf;
XVisualInfo vt;
int nvisuals, npixmap, i;
int match = 0;
int index = -2;
vi = TSXGetVisualInfo(display, VisualNoMask, &vt, &nvisuals);
pf = TSXListPixmapFormats(display, &npixmap);
for (i = 0; i < npixmap; i++) {
if (pf[i].depth == depth) {
int j;
for (j = 0; j < nvisuals; j++) {
if (vi[j].depth == pf[i].depth) {
pixelformat->dwSize = sizeof(*pixelformat);
if (depth == 8) {
pixelformat->dwFlags = DDPF_PALETTEINDEXED8|DDPF_RGB;
pixelformat->u1.dwRBitMask = 0;
pixelformat->u2.dwGBitMask = 0;
pixelformat->u3.dwBBitMask = 0;
} else {
pixelformat->dwFlags = DDPF_RGB;
pixelformat->u1.dwRBitMask = vi[j].red_mask;
pixelformat->u2.dwGBitMask = vi[j].green_mask;
pixelformat->u3.dwBBitMask = vi[j].blue_mask;
}
pixelformat->dwFourCC = 0;
pixelformat->u.dwRGBBitCount = pf[i].bits_per_pixel;
pixelformat->u4.dwRGBAlphaBitMask= 0;
*screen_pixelformat = *pixelformat;
if (pix_depth)
*pix_depth = vi[j].depth;
match = 1;
index = -1;
goto clean_up_and_exit;
}
}
WARN("No visual corresponding to pixmap format !\n");
}
}
if (match == 0) {
/* We try now to find an emulated mode */
int c;
for (c = 0; c < sizeof(ModeEmulations) / sizeof(Convert); c++) {
if (ModeEmulations[c].dest.depth == depth) {
/* Found an emulation function, now tries to find a matching visual / pixel format pair */
for (i = 0; i < npixmap; i++) {
if ((pf[i].depth == ModeEmulations[c].screen.depth) &&
(pf[i].bits_per_pixel == ModeEmulations[c].screen.bpp)) {
int j;
for (j = 0; j < nvisuals; j++) {
if (vi[j].depth == pf[i].depth) {
screen_pixelformat->dwSize = sizeof(*screen_pixelformat);
screen_pixelformat->dwFlags = DDPF_RGB;
screen_pixelformat->dwFourCC = 0;
screen_pixelformat->u.dwRGBBitCount = pf[i].bits_per_pixel;
screen_pixelformat->u1.dwRBitMask = vi[j].red_mask;
screen_pixelformat->u2.dwGBitMask = vi[j].green_mask;
screen_pixelformat->u3.dwBBitMask = vi[j].blue_mask;
screen_pixelformat->u4.dwRGBAlphaBitMask= 0;
pixelformat->dwSize = sizeof(*pixelformat);
pixelformat->dwFourCC = 0;
if (depth == 8) {
pixelformat->dwFlags = DDPF_RGB|DDPF_PALETTEINDEXED8;
pixelformat->u.dwRGBBitCount = 8;
pixelformat->u1.dwRBitMask = 0;
pixelformat->u2.dwGBitMask = 0;
pixelformat->u3.dwBBitMask = 0;
} else {
pixelformat->dwFlags = DDPF_RGB;
pixelformat->u.dwRGBBitCount = ModeEmulations[c].dest.bpp;
pixelformat->u1.dwRBitMask = ModeEmulations[c].dest.rmask;
pixelformat->u2.dwGBitMask = ModeEmulations[c].dest.gmask;
pixelformat->u3.dwBBitMask = ModeEmulations[c].dest.bmask;
}
pixelformat->u4.dwRGBAlphaBitMask= 0;
if (pix_depth)
*pix_depth = vi[j].depth;
match = 2;
index = c;
goto clean_up_and_exit;
}
ERR("No visual corresponding to pixmap format !\n");
}
}
}
}
}
}
clean_up_and_exit:
TSXFree(vi);
TSXFree(pf);
return index;
}
/*******************************************************************************
* IDirectDraw
*/
#ifdef HAVE_LIBXXSHM
/* Error handlers for Image creation */
static int XShmErrorHandler(Display *dpy, XErrorEvent *event) {
XShmErrorFlag = 1;
return 0;
}
static XImage *create_xshmimage(
IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf
) {
DSPRIVATE(lpdsf);
DDPRIVATE(This);
XImage *img;
int (*WineXHandler)(Display *, XErrorEvent *);
img = TSXShmCreateImage(display,
DefaultVisualOfScreen(X11DRV_GetXScreen()),
This->d.pixmap_depth,
ZPixmap,
NULL,
&(dspriv->shminfo),
lpdsf->s.surface_desc.dwWidth,
lpdsf->s.surface_desc.dwHeight
);
if (img == NULL) {
FIXME("Couldn't create XShm image (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->bytes_per_line * img->height, 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;
TSXDestroyImage(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;
TSXDestroyImage(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;
XDestroyImage(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);
if (This->d.pixel_convert != NULL) {
int bpp = PFGET_BPP(This->d.directdraw_pixelformat);
lpdsf->s.surface_desc.u1.lpSurface = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
lpdsf->s.surface_desc.dwWidth *
lpdsf->s.surface_desc.dwHeight *
bpp
);
} else
lpdsf->s.surface_desc.u1.lpSurface = img->data;
return img;
}
#endif /* HAVE_LIBXXSHM */
static XImage *create_ximage(IDirectDraw2Impl* This, IDirectDrawSurface4Impl* lpdsf) {
XImage *img = NULL;
DDPRIVATE(This);
void *img_data;
int bpp = PFGET_BPP(This->d.directdraw_pixelformat);
#ifdef HAVE_LIBXXSHM
if (ddpriv->xshm_active)
img = create_xshmimage(This, lpdsf);
if (img == NULL) {
#endif
/* Allocate surface memory */
lpdsf->s.surface_desc.u1.lpSurface = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
lpdsf->s.surface_desc.dwWidth *
lpdsf->s.surface_desc.dwHeight *
bpp
);
if (This->d.pixel_convert != NULL)
img_data = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
lpdsf->s.surface_desc.dwWidth *
lpdsf->s.surface_desc.dwHeight *
bpp
);
else
img_data = lpdsf->s.surface_desc.u1.lpSurface;
/* In this case, create an XImage */
img = TSXCreateImage(display,
DefaultVisualOfScreen(X11DRV_GetXScreen()),
This->d.pixmap_depth,
ZPixmap,
0,
img_data,
lpdsf->s.surface_desc.dwWidth,
lpdsf->s.surface_desc.dwHeight,
32,
lpdsf->s.surface_desc.dwWidth*bpp
);
#ifdef HAVE_LIBXXSHM
}
#endif
/* assert(bpp*lpdsf->s.surface_desc.dwWidth == img->bytes_per_line); */
if (This->d.pixel_convert != NULL)
lpdsf->s.surface_desc.lPitch = bpp*lpdsf->s.surface_desc.dwWidth;
else
lpdsf->s.surface_desc.lPitch = img->bytes_per_line;
return img;
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreateSurface(
LPDIRECTDRAW2 iface,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf,
IUnknown *lpunk
) {
ICOM_THIS(IDirectDraw2Impl,iface);
IDirectDrawSurfaceImpl* dsurf;
x11_ds_private *dspriv;
TRACE("(%p)->CreateSurface(%p,%p,%p)\n", This,lpddsd,lpdsf,lpunk);
if (TRACE_ON(ddraw)) _dump_surface_desc(lpddsd);
*lpdsf = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(IDirectDrawSurfaceImpl)
);
dsurf = (IDirectDrawSurfaceImpl*)*lpdsf;
dsurf->ref = 2;
dsurf->private = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(x11_ds_private)
);
ICOM_VTBL(dsurf) = (ICOM_VTABLE(IDirectDrawSurface)*)&xlib_dds4vt;
dspriv = (x11_ds_private*)dsurf->private;
dsurf->s.ddraw = This;
IDirectDraw2_AddRef(iface);
dsurf->s.palette = NULL;
dsurf->s.lpClipper = NULL;
dspriv->image = NULL; /* This is for off-screen buffers */
/* Copy the surface description */
dsurf->s.surface_desc = *lpddsd;
if (!(lpddsd->dwFlags & DDSD_WIDTH))
dsurf->s.surface_desc.dwWidth = This->d.width;
if (!(lpddsd->dwFlags & DDSD_HEIGHT))
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 */
if ((lpddsd->dwFlags & DDSD_CAPS) &&
(lpddsd->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
) {
XImage *img;
TRACE("using standard XImage for a primary surface (%p)\n", dsurf);
/* Create the XImage */
img = create_ximage(This,(IDirectDrawSurface4Impl*)dsurf);
if (img == NULL)
return DDERR_OUTOFMEMORY;
dspriv->image = 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;
/* Check for backbuffers */
if (lpddsd->dwFlags & DDSD_BACKBUFFERCOUNT) {
IDirectDrawSurface4Impl* back;
XImage *img;
int i;
for (i=lpddsd->dwBackBufferCount;i--;) {
x11_ds_private *bspriv;
back = (IDirectDrawSurface4Impl*)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(IDirectDrawSurface4Impl)
);
TRACE("allocated back-buffer (%p)\n", back);
IDirectDraw2_AddRef(iface);
back->s.ddraw = This;
back->ref = 2;
ICOM_VTBL(back)=(ICOM_VTABLE(IDirectDrawSurface4)*)&xlib_dds4vt;
/* Copy the surface description from the front buffer */
back->s.surface_desc = dsurf->s.surface_desc;
back->s.surface_desc.u1.lpSurface = NULL;
back->private = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(x11_ds_private)
);
bspriv = (x11_ds_private*)back->private;
/* Create the XImage. */
img = create_ximage(This, back);
if (img == 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
* will be fixed up in _Flip().
*/
SDDSCAPS(dsurf) |= DDSCAPS_FRONTBUFFER;
SDDSCAPS(back) |= DDSCAPS_BACKBUFFER|DDSCAPS_VIDEOMEMORY|DDSCAPS_FLIP;
back->s.surface_desc.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
SDDSCAPS(back) &= ~DDSCAPS_VISIBLE;
TRACE("attaching surface %p to %p\n",back,*lpdsf);
IDirectDrawSurface4_AddAttachedSurface((LPDIRECTDRAWSURFACE4)(*lpdsf),(LPDIRECTDRAWSURFACE4)back);
}
}
} else {
/* There is no Xlib-specific code here...
* Go to the common surface creation function
*/
return common_off_screen_CreateSurface(This,dsurf);
}
return DD_OK;
}
/*
* The Xlib Implementation tries to use the passed hwnd as drawing window,
* even when the approbiate bitmasks are not specified.
*/
static HRESULT WINAPI Xlib_IDirectDraw2Impl_SetCooperativeLevel(
LPDIRECTDRAW2 iface,HWND hwnd,DWORD cooplevel
) {
ICOM_THIS(IDirectDraw2Impl,iface);
DDPRIVATE(This);
FIXME("(%p)->(%08lx,%08lx)\n",This,(DWORD)hwnd,cooplevel);
if (TRACE_ON(ddraw))
_dump_cooperativelevel(cooplevel);
This->d.mainWindow = hwnd;
/* This will be overwritten in the case of Full Screen mode.
Windowed games could work with that :-) */
if (hwnd) {
WND *tmpWnd = WIN_FindWndPtr(hwnd);
ddpriv->drawable = X11DRV_WND_GetXWindow(tmpWnd);
WIN_ReleaseWndPtr(tmpWnd);
if( !ddpriv->drawable ) {
ddpriv->drawable = ((X11DRV_WND_DATA *) WIN_GetDesktop()->pDriverData)->window;
WIN_ReleaseDesktop();
}
TRACE("Setting drawable to %ld\n", ddpriv->drawable);
}
return DD_OK;
}
static HRESULT WINAPI Xlib_IDirectDrawImpl_SetDisplayMode(
LPDIRECTDRAW iface,DWORD width,DWORD height,DWORD depth
) {
ICOM_THIS(IDirectDrawImpl,iface);
DDPRIVATE(This);
char buf[200];
WND *tmpWnd;
int c;
TRACE("(%p)->SetDisplayMode(%ld,%ld,%ld)\n",
This, width, height, depth);
switch ((c = _common_depth_to_pixelformat(depth,
&(This->d.directdraw_pixelformat),
&(This->d.screen_pixelformat),
&(This->d.pixmap_depth)))) {
case -2:
sprintf(buf,"SetDisplayMode(w=%ld,h=%ld,d=%ld), unsupported depth!",width,height,depth);
MessageBoxA(0,buf,"WINE DirectDraw",MB_OK|MB_ICONSTOP);
return DDERR_UNSUPPORTEDMODE;
case -1:
/* No convertion */
This->d.pixel_convert = NULL;
This->d.palette_convert = NULL;
break;
default:
DPRINTF("DirectDraw warning: running in depth-convertion mode. Should run using a %ld depth for optimal performances.\n", depth);
/* Set the depth convertion routines */
This->d.pixel_convert = ModeEmulations[c].funcs.pixel_convert;
This->d.palette_convert = ModeEmulations[c].funcs.palette_convert;
}
This->d.width = width;
This->d.height = height;
_common_IDirectDrawImpl_SetDisplayMode(This);
tmpWnd = WIN_FindWndPtr(This->d.window);
This->d.paintable = 1;
ddpriv->drawable = ((X11DRV_WND_DATA *) tmpWnd->pDriverData)->window;
WIN_ReleaseWndPtr(tmpWnd);
/* We don't have a context for this window. Host off the desktop */
if( !ddpriv->drawable )
{
ddpriv->drawable = ((X11DRV_WND_DATA *) WIN_GetDesktop()->pDriverData)->window;
WIN_ReleaseDesktop();
}
TRACE("Setting drawable to %ld\n", ddpriv->drawable);
if (get_option( "DXGrab", 0 )) {
/* Confine cursor movement (risky, but the user asked for it) */
TSXGrabPointer(display, ddpriv->drawable, True, 0, GrabModeAsync, GrabModeAsync, ddpriv->drawable, None, CurrentTime);
}
return DD_OK;
}
static void fill_caps(LPDDCAPS caps) {
/* This function tries to fill the capabilities of Wine's DDraw implementation.
Need to be fixed, though.. */
if (caps == NULL)
return;
caps->dwSize = sizeof(*caps);
caps->dwCaps = DDCAPS_ALPHA | DDCAPS_BLT | DDCAPS_BLTSTRETCH | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL | DDCAPS_CANBLTSYSMEM | DDCAPS_COLORKEY | DDCAPS_PALETTE /*| DDCAPS_NOHARDWARE*/;
caps->dwCaps2 = DDCAPS2_CERTIFIED | DDCAPS2_NOPAGELOCKREQUIRED | DDCAPS2_WIDESURFACES;
caps->dwCKeyCaps = 0xFFFFFFFF; /* Should put real caps here one day... */
caps->dwFXCaps = 0;
caps->dwFXAlphaCaps = 0;
caps->dwPalCaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256;
caps->dwSVCaps = 0;
caps->dwZBufferBitDepths = DDBD_16;
/* I put here 8 Mo so that D3D applications will believe they have enough memory
to put textures in video memory.
BTW, is this only frame buffer memory or also texture memory (for Voodoo boards
for example) ? */
caps->dwVidMemTotal = 8192 * 1024;
caps->dwVidMemFree = 8192 * 1024;
/* 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_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
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetCaps(
LPDIRECTDRAW2 iface,LPDDCAPS caps1,LPDDCAPS caps2
) {
ICOM_THIS(IDirectDraw2Impl,iface);
TRACE("(%p)->GetCaps(%p,%p)\n",This,caps1,caps2);
/* Put the same caps for the two capabilities */
fill_caps(caps1);
fill_caps(caps2);
return DD_OK;
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_CreatePalette(
LPDIRECTDRAW2 iface,DWORD dwFlags,LPPALETTEENTRY palent,
LPDIRECTDRAWPALETTE *lpddpal,LPUNKNOWN lpunk
) {
ICOM_THIS(IDirectDraw2Impl,iface);
IDirectDrawPaletteImpl** ilpddpal=(IDirectDrawPaletteImpl**)lpddpal;
int xsize;
HRESULT res;
TRACE("(%p)->(%08lx,%p,%p,%p)\n",This,dwFlags,palent,ilpddpal,lpunk);
res = common_IDirectDraw2Impl_CreatePalette(This,dwFlags,palent,ilpddpal,lpunk,&xsize);
if (res != 0)
return res;
(*ilpddpal)->private = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(x11_dp_private)
);
ICOM_VTBL(*ilpddpal) = &xlib_ddpalvt;
return DD_OK;
}
static ULONG WINAPI Xlib_IDirectDraw2Impl_Release(LPDIRECTDRAW2 iface) {
ICOM_THIS(IDirectDraw2Impl,iface);
TRACE("(%p)->() decrementing from %lu.\n", This, This->ref );
if (!--(This->ref)) {
if (This->d.window && GetPropA(This->d.window,ddProp))
DestroyWindow(This->d.window);
HeapFree(GetProcessHeap(),0,This);
return S_OK;
}
/* FIXME: destroy window ... */
return This->ref;
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_QueryInterface(
LPDIRECTDRAW2 iface,REFIID refiid,LPVOID *obj
) {
ICOM_THIS(IDirectDraw2Impl,iface);
TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
if ( IsEqualGUID( &IID_IUnknown, refiid ) ) {
*obj = This;
IDirectDraw2_AddRef(iface);
TRACE(" Creating IUnknown interface (%p)\n", *obj);
return S_OK;
}
if ( IsEqualGUID( &IID_IDirectDraw, refiid ) ) {
ICOM_VTBL(This) = (ICOM_VTABLE(IDirectDraw2)*)&xlib_ddvt;
IDirectDraw2_AddRef(iface);
*obj = This;
TRACE(" Creating IDirectDraw interface (%p)\n", *obj);
return S_OK;
}
if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) ) {
ICOM_VTBL(This) = (ICOM_VTABLE(IDirectDraw2)*)&xlib_dd2vt;
IDirectDraw2_AddRef(iface);
*obj = This;
TRACE(" Creating IDirectDraw2 interface (%p)\n", *obj);
return S_OK;
}
if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) ) {
ICOM_VTBL(This) = (ICOM_VTABLE(IDirectDraw2)*)&xlib_dd4vt;
IDirectDraw2_AddRef(iface);
*obj = This;
TRACE(" Creating IDirectDraw4 interface (%p)\n", *obj);
return S_OK;
}
#ifdef HAVE_OPENGL
if ( IsEqualGUID( &IID_IDirect3D, refiid ) )
return create_direct3d(obj,This);
if ( IsEqualGUID( &IID_IDirect3D2, refiid ) )
return create_direct3d2(obj,This);
#endif
FIXME("(%p):interface for IID %s _NOT_ found!\n",This,debugstr_guid(refiid));
return OLE_E_ENUM_NOMORE;
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_EnumDisplayModes(
LPDIRECTDRAW2 iface,DWORD dwFlags,LPDDSURFACEDESC lpddsfd,LPVOID context,LPDDENUMMODESCALLBACK modescb
) {
ICOM_THIS(IDirectDraw2Impl,iface);
XVisualInfo *vi;
XPixmapFormatValues *pf;
XVisualInfo vt;
int xbpp = 1, nvisuals, npixmap, i, emu;
int has_mode[] = { 0, 0, 0, 0 };
int has_depth[] = { 8, 15, 16, 24 };
DDSURFACEDESC ddsfd;
static struct {
int w,h;
} modes[] = { /* some of the usual modes */
{512,384},
{640,400},
{640,480},
{800,600},
{1024,768},
{1280,1024}
};
DWORD maxWidth, maxHeight;
TRACE("(%p)->(0x%08lx,%p,%p,%p)\n",This,dwFlags,lpddsfd,context,modescb);
ddsfd.dwSize = sizeof(ddsfd);
ddsfd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_CAPS|DDSD_PITCH;
if (dwFlags & DDEDM_REFRESHRATES) {
ddsfd.dwFlags |= DDSD_REFRESHRATE;
ddsfd.u.dwRefreshRate = 60;
}
maxWidth = MONITOR_GetWidth(&MONITOR_PrimaryMonitor);
maxHeight = MONITOR_GetHeight(&MONITOR_PrimaryMonitor);
vi = TSXGetVisualInfo(display, VisualNoMask, &vt, &nvisuals);
pf = TSXListPixmapFormats(display, &npixmap);
i = 0;
emu = 0;
while ((i < npixmap) || (emu != 4)) {
int mode_index = 0;
int send_mode = 0;
int j;
if (i < npixmap) {
for (j = 0; j < 4; j++) {
if (has_depth[j] == pf[i].depth) {
mode_index = j;
break;
}
}
if (j == 4) {
i++;
continue;
}
if (has_mode[mode_index] == 0) {
if (mode_index == 0) {
send_mode = 1;
ddsfd.ddsCaps.dwCaps = DDSCAPS_PALETTE;
ddsfd.ddpfPixelFormat.dwSize = sizeof(ddsfd.ddpfPixelFormat);
ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB|DDPF_PALETTEINDEXED8;
ddsfd.ddpfPixelFormat.dwFourCC = 0;
ddsfd.ddpfPixelFormat.u.dwRGBBitCount = 8;
ddsfd.ddpfPixelFormat.u1.dwRBitMask = 0;
ddsfd.ddpfPixelFormat.u2.dwGBitMask = 0;
ddsfd.ddpfPixelFormat.u3.dwBBitMask = 0;
ddsfd.ddpfPixelFormat.u4.dwRGBAlphaBitMask= 0;
xbpp = 1;
has_mode[mode_index] = 1;
} else {
/* All the 'true color' depths (15, 16 and 24)
First, find the corresponding visual to extract the bit masks */
for (j = 0; j < nvisuals; j++) {
if (vi[j].depth == pf[i].depth) {
ddsfd.ddsCaps.dwCaps = 0;
ddsfd.ddpfPixelFormat.dwSize = sizeof(ddsfd.ddpfPixelFormat);
ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsfd.ddpfPixelFormat.dwFourCC = 0;
ddsfd.ddpfPixelFormat.u.dwRGBBitCount = pf[i].bits_per_pixel;
ddsfd.ddpfPixelFormat.u1.dwRBitMask = vi[j].red_mask;
ddsfd.ddpfPixelFormat.u2.dwGBitMask = vi[j].green_mask;
ddsfd.ddpfPixelFormat.u3.dwBBitMask = vi[j].blue_mask;
ddsfd.ddpfPixelFormat.u4.dwRGBAlphaBitMask= 0;
xbpp = pf[i].bits_per_pixel/8;
send_mode = 1;
has_mode[mode_index] = 1;
break;
}
}
if (j == nvisuals)
WARN("Did not find visual corresponding the the pixmap format !\n");
}
}
i++;
} else {
/* Now to emulated modes */
if (has_mode[emu] == 0) {
int c;
int l;
int depth = has_depth[emu];
for (c = 0; (c < sizeof(ModeEmulations) / sizeof(Convert)) && (send_mode == 0); c++) {
if (ModeEmulations[c].dest.depth == depth) {
/* Found an emulation function, now tries to find a matching visual / pixel format pair */
for (l = 0; (l < npixmap) && (send_mode == 0); l++) {
if ((pf[l].depth == ModeEmulations[c].screen.depth) &&
(pf[l].bits_per_pixel == ModeEmulations[c].screen.bpp)) {
int j;
for (j = 0; (j < nvisuals) && (send_mode == 0); j++) {
if ((vi[j].depth == pf[l].depth) &&
(vi[j].red_mask == ModeEmulations[c].screen.rmask) &&
(vi[j].green_mask == ModeEmulations[c].screen.gmask) &&
(vi[j].blue_mask == ModeEmulations[c].screen.bmask)) {
ddsfd.ddpfPixelFormat.dwSize = sizeof(ddsfd.ddpfPixelFormat);
ddsfd.ddpfPixelFormat.dwFourCC = 0;
if (depth == 8) {
ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB|DDPF_PALETTEINDEXED8;
ddsfd.ddpfPixelFormat.u.dwRGBBitCount = 8;
ddsfd.ddpfPixelFormat.u1.dwRBitMask = 0;
ddsfd.ddpfPixelFormat.u2.dwGBitMask = 0;
ddsfd.ddpfPixelFormat.u3.dwBBitMask = 0;
} else {
ddsfd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsfd.ddpfPixelFormat.u.dwRGBBitCount = ModeEmulations[c].dest.bpp;
ddsfd.ddpfPixelFormat.u1.dwRBitMask = ModeEmulations[c].dest.rmask;
ddsfd.ddpfPixelFormat.u2.dwGBitMask = ModeEmulations[c].dest.gmask;
ddsfd.ddpfPixelFormat.u3.dwBBitMask = ModeEmulations[c].dest.bmask;
}
ddsfd.ddpfPixelFormat.u4.dwRGBAlphaBitMask= 0;
send_mode = 1;
}
if (send_mode == 0)
WARN("No visual corresponding to pixmap format !\n");
}
}
}
}
}
}
emu++;
}
if (send_mode) {
int mode;
if (TRACE_ON(ddraw)) {
TRACE("Enumerating with pixel format : \n");
_dump_pixelformat(&(ddsfd.ddpfPixelFormat));
DPRINTF("\n");
}
for (mode = 0; mode < sizeof(modes)/sizeof(modes[0]); mode++) {
/* Do not enumerate modes we cannot handle anyway */
if ((modes[mode].w > maxWidth) || (modes[mode].h > maxHeight))
break;
ddsfd.dwWidth = modes[mode].w;
ddsfd.dwHeight= modes[mode].h;
ddsfd.lPitch = ddsfd.dwWidth * xbpp;
/* Now, send the mode description to the application */
TRACE(" - mode %4ld - %4ld\n", ddsfd.dwWidth, ddsfd.dwHeight);
if (!modescb(&ddsfd, context))
goto exit_enum;
}
if (!(dwFlags & DDEDM_STANDARDVGAMODES)) {
/* modeX is not standard VGA */
ddsfd.dwWidth = 320;
ddsfd.dwHeight = 200;
ddsfd.lPitch = 320 * xbpp;
if (!modescb(&ddsfd, context))
goto exit_enum;
}
}
}
exit_enum:
TSXFree(vi);
TSXFree(pf);
return DD_OK;
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetDisplayMode(
LPDIRECTDRAW2 iface,LPDDSURFACEDESC lpddsfd
) {
ICOM_THIS(IDirectDraw2Impl,iface);
TRACE("(%p)->GetDisplayMode(%p)\n",This,lpddsfd);
lpddsfd->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_BACKBUFFERCOUNT|DDSD_PIXELFORMAT|DDSD_CAPS;
lpddsfd->dwHeight = This->d.height;
lpddsfd->dwWidth = This->d.width;
lpddsfd->lPitch = lpddsfd->dwWidth * PFGET_BPP(This->d.directdraw_pixelformat);
lpddsfd->dwBackBufferCount = 2;
lpddsfd->u.dwRefreshRate = 60;
lpddsfd->ddsCaps.dwCaps = DDSCAPS_PALETTE;
lpddsfd->ddpfPixelFormat = This->d.directdraw_pixelformat;
if (TRACE_ON(ddraw))
_dump_surface_desc(lpddsfd);
return DD_OK;
}
/* 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))
#else
# define XCAST(fun) (void *)
#endif
ICOM_VTABLE(IDirectDraw) xlib_ddvt = {
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
XCAST(QueryInterface)Xlib_IDirectDraw2Impl_QueryInterface,
XCAST(AddRef)IDirectDraw2Impl_AddRef,
XCAST(Release)Xlib_IDirectDraw2Impl_Release,
XCAST(Compact)IDirectDraw2Impl_Compact,
XCAST(CreateClipper)IDirectDraw2Impl_CreateClipper,
XCAST(CreatePalette)Xlib_IDirectDraw2Impl_CreatePalette,
XCAST(CreateSurface)Xlib_IDirectDraw2Impl_CreateSurface,
XCAST(DuplicateSurface)IDirectDraw2Impl_DuplicateSurface,
XCAST(EnumDisplayModes)Xlib_IDirectDraw2Impl_EnumDisplayModes,
XCAST(EnumSurfaces)IDirectDraw2Impl_EnumSurfaces,
XCAST(FlipToGDISurface)IDirectDraw2Impl_FlipToGDISurface,
XCAST(GetCaps)Xlib_IDirectDraw2Impl_GetCaps,
XCAST(GetDisplayMode)Xlib_IDirectDraw2Impl_GetDisplayMode,
XCAST(GetFourCCCodes)IDirectDraw2Impl_GetFourCCCodes,
XCAST(GetGDISurface)IDirectDraw2Impl_GetGDISurface,
XCAST(GetMonitorFrequency)IDirectDraw2Impl_GetMonitorFrequency,
XCAST(GetScanLine)IDirectDraw2Impl_GetScanLine,
XCAST(GetVerticalBlankStatus)IDirectDraw2Impl_GetVerticalBlankStatus,
XCAST(Initialize)IDirectDraw2Impl_Initialize,
XCAST(RestoreDisplayMode)IDirectDraw2Impl_RestoreDisplayMode,
XCAST(SetCooperativeLevel)Xlib_IDirectDraw2Impl_SetCooperativeLevel,
Xlib_IDirectDrawImpl_SetDisplayMode,
XCAST(WaitForVerticalBlank)IDirectDraw2Impl_WaitForVerticalBlank,
};
#undef XCAST
/*****************************************************************************
* IDirectDraw2
*
*/
static HRESULT WINAPI Xlib_IDirectDraw2Impl_SetDisplayMode(
LPDIRECTDRAW2 iface,DWORD width,DWORD height,DWORD depth,DWORD dwRefreshRate,DWORD dwFlags
) {
FIXME( "Ignored parameters (0x%08lx,0x%08lx)\n", dwRefreshRate, dwFlags );
return Xlib_IDirectDrawImpl_SetDisplayMode((LPDIRECTDRAW)iface,width,height,depth);
}
static HRESULT WINAPI Xlib_IDirectDraw2Impl_GetAvailableVidMem(
LPDIRECTDRAW2 iface,LPDDSCAPS ddscaps,LPDWORD total,LPDWORD free
) {
ICOM_THIS(IDirectDraw2Impl,iface);
TRACE("(%p)->(%p,%p,%p)\n",This,ddscaps,total,free);
if (total) *total = 16* 1024 * 1024;
if (free) *free = 16* 1024 * 1024;
return DD_OK;
}
ICOM_VTABLE(IDirectDraw2) xlib_dd2vt = {
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
Xlib_IDirectDraw2Impl_QueryInterface,
IDirectDraw2Impl_AddRef,
Xlib_IDirectDraw2Impl_Release,
IDirectDraw2Impl_Compact,
IDirectDraw2Impl_CreateClipper,
Xlib_IDirectDraw2Impl_CreatePalette,
Xlib_IDirectDraw2Impl_CreateSurface,
IDirectDraw2Impl_DuplicateSurface,
Xlib_IDirectDraw2Impl_EnumDisplayModes,
IDirectDraw2Impl_EnumSurfaces,
IDirectDraw2Impl_FlipToGDISurface,
Xlib_IDirectDraw2Impl_GetCaps,
Xlib_IDirectDraw2Impl_GetDisplayMode,
IDirectDraw2Impl_GetFourCCCodes,
IDirectDraw2Impl_GetGDISurface,
IDirectDraw2Impl_GetMonitorFrequency,
IDirectDraw2Impl_GetScanLine,
IDirectDraw2Impl_GetVerticalBlankStatus,
IDirectDraw2Impl_Initialize,
IDirectDraw2Impl_RestoreDisplayMode,
Xlib_IDirectDraw2Impl_SetCooperativeLevel,
Xlib_IDirectDraw2Impl_SetDisplayMode,
IDirectDraw2Impl_WaitForVerticalBlank,
Xlib_IDirectDraw2Impl_GetAvailableVidMem
};
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
# define XCAST(fun) (typeof(xlib_dd4vt.fn##fun))
#else
# define XCAST(fun) (void*)
#endif
ICOM_VTABLE(IDirectDraw4) xlib_dd4vt = {
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
XCAST(QueryInterface)Xlib_IDirectDraw2Impl_QueryInterface,
XCAST(AddRef)IDirectDraw2Impl_AddRef,
XCAST(Release)Xlib_IDirectDraw2Impl_Release,
XCAST(Compact)IDirectDraw2Impl_Compact,
XCAST(CreateClipper)IDirectDraw2Impl_CreateClipper,
XCAST(CreatePalette)Xlib_IDirectDraw2Impl_CreatePalette,
XCAST(CreateSurface)Xlib_IDirectDraw2Impl_CreateSurface,
XCAST(DuplicateSurface)IDirectDraw2Impl_DuplicateSurface,
XCAST(EnumDisplayModes)Xlib_IDirectDraw2Impl_EnumDisplayModes,
XCAST(EnumSurfaces)IDirectDraw2Impl_EnumSurfaces,
XCAST(FlipToGDISurface)IDirectDraw2Impl_FlipToGDISurface,
XCAST(GetCaps)Xlib_IDirectDraw2Impl_GetCaps,
XCAST(GetDisplayMode)Xlib_IDirectDraw2Impl_GetDisplayMode,
XCAST(GetFourCCCodes)IDirectDraw2Impl_GetFourCCCodes,
XCAST(GetGDISurface)IDirectDraw2Impl_GetGDISurface,
XCAST(GetMonitorFrequency)IDirectDraw2Impl_GetMonitorFrequency,
XCAST(GetScanLine)IDirectDraw2Impl_GetScanLine,
XCAST(GetVerticalBlankStatus)IDirectDraw2Impl_GetVerticalBlankStatus,
XCAST(Initialize)IDirectDraw2Impl_Initialize,
XCAST(RestoreDisplayMode)IDirectDraw2Impl_RestoreDisplayMode,
XCAST(SetCooperativeLevel)Xlib_IDirectDraw2Impl_SetCooperativeLevel,
XCAST(SetDisplayMode)Xlib_IDirectDrawImpl_SetDisplayMode,
XCAST(WaitForVerticalBlank)IDirectDraw2Impl_WaitForVerticalBlank,
XCAST(GetAvailableVidMem)Xlib_IDirectDraw2Impl_GetAvailableVidMem,
IDirectDraw4Impl_GetSurfaceFromDC,
IDirectDraw4Impl_RestoreAllSurfaces,
IDirectDraw4Impl_TestCooperativeLevel,
IDirectDraw4Impl_GetDeviceIdentifier
};
#undef XCAST